By grain reconstruction we mean the subdivision of the specimen, or more precisely the measured surface of the specimen, into regions of similar orientation which we then call grains. Note that there is no canonical definition of what is a grain. The default grain reconstruction method in MTEX is based on the definition of high angle grain boundaries which are assumed at the perpendicular bisector between neighboring measurements whenever their misorientation angle exceeds a certain threshold. According to this point of view grains are regions surrounded by grain boundaries.
In order to illustrate the grain reconstruction process we consider the following sample data set
% import the data
plottingConvention.default('y↑→x');
mtexdata forsterite
% restrict it to a subregion of interest.
ebsd = ebsd(inpolygon(ebsd,[5 2 10 5]*10^3));
% make a phase plot
plot(ebsd,'micronbar','off')ebsd = EBSDsquare (y↑→x)
Phase Orientations Mineral Color Symmetry Crystal reference frame
0 58485 (24%) notIndexed none
1 152345 (62%) Forsterite LightSkyBlue mmm
2 26058 (11%) Enstatite DarkSeaGreen mmm
3 9064 (3.7%) Diopside Goldenrod 12/m1 X||a*, Y||b, Z||c
Properties: bands, bc, bs, error, mad, oldId
Scan unit : um
X x Y x Z : [0 → 36550] x [0 → 16750] x [0 → 0]
Normal vector: (0,0,1)
Square grid :336 x 732
Basic grain reconstruction
We see that there are a lot of not indexed measurements. For grain reconstruction, we have three different choices how to deal with these unindexed regions:
- leave them unindexed
- assign them to the surrounding grains
- a mixture of both, e.g., assign small notindexed regions to the surrounding grains but keep large notindexed regions
The extent to which unindexed pixels are assigned is controlled by the parameter 'alpha'. Roughly speaking this parameter is the radius, in pixels, of the smallest unindexed region that will not be entirely assigned to surrounding grains. The default of this value is alpha = 3.1.
The second parameter 'angle' involved in grain reconstruction is the threshold misorientation angle indicating a grain boundary. By default, this value is set to angle = 10*degree.
Finally, the option 'minPixel' controls the minimum size of a reconstructed grain. Grains with less pixels are considered as not indexed.
All grain reconstruction methods in MTEX are accessible via the command calcGrains which takes as input an EBSD data set and returns a list of grain.
[grains, ebsd] = calcGrains(ebsd,'alpha',2.1,'angle',10*degree,'minPixel',5);
grainsgrains = grain2d (y↑→x)
Phase Grains Pixels Mineral Symmetry Color
0 4 448 notIndexed none
1 55 14015 Forsterite mmm LightSkyBlue
2 13 1371 Enstatite mmm DarkSeaGreen
3 21 693 Diopside 12/m1 Goldenrod
boundary segments: 3481 (166248 µm)
inner boundary segments: 1 (19 µm)
triple points: 134
Properties: meanRotation, GOSThe reconstructed grains are stored in the variable grains. To visualize the grains we can plot its boundaries by the command plot.
% start override mode
hold on
% plot the boundary of all grains
plot(grains.boundary,'linewidth',1.5,'micronbar','off')
% stop override mode
hold off
Grain Boundary Smoothing
Due to the gridded nature of the EBSD measurement the reconstructed grain boundaries often suffer from the staircase effect. This can be reduced by smoothing the grain boundaries using the command smooth
grains = smoothBoundary(grains,5);
% display the result
plot(ebsd,'micronbar','off')
hold on
plot(grains.boundary,'linewidth',1.5)
hold off
Adapting the Alpha Parameter
Increasing the parameter 'alpha' larger not indexed regions are associated to grains.
% reload the data
mtexdata forsterite silent
ebsd = ebsd(inpolygon(ebsd,[5 2 10 5]*10^3));
[grains, ebsd] = calcGrains(ebsd,'alpha',6,'angle',10*degree,'minPixel',3);
grains = smoothBoundary(grains,3);
% plot the boundary of all grains
plot(ebsd,'micronbar','off')
hold on
plot(grains.boundary,'linewidth',1.5)
hold off
On the other setting alpha = 0 the grains consists exactly of the measurement pixels
% reload the data
mtexdata forsterite silent
ebsd = ebsd(inpolygon(ebsd,[5 2 10 5]*10^3));
[grains, ebsd] = calcGrains(ebsd,'alpha',0,'angle',10*degree);
% plot the boundary of all grains
plot(ebsd,'micronbar','off')
hold on
plot(grains.boundary,'linewidth',1.5)
hold off
Grain Reconstruction in heavily deformed microstructures
Everything above rests on one assumption: that a misorientation between two neighboring pixels means the same thing everywhere on the map, so that a single threshold angle can separate "inside a grain" from "across a grain boundary". In a heavily deformed material that assumption fails from both sides at once. Inside a grain the lattice is bent, so neighboring pixels differ by an amount that has nothing to do with a boundary and which accumulates to tens of degrees across the grain. Between two grains, on the other hand, the misorientation may be well below any threshold one could still call high angle.
As an example we consider an austenitic steel deformed in situ. It was indexed by spherical pattern matching rather than by the Hough transform, which leaves an orientation noise of about 0.1 degree - an order of magnitude below a typical Hough indexed map - so the substructure the deformation produced is actually resolved.
mtexdata EMSphinx
% the deformed austenite
ebsd = ebsd('Iron fcc');
plot(ebsd,ebsd.orientations)ebsd = EBSDsquare (y↑→x)
Phase Orientations Mineral Color Symmetry Crystal reference frame
0 2148 (0.44%) Iron bcc LightSkyBlue m-3m
1 478052 (99%) Iron fcc DarkSeaGreen m-3m
2 4940 (1%) Cobalt Goldenrod 6/mmm X||a, Y||b*, Z||c
Properties: IQ, Metric, oldId
Scan unit : um
X x Y x Z : [0 → 382] x [0 → 203] x [0 → 0]
Normal vector: (0,0,1)
Square grid :508 x 955
dataSet: /Scan 1/EBSD
dataSets: Scan 1/EBSD Scan 2/EBSD Scan 3/EBSD Scan 4/EBSD
The color gradients within the elongated grains are the bent lattice. We zoom into a smaller region to see what a threshold makes of it.
region = [40 30 80 60];
ebsd = ebsd(inpolygon(ebsd,region));
plot(ebsd,ebsd.orientations)
At the usual 10 degree the reconstruction returns the grains, but every boundary below the threshold is missed - and there are many, since deformation creates them.
grains = smoothBoundary(calcGrains(ebsd,'angle',10*degree,'minPixel',10),5);
plot(ebsd,ebsd.orientations)
hold on
plot(grains.boundary,'linewidth',1.5)
hold off
Lowering the threshold does not recover them. Well before it reaches the angles those boundaries actually have, it starts cutting the bent lattice inside the grains, and the boundaries it draws there are contour lines of a smooth orientation field rather than anything physical.
grains = smoothBoundary(calcGrains(ebsd,'angle',0.5*degree,'minPixel',10),5);
plot(ebsd,ebsd.orientations)
hold on
plot(grains.boundary,'linewidth',1.5)
hold off
Fast multiscale clustering
The way out is to stop asking about pixel pairs in isolation. Fast multiscale clustering, gbcFMC, builds a hierarchy of ever coarser aggregates of pixels and compares the misorientation between two aggregates against their own internal orientation spread instead of against a fixed angle. A 1 degree step between two uniform aggregates is then a boundary, while the same step inside a strongly bent grain is not, and the algorithm has no threshold angle at all.
It is selected by the option 'fmc', whose value cmaha controls how sharply a surprising misorientation suppresses the coupling between two aggregates - larger values separate more strictly and return more grains.
grains = calcGrains(ebsd,'fmc',0.5,'minPixel',10);
grains = smoothBoundary(grains,5);
plot(ebsd,ebsd.orientations)
hold on
plot(grains.boundary,'linewidth',1.5)
hold off
Note that the low angle boundaries missed at 10 degree are found, without any of the spurious ones a 0.5 degree threshold produced.
Raising cmaha resolves the substructure within those grains - the dislocation cells that carry the deformation.
grains = calcGrains(ebsd,'fmc',1.5,'minPixel',10);
grains = smoothBoundary(grains,5);
plot(ebsd,ebsd.orientations)
hold on
plot(grains.boundary,'linewidth',1.5)
hold off
Finally the same reconstruction on the full map. Unlike the threshold based criteria, FMC clusters the entire map at once rather than pixel pair by pixel pair, which is why this takes a few seconds. Adding the flag 'verbose' reports how far the hierarchy coarsened and at which of its scales the grains were eventually read off.
mtexdata EMSphinx silent
ebsd = ebsd('Iron fcc');
grains = calcGrains(ebsd,'fmc',1.5,'minPixel',10)
grains = smoothBoundary(grains,5);
plot(ebsd,ebsd.orientations)
hold on
plot(grains.boundary)
hold offgrains = grain2d (y↑→x)
Phase Grains Pixels Mineral Symmetry Color
-1 1 1 notIndexed none
1 1893 478051 Iron fcc m-3m DarkSeaGreen
boundary segments: 72584 (28997 µm)
inner boundary segments: 0 (0 µm)
triple points: 3431
Properties: meanRotation, GOS
More ways to reconstruct grains
The threshold angle and fast multiscale clustering are two of several criteria by which calcGrains may separate neighbouring pixels, and all of them are interchangeable objects. How to choose between them, how to segment by a property other than the orientation, and how to write a criterion of your own is the subject of Advanced Grain Reconstruction. A second way of turning a criterion into grains, by clustering the map instead of taking connected components, is described in Markovian Clustering.