turn the pixel staircase of a grain boundary into a smooth curve
Description
EBSD data is measured on a regular grid, so a grain boundary comes out of calcGrains as a staircase of pixel edges - every segment runs along one of the grid axes, whatever direction the boundary actually has. This is repaired in three steps
-
simplifyBoundarydrops every vertex whose removal moves the boundary by less thanepsilon. A staircase is never further thand/sqrt(2)from the straight line it approximates,dbeing the pixel spacing, so that is the tolerance which removes the grid and nothing else -
refineBoundaryresamples what is left at equal arc lengthdelta, which gives the smoothing evenly spaced degrees of freedom that are no longer tied to the grid - the smoothing itself, by default a constrained Laplacian applied
itertimes
Which algorithm performs the last step is decided by a boundaryFilter
-
laplaceFilter- the default, repeated local averaging. Shrinks, and its knob is an iteration count rather than a length -
taubinFilter- follows every smoothing pass by a slightly larger unshrinking pass, so the area is given back -
curvatureFilter- one sparse solve instead of an iteration, stated as a smoothing length and therefore independent both of the iteration count and of the step size of the map -
huberFilter- the same, but with an l^1/l^2 penalty that keeps a genuinely faceted boundary faceted
Both tolerances are derived from the median segment length before the first step - afterwards the median is the length of the straightened runs, not the pixel spacing.
Neither of the first two steps is cosmetic. Simplifying alone leaves a curve as a handful of long chords, and smoothing those cuts the corners off the polygon they form - a circle of 15 pixel radius loses 14% of its area over 25 iterations, against 0.4% for the full three steps. Smoothing alone leaves the boundary directions of a straight boundary scattered around the grid axes.
Junctions - triple points, quadruple points, and the vertices where the inner boundary ends on the outer one - stay exactly where they are throughout, unless moveTriplePoints is given. When grains were segmented using alphaShapes, all grains next to holes have outer boundary.
Note that the first two steps change the number of boundary segments, and a resampled segment no longer runs between a specific pair of pixels. Where gB.ebsdId is analysed per segment, switch them off with 'noSimplify' and 'noRefine'.
Syntax
grains = smoothBoundary(grains)
grains = smoothBoundary(grains,iter)
grains = smoothBoundary(grains,iter,'noSimplify','noRefine')
grains = smoothBoundary(grains,iter,'simplify',epsilon,'refine',delta)grains = smoothBoundary(grains,taubinFilter)
grains = smoothBoundary(grains,curvatureFilter('smoothingLength',3))Input
| grains | grain2d |
| iter | number of smoothing iterations (default: 1) |
| F | boundaryFilter, the smoothing algorithm to use |
Output
| grains | grain2d |
| F | boundaryFilter that was used |
Options
| simplify | Douglas-Peucker tolerance (default: d/sqrt(2)) |
| refine | resampling length (default: d) |
| noSimplify | do not simplify the boundary first |
| noRefine | do not resample the boundary |
| moveTriplePoints | do not exclude triple/quadruple points from smoothing |
| moveOuterBoundary | do not exclude outer boundary from smoothing |
| The remaining options configure the default laplaceFilter and have no meaning for the other filters | |
| second_order, S2 | second order smoothing |
| rate | default smoothing kernel |
| gauss | Gaussian smoothing kernel |
| exp | exponential smoothing kernel |
| umbrella | umbrella smoothing kernel |
See also
grain2d.simplifyBoundary grain2d.refineBoundary grain2d.reduceBoundary boundaryFilter laplaceFilter taubinFilter curvatureFilter huberFilter