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?
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()
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?
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.