How to remove artifact patches from a surface mesh?

Happy New Year, to whom it applies! :champagne:

I occasionally come across artifacts as indicated by the yellow ellipse below: Small surface patches that are connected with the main surface body by a single point only.

I try to remove these artifact patches. But how? vtkConnectivityFilter was not working for me. Before working on a custom solution, I wanted to check if there is already a filter that could take care of this. I’m already able to identify the “connecting point” by analyzing the contour edge. But what to do next?

I attached an example that exhibits this problem. surfaceWithArtifact.vtp (7.2 KB)

Thanks for any hints

Hello,

The “connecting point” could be split or duplicated by vtkPolyDataNormals. After that, the vtkConnectivityFilter would identify an artifact component and remove it. (see below)

import argparse
import vtk

def main():
    parser = argparse.ArgumentParser(description='Remove artifacts')
    parser.add_argument('--inputfilename', '-i', type=str, default='surfaceWithArtifact.vtp')
    args = parser.parse_args()

    input_file_name = args.inputfilename

    colors = vtk.vtkNamedColors()

    reader = vtk.vtkXMLPolyDataReader()
    reader.SetFileName(input_file_name)
    reader.Update()

    normals = vtk.vtkPolyDataNormals()
    normals.SetInputConnection(reader.GetOutputPort())
    normals.SetFeatureAngle(180.0)
    normals.SplittingOn()

    connectivity = vtk.vtkConnectivityFilter()
    connectivity.SetInputConnection(normals.GetOutputPort())
    connectivity.SetExtractionModeToLargestRegion()
    connectivity.Update()

    # A renderer.
    renderer = vtk.vtkRenderer()
    renderer.SetBackground(colors.GetColor3d("White"))

    # Create background colors for each viewport.
    backgroundColors = list()
    backgroundColors.append(colors.GetColor3d("Cornsilk"))
    backgroundColors.append(colors.GetColor3d("NavajoWhite"))

    # Create a renderer for each view port.
    ren = list()
    ren.append(vtk.vtkRenderer())
    ren.append(vtk.vtkRenderer())
    ren[0].SetViewport(0, 0, 1.0 / 2.0, 1)  # Input
    ren[1].SetViewport(1.0 / 2.0, 0, 10, 1)  # Remove artifacts

    # Shared camera.
    camera = vtk.vtkCamera()

    for i in range(2):
        # mapper
        mapper = vtk.vtkPolyDataMapper()
        mapper.ScalarVisibilityOff()

        if i == 0:
            mapper.SetInputData(reader.GetOutput())
        elif i == 1:
            mapper.SetInputData(connectivity.GetOutput())

        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().SetDiffuseColor(colors.GetColor3d("Peacock"))
        actor.GetProperty().SetDiffuse(.7)
        actor.GetProperty().SetSpecularPower(20)
        actor.GetProperty().SetSpecular(.5)

        # add the actor
        ren[i].SetBackground(backgroundColors[i])
        ren[i].SetActiveCamera(camera)
        ren[i].AddActor(actor)

    # Render window.
    renwin = vtk.vtkRenderWindow()
    renwin.AddRenderer(ren[0])
    renwin.AddRenderer(ren[1])

    # An interactor
    interactor = vtk.vtkRenderWindowInteractor()
    interactor.SetRenderWindow(renwin)

    renwin.SetSize(600, 300)
    ren[0].GetActiveCamera().SetFocalPoint(0, 0, 0)
    ren[0].GetActiveCamera().SetPosition(1, 0, 0)
    ren[0].GetActiveCamera().SetViewUp(0, 0, -1)
    ren[0].ResetCamera()

    ren[0].GetActiveCamera().Azimuth(80)
    ren[0].GetActiveCamera().Roll(120)
    ren[0].GetActiveCamera().Dolly(1.1)
    ren[0].ResetCameraClippingRange()

    renwin.Render()
    ren[0].ResetCamera()
    renwin.Render()

    # Start.
    interactor.Initialize()
    interactor.Start()


if __name__ == '__main__':
    main()

remove_artifact

2 Likes

Thank you, Yoshimi!

Cool, never thought of that! Just some followup question: Is the choice of the feature angle (180 degrees) robust? Do you expect this to work for any configuration of the artifact patch? And isn’t it possible that this will create “invisible cracks” to the surface?

Hello,

The choice of Feature angle (180 degrees) is to avoid introducing “invisible cracks” in the surface, because this does not detect and split the sharp edges with inner angle more than 0 degree across neighboring polygons. I believe this is robust on this point.

I’m sorry that there is never enough testing for this.