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?
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).
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.
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.
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.
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.
I believe that I can reproduce the old behavior by adding an additional flag something like “WeightNonManifoldEdgesOn/Off()” to the current incarnation of vtkWIndowedSincPolyDataFilter.
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?
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?