Mesh internal surface smoothing behavior changed in vtkWindowedSincPolyDataFilter

It seems that the rewrite of vtkWindowedSincPolyDataFilter (that amazingly improved its performance) also changed how internal surfaces are smoothed. Smoothing of internal surfaces are important because when we segment a medical image we usually annotate many adjacent structures that have common surfaces and when we apply smoothing then we want to smooth surface of each structure and not just the outer surface of the entire segmented region.

The old version (VTK8) smoothed the internal surfaces, while the new version (VTK9) does not seem to smooth internal edges at all.

I’ve tried to adjust all parameters (BoundarySmoothingOn/Off, FeatureEdgeSmoothingOn/Off, NonManifoldSmoothingOn/Off, FeatureAngle, EdgeAngle, NormalizeCoordinatesOn/Off) but I could not find any settings that would smooth the internal surfaces.

@will.schroeder Is this difference expected? Could there be any preprocessing or filter parameter combination that would allow smoothing internal surfaces?


Input surface

Smoothed surface using old vtkWindowedSincPolyDataFilter

Boundary between segments are smoothed. There is some bubbling due to the strong smoothing factor (we used somewhat stronger smoothing as usual to make all differences easier to see).


Smoothed surface using new vtkWindowedSincPolyDataFilter

Outer surface is smoothed - good. There is no bubbling (outer surface remains smooth) - good (better than the old version). However, internal edges remain sharp and jagged - not good, they are not smoothed at all.


How to reproduce

Run the Python script below on this data set, using the old and new version of vtkWindowedSincPolyDataFilter (in the zip file I’ve included both outputs, so the results can be compared without running the script).

# WindowedSyncPolyDataFilter internal edge smoothing test

reader = vtk.vtkXMLPolyDataReader()

smoother = vtk.vtkWindowedSincPolyDataFilter()

writer = vtk.vtkXMLPolyDataWriter()

Thanks Andras for bringing this to our attention. The filters should produce the same results so this needs to be fixed.

By internal edges, are you using vtkDiscreteMarchingCubes (or equivalent) to produce non-manifold edges (i.e., edges used by more than two triangles/polygons)?

Unfortunately I’ve got some heavy deliverables this month, but as soon as I can I will look into this. I suspect that it may be related to the smoothing network as it relates to non-manifold edges.

Yes, we use vtkDiscreteMarchingCubes, to generate the input mesh from a label volume (see here.

Sounds great, thank you.

@lassoan something like this may also make a good example.

If you’re really busy, I’m happy to do both a Python & C++ example form what you have provided once the internal edge smoothing is fixed…

1 Like

Andrew this would be good. Part of the reason is that I hope to complete Surface Nets 3D in June, which (should be) a superior version of vtkDiscreteMarchingCubes. It would be good to have an example for that as well.

Excellent! Keep me in the loop … please.

Andras, I’ve tracked this down. I’m scratching my head a little bit because there’s an argument to be made that the previous incarnation of vtkWindowedSincPolyDataFilter had incorrect behavior. If nothing else the documentation was confusing. Basically what happened is that if NonManifoldSmoothing was on, the filter ignored non-manifold edges, i.e., treated them as simple edges, and ignored everything else (feature edges, edge angle, etc.)

I don’t think it’ll be hard to replicate the old behavior, I’ll poke at this and let you know where we are. I’ll need you to approve the MR if we get to that point.

1 Like

Thanks a lot in advance!

If the current behavior is useful, too, then maybe new flag(s) could be added to allow choosing between the old and the new behavior.

Andras, an update.

Now that I’ve dug into this the old filter, in combination with vtkDiscreteMarchingCubes, IMO it is pretty ugly when it comes to dealing with non-manifold smoothing (i.e., multiple labels).

  • First of all, the smoothing stencil is incorrect, each non-manifold edge is added to the smoothing stencil N times, where N is the number of cells sharing the non-manifold edge. So for example (from the data you gave me), the newer version of vtkWIndowedSincPolyDataFilter will typically have 7 edge connections in the stencil, while the older version has 16 (3 nonmanifold edges used by four cells each adds an additional 3 repeated edges per nonmanifold edge adding a total of 9 additional edges). This has the unexpected side effect of heavily weighting the nonmanifold edges during the smoothing process, which miraculously produces better smoothing results in many cases. (Whether this is intentional or not I can’t tell - there are no comments in the code to this effect - it looks like a bug to me.)

  • Second, if you really look at a smoothed mesh containing lots of nonmanifold contact edges, it is quite bad IMO to the point that I’d be worried about using it in analysis. Visually yes, it often looks better, but wow the resulting mesh self intersects all over the place (along the interface between two different segmented objects).

So what to do? Here are some thoughts; I’d like to hear yours as well.

  1. I believe that I can reproduce the old behavior by adding an additional flag something like “WeightNonManifoldEdgesOn/Off()” to the current incarnation of vtkWIndowedSincPolyDataFilter.
  2. In the long run, I think that a Surface Nets algorithm is going to give superior results (and I am working on that now although it’s going to take some time to get it tested and ready for production).

Is it important to reproduce the old behavior? Or should we just shoot for an improved discrete isocontouring algorithm (i.e., surface nets)? Or both?

Thanks a lot for your continued effort on this.

It was always kind of a mystery why or how it all worked (it was mainly developed by Bill Lorensen about 15 years ago, maybe he knew), but the results were good - smoothed internal boundaries with very little or no overlap between structures.

Maybe we were not bothered by mesh quality problems because we most often used it for visualization; for analysis we usually rasterized it back to binary images.

This would be great. Both because of timing (there would be no time pressure for the new Surface Nets algorithm development) and also to have a baseline to compare the Surface Nets algorithm to. Also, if the Surface Nets algorithm works in a completely different way then there is a chance that for some problems some users will still prefer using the previous method.

@will.schroeder We have found out today that this change in behavior caused a regression in our heart leaflet analysis workflow (leaflets are pulled away from each other now when the segmentation is smoothed). If we need to revert to a several-year-old software version where joint smoothing worked then we would need to redo a lot of validation work. So, it would save us a lot of time if you could add that flag to the filter to restore the old behavior.

We have a pressing deadline for this (we need to resubmit a revision for a journal paper within a few weeks that requires this fix). When do you think you could add the flag to reproduce the old behavior?

Andras I am on vacation through the 21st of July. It’s top of my list when I return; I’m hoping that the fix will be made quickly soon after that.

Sounds good, thanks a lot!

@will.schroeder Have you been able to make progress in this?

I’ve blocked out time tomorrow to knock this out. Hopefully I’ll have good news then - I’ll let you know one way or the other tomorrow.

Andras FYI I am definitely seeing improvement, the results aren’t quite the same. I’m going to continue tomorrow morning…

1 Like