Selecting Grains edit page

A grain2d variable is a list of grains. Selecting grains means indexing that list by position, phase, property, spatial coordinates, or mean orientation. Every selection is another grain list, so selections can be applied one after another.

This page assumes that you have reconstructed grains as described in Grain Reconstruction. It also assumes that you can draw them as in Plotting Grains.

close all;

% load sample EBSD data set
plottingConvention.default('y↑→x');
mtexdata forsterite silent

% restrict it to a subregion of interest
ebsd = ebsd(inpolygon(ebsd,[5 2 10 5]*10^3));

% reconstruct grains and store their ids with the measurements
[grains,ebsd] = calcGrains(ebsd,'angle',5*degree,'minPixel',5,'alpha',6);

% smooth the boundaries
grains = smoothBoundary(grains,5);

% plot forsterite by orientation
plot(ebsd('Fo'),ebsd('Fo').orientations,'ipfDirection',zvector)

% plot the other two phases in grey
hold on
plot(ebsd('En'),'FaceColor','lightgray')
plot(ebsd('Di'),'FaceColor','darkgray')
plot(grains.boundary,'lineWidth',2)
hold off

The black network outlines every reconstructed grain. The forsterite measurements retain their orientation colours, while the two minor phases are grey so that later highlights remain easy to see.

By mouse

selectInteractive installs a mouse callback on the current figure. A click selects one grain, and additional clicks extend the selection. The global variable indSelected stores the selected positions in the current grain list.

selectInteractive(grains,'lineColor','gold')

clear global indSelected
global indSelected

Nobody clicks while this page is published. We therefore set indSelected to the list position of the grain at a known coordinate.

indSelected = grains.id2ind(grains(9000,3500).id);

mouseGrains = grains(indSelected)

hold on
plot(mouseGrains.boundary,'lineWidth',4,'lineColor','gold')
hold off
mouseGrains = grain2d (y↑→x)
 
 Phase  Grains  Pixels     Mineral  Symmetry         Color
     1       1     323  Forsterite       mmm  LightSkyBlue
 
 boundary segments: 87 (4067 µm)
 inner boundary segments: 0 (0 µm)
 triple points: 6
 
 Id   Phase   Pixels      meanRotation          GOS
 47       1      323   (131°,64°,250°)   0.00795279

The gold outline marks the selected grain. If several grains had been clicked, every selected outline would be gold and mouseGrains would contain all of them.

By position

The expression grains(x,y) returns the grain containing the point (x,y) in map coordinates. It needs neither a figure nor a mouse click.

x = 12000;
y = 4000;

hold on
plot(grains(x,y).boundary,'lineWidth',4,'lineColor','blue')
plot(x,y,'Marker','s','MarkerFaceColor','k','MarkerSize',10,...
  'MarkerEdgeColor','w','DisplayName','A')
hold off

Marker A lies inside the thick blue outline. The coordinate is used for the lookup; its location in the current axes does not affect the result.

By phase

A grain is phase-homogeneous. A mineral name therefore selects every grain of that phase, and the displayed summary reports what came back.

forsteriteGrains = grains('forsterite')
forsteriteGrains = grain2d (y↑→x)
 
 Phase  Grains  Pixels     Mineral  Symmetry         Color
     1      61   14009  Forsterite       mmm  LightSkyBlue
 
 boundary segments: 2825 (132934 µm)
 inner boundary segments: 12 (568 µm)
 triple points: 135
 
 Properties: meanRotation, GOS

The mineral name is the readable form of a condition on phase. This property stores one imported phase number per grain.

firstFivePhase = grains(1:5).phase
firstFivePhase =
     1
     3
     2
     1
     1

By a property

A grain property has one value per grain. MATLAB operations on numeric arrays can therefore build indices from any such property. We begin with area.

grainArea = grains.area;

plot(grains,grainArea)

Large grains are bright and small grains are dark. This map shows where the extremes lie before any threshold is imposed.

max returns the largest value and its position in the list. That position is an index, not a persistent grain ID.

[maxArea,maxIndex] = max(grainArea)

hold on
plot(grains(maxIndex).boundary,'lineColor','red','lineWidth',4)
hold off
maxArea =
   4.1122e+06
maxIndex =
    28

The red outline encloses the brightest grain in the area map. Sorting generalises this selection from one grain to the largest few.

[sortedArea,sortedIndex] = sort(grainArea,'descend');

% select the second to fifth largest grains
hold on
plot(grains(sortedIndex(2:5)).boundary,'lineColor','orange','lineWidth',4)
hold off

The orange outlines mark ranks two through five. The largest grain remains identifiable by its red outline from the preceding selection.

By a condition

A logical array with one value per grain can index the list directly. Here it selects every grain at least one quarter the size of the largest.

condition = grainArea > maxArea/4;

hold on
plot(grains(condition).boundary,'lineColor','yellow','lineWidth',4)
hold off

The yellow outlines include more grains than the fixed rank selection. Their membership follows an area threshold rather than a chosen count.

Conditions may be combined. The next selection requires a perimeter above 6000 map units and at least 600 measurements. The pixel-count condition excludes grains too small for their outline to support a useful shape interpretation.

condition = grains.perimeter > 6000 & grains.numPixel >= 600;

selectedGrains = grains(condition)

plot(selectedGrains)
selectedGrains = grain2d (y↑→x)
 
 Phase  Grains  Pixels     Mineral  Symmetry         Color
     1       4    5248  Forsterite       mmm  LightSkyBlue
 
 boundary segments: 737 (34466 µm)
 inner boundary segments: 0 (0 µm)
 triple points: 43
 
 Id   Phase   Pixels       meanRotation      GOS
 28       1     1545    (167°,81°,251°)    0.013
 60       1     1047     (89°,99°,224°)   0.0077
 82       1     1208    (153°,68°,237°)   0.0081
 84       1     1448   (166°,127°,259°)    0.014

Only the grains satisfying both conditions remain in the plot. Empty spaces belong to grains excluded by at least one condition.

By orientation

findByOrientation selects grains whose mean orientation lies within a specified angle of a reference orientation. It accounts for crystal symmetry, so equivalent descriptions of the same lattice orientation are treated as the same orientation.

We use the first gold grain from above as the reference and a threshold of 20 degrees.

referenceGrain = mouseGrains(1);
similarGrains = grains.findByOrientation(referenceGrain.meanOrientation,20*degree)

plot(ebsd('Fo'),ebsd('Fo').orientations,'ipfDirection',zvector)
hold on
plot(grains.boundary,'lineWidth',2)
plot(similarGrains.boundary,'lineWidth',4,'lineColor','gold')
hold off
similarGrains = grain2d (y↑→x)
 
 Phase  Grains  Pixels     Mineral  Symmetry         Color
     1       3     523  Forsterite       mmm  LightSkyBlue
 
 boundary segments: 164 (7766 µm)
 inner boundary segments: 0 (0 µm)
 triple points: 13
 
 Id   Phase   Pixels      meanRotation     GOS
 18       1       19   (144°,74°,250°)    0.01
 47       1      323   (131°,64°,250°)   0.008
 55       1      181   (131°,64°,245°)   0.007

Three grains are selected, and two share a boundary. Neighbours with mean orientations this close deserve a second look. The reconstruction may have split one grain, or the grains may have belonged together before another process separated them. Merging Grains develops this question.

List position and grain ID

A list position answers "which entry of this variable?" A grain ID answers "which reconstructed grain?" They are initially often equal, but a subset keeps the original IDs while its positions start again at one.

plot(grains)
largeGrains = grains(grains.numPixel > 50);
text(largeGrains,largeGrains.id)

The labels are persistent grain IDs. They are not the positions of the labelled grains in largeGrains.

listPosition = 1;
grainId = largeGrains.id(listPosition);
fprintf('list position %d has grain ID %d\n',listPosition,grainId);

grainByPosition = largeGrains(listPosition);
grainById = largeGrains('id',grainId);
sameGrain = grainByPosition.id == grainById.id
list position 1 has grain ID 3
sameGrain =
  logical
   1

largeGrains(1) selects by position. The form largeGrains('id',grainId) searches the stored IDs. The printed logical value confirms that both expressions identify the same grain here.

From grains back to measurements

Every grain selection can be converted to the measurements it contains. This requires the grainId property that calcGrains returned with the map.

measurementsByGrain = ebsd(grainById)

measurementsById = ebsd(ebsd.grainId == grainId);
sameMeasurements = isequal(measurementsByGrain.id,measurementsById.id)
measurementsByGrain = EBSD (y↑→x)
 
 Phase  Orientations    Mineral         Color  Symmetry  Crystal reference frame
     2    346 (100%)  Enstatite  DarkSeaGreen       mmm                         
 
 Properties: bands, bc, bs, error, mad, oldId, grainId
 Scan unit : um
 X × Y × Z : [5000 → 5550] × [3750 → 5850] × [0 → 0]
 Normal vector: (0,0,1)
 
sameMeasurements =
  logical
   1

The first command displays the selected measurements. The printed logical value confirms that selecting by the grain object and matching the stored ebsd.grainId return the same subset.

Applied to the largest grain, this relationship reveals the orientations measured inside one reconstructed grain.

largestGrain = grains(maxIndex);
largestGrainEbsd = ebsd(largestGrain);

plot(largestGrainEbsd,largestGrainEbsd.orientations,...
  'ipfDirection',zvector)
hold on
plot(largestGrain.boundary,'lineWidth',2)
hold off

The colours inside the black outline come from the individual measurements, not from one grain mean. On this grain the spread is small, under two and a half degrees, so the fill reads as a single shade and the unindexed white pixels are what stands out.

A spread this size has to be measured rather than looked for. The mean and spread of the distribution are the subject of Grain Orientation Parameters.

Grains at the edge of the map

A grain touching the map edge continues outside the measured region. Its observed area and shape describe only the measured piece. Remove such grains before calculating per-grain size or shape statistics with isBoundary.

interiorGrains = grains(~grains.isBoundary);
plot(interiorGrains)

The white band around the plot is occupied by the omitted edge grains. This exclusion is appropriate for comparing complete observed shapes. A standardised average grain-size measurement may prescribe a different boundary-counting rule, so follow the selected standard when reporting one.

The boundary network shows what isBoundary tests. Each grain boundary segment stores the IDs of the two grains it separates. A segment at the map edge has no grain on one side, so the corresponding ID is zero.

% find segments with zero on one side
isOuterBoundary = any(grains.boundary.grainId == 0,2);

plot(grains)
hold on
plot(grains.boundary(isOuterBoundary),'lineColor','red','lineWidth',2)
hold off

The red segments form the outer rim of the measured region. Their nonzero IDs identify exactly the grains removed above.

boundaryGrainId = grains.boundary(isOuterBoundary).grainId;
boundaryGrainId(boundaryGrainId == 0) = [];
boundaryGrainId = unique(boundaryGrainId);

plot(grains('id',boundaryGrainId))

Only the edge grains remain. The explicit 'id' lookup is required because the values came from grainBoundary.grainId rather than from list positions.

Next

Shape Parameters defines the area, perimeter, and other geometric properties used to build selections. The ellipse, convex hull, and projection pages that follow it provide further shape measures. Grain Orientation Parameters develops selections based on the orientation distribution inside each grain.

Grain selections also lead back to the boundary network. Selecting Grain Boundaries selects its segments, and Merging Grains uses selected boundaries to join grains.

Further reading

  • F. Bachmann, R. Hielscher, and H. Schaeben, "Grain detection from 2d and 3d EBSD data - Specification of the MTEX algorithm", Ultramicroscopy 111 (2011), 1720-1733, doi:10.1016/j.ultramic.2011.08.002. This paper derives the Voronoi-cell grain model whose IDs connect the grain list to the EBSD measurements.
  • ASTM E2627-13(2019), Standard Practice for Determining Average Grain Size Using Electron Backscatter Diffraction (EBSD) in Fully Recrystallized Polycrystalline Materials.
  • ISO 13067:2020, Microbeam analysis - Electron backscatter diffraction - Measurement of average grain size. It distinguishes measurements on a two-dimensional section from inferences about three-dimensional grain size.

Citing this page. This page is part of the documentation of MTEX, a free and open source MATLAB toolbox for analyzing and modeling crystallographic textures. It was written by The MTEX Developers and is published at https://mtex-toolbox.github.io/SelectingGrains.html. If you use MTEX, or reuse text or figures from this page, in your research, please cite

F. Bachmann, R. Hielscher, H. Schaeben: Texture Analysis with MTEX - Free and Open Source Software Toolbox, Solid State Phenomena 160 (2010), 63-68. 10.4028/www.scientific.net/SSP.160.63

BibTeX
@article{bachmann2010mtex,
  author  = {F. Bachmann and R. Hielscher and H. Schaeben},
  title   = {Texture Analysis with MTEX - Free and Open Source Software Toolbox},
  journal = {Solid State Phenomena},
  volume  = {160},
  pages   = {63-68},
  year    = {2010},
  doi     = {10.4028/www.scientific.net/SSP.160.63},
  url     = {https://doi.org/10.4028/www.scientific.net/SSP.160.63}
}

Other papers describing specific MTEX methods are listed under Publications — please cite the one that best fits your application. The MTEX source code is licensed under the GNU General Public License v2.0; the text and figures of this documentation are licensed under CC BY 4.0, which permits reuse — including by automated systems — provided The MTEX Developers and this page are credited.