Using the CannyEdgeDetector example to create an image stencil with vtkPolyDataToImageStencil


I am trying to extend the CannyEdgeDetector example to make an image stencil, and from that make a mask (image data).

I have used vtkPolyDataToImageStencil() to turn the polydata created with the CannyEdgeDetector example into a stencil, and then vtkImageStencilToImage() to turn this into an image.

The problem I have is that in some places the edges drawn in the canny edge detector have gaps in them. When the stencil closes the gaps, sometimes it joins them to gaps a long way across in the image.

For example the image I am working with has a number of squares and lines which I am trying to outline and turn into a mask. I have attached 2 images, the first shows the polydata (red) produced by the canny edge detector overlayed on the image, and the second shows the mask in blue overlayed on the image (after vtkPolyDataToImageStencil and vtkImageStencilToImage). The square in the top left has a gap in the outline, at the bottom. Instead of this being joined up in the stencil, it is instead joined to the square in the top right, which has a gap in the outline on the top left and bottom left corners.



We considered splitting the polydata into separate lines, and making separate image stencils for each line in the polydata, but this wouldn’t work because in some places we do want it to join together different polylines. E.g. I have attached a second part of the image where two lines cross, and it can be seen that the polydata is correctly stencilled by joining together different lines.



The only option in the vtkPolyDataToImageStencil() seems to be SetTolerance() which hasn’t helped.

I would like to understand if there is an easier way to close the gaps in the polydata when making a stencil, it would be great if this could be done based on proximity. Or if there is an easier way to turn the polydata from the CannyEdgeDetector into a mask, that would be great.



You might be able to solve the issue by applying vtkCleanPolyData before generating the stencil (use vtkCleanPolyData::SetTolerance() to set a reasonable tolerance, maybe around half the pixel size).

Another thing to try is vtkMarchingSquares, instead of performing canny edge detection. Your images have good contrast and fairly uniform brightness, so marching squares should work well (and it will be much more efficient). Another bonus is that the output of vtkMarchingSquares is topologically “clean” and therefore works well as an input to vtkPolyDataToImageStencil.

The most efficient solution, however, might be to avoid polydata altogether. Have you tried running vtkImageToImageStencil (with a threshold) directly on your image?

1 Like