Average distance between nearest neighbors of grain boundaries
조회 수: 71 (최근 30일)
이전 댓글 표시
I have an image which contains both grains and grain boundaries. I wanted to write a matlab code to determine the average distance from one grain boundary to its nearest grain boundary and to the second nearest neighbor and so forth.
댓글 수: 8
Image Analyst
2024년 12월 5일 19:01
His binary image of the boundary showed single lines separating the grains. So it's the right hand side image. So in the right image, the distance between the white part of the boundaries is zero. Do you want the average distance between ALL the coordinates, i.e. all the (purple+white) and the (green+white) coordinates? If so, label your grains with bwlabel then take a pair of grains and dilate each with imdilate to enlarge it one pixel layer then get the boundaries with bwboundaries. Then use pdist2 to get the distance of every perimeter point of one grain to every perimeter point of the other grain. Then take the mean of all those distances. Not sure what physical meaning this would have though (I'm not a metallurgist). Or maybe you want the average of the closest distances rather than all the distances.
Or maybe you want the Hausdorff distance. See http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/98/normand/main.html
DGM
2024년 12월 5일 20:00
It would seem like the second image is what's being described, but:
- it's just more complicated (and slower) to calculate the second case (I did give a crude example below)
- the difference between the two is fairly small
- we don't know how accurately these lines actually correspond to the original image, so is that difference meaningful?
I don't know what the contextual meaning of the average pixel distance would be either.
답변 (2개)
Jaimin
2024년 12월 5일 11:21
Hi @Prince
To calculate the average distance from one grain boundary to its nearest grain boundaries, you can follow these general steps in MATLAB:
- Preprocess the Image: Convert the image to a binary format where the grain boundaries are clearly distinguished from the grains.
- Identify Grain Boundaries: Use edge detection or image segmentation techniques to identify the grain boundaries.
- Extract Boundary Points: Get the coordinates of the boundary points.
- Calculate Distances: For each boundary point, calculate distances to all other boundary points and find the nearest, second nearest, etc.
- Compute Average Distances: Compute the average of these distances for the first, second, nth nearest neighbours.
For more information kindly refer following resources.
I hope this will be helpful.
댓글 수: 0
DGM
2024년 12월 5일 15:47
편집: DGM
2024년 12월 5일 18:53
Maybe a start, maybe not:
% the image as a logical mask
inpict = imread('unettestfile.png')>128;
% if we're not going to fix open edges
% then just get rid of them
lastpix = nnz(inpict);
currpix = lastpix - 1;
while lastpix ~= currpix
inpict = inpict & ~bwmorph(inpict,'endpoints');
lastpix = currpix;
currpix = nnz(inpict);
end
% convert to a mask describing complete grains
grainmask = imclearborder(~inpict,4);
% of course this won't show up well unless it's displayed at full-scale
imshow(grainmask)
% if boundaries are "shared" by neighboring grains,
% i don't see a simple way to do that without loops
% dilating and evaluating each blob independently.
% it's not clear that it's necessary to treat the boundaries that way.
% instead, just consider the boundary of each blob
% in this case, no boundary pixels are shared between blobs
grbound2 = bwboundaries(grainmask,4);
% find distance between interior boundary centroids
nblobs = size(grbound2,1);
Db = zeros(nblobs);
for kr = 1:nblobs
groupA = grbound2{kr};
for kc = kr+1:nblobs
groupB = grbound2{kc};
Db(kr,kc) = sqrt(sum((mean(groupA,1) - mean(groupB,1)).^2,2));
end
end
Db = Db + Db.'; % make symmetric for easier sorting
% find distance between the actual blob centroids
% in this case, we don't need grbound2
CC = bwconncomp(grainmask,4);
S = regionprops(CC,'PixelList');
Dgr = zeros(nblobs);
for kr = 1:nblobs
groupA = S(kr).PixelList;
for kc = kr+1:nblobs
groupB = S(kc).PixelList;
Dgr(kr,kc) = sqrt(sum((mean(groupA,1) - mean(groupB,1)).^2,2));
end
end
Dgr = Dgr + Dgr.'; % make symmetric for easier sorting
% the difference is small. does it matter?
immse(Db,Dgr)
% alternatively, we can calculate Dgr quite a bit more easily
% since we don't really need to deal with many lists of points
CC = bwconncomp(grainmask,4);
S = regionprops(CC,'Centroid');
c = vertcat(S.Centroid);
Dgr2 = pdist2(c,c); % same thing
% find average distance between individual boundary pixels
nblobs = size(grbound2,1);
Dpxpx = zeros(nblobs);
for kr = 1:nblobs
groupA = grbound2{kr};
for kc = kr+1:nblobs
groupB = grbound2{kc};
dr = groupA(:,1) - groupB(:,1).';
dc = groupA(:,2) - groupB(:,2).';
Dpxpx(kr,kc) = mean(hypot(dr,dc),'all');
end
end
Dpxpx = Dpxpx + Dpxpx.'; % make symmetric for easier sorting
Here are three different distance matrices:
- Dpxpx: the average distance between groups of boundary pixels
- Db: the distance between the centroids of boundary pixel groups
- Dgr/Dgr2: the distance between the grain centroids
These rows/columns of these matrices are ordered based on how the connected groups are extracted from the image. You will have to sort them according to whatever your goals are. For example:
[Dpxpx idx] = sort(Dpxpx,2);
... will sort the rows of Dpxpx and return the sorted neighbor indices. The first column of Dpxpx will be the self-distance (0), and the following columns will be the distance to the nearest neighbors. The first column of idx will be the blob/boundary index, and the following columns will be the indices of its nearest neighbors.
댓글 수: 1
DGM
2024년 12월 5일 18:35
편집: DGM
2024년 12월 5일 18:38
Assuming we're talking about the average distance between all members of two pixel sets, we can disregard the centroid-based examples. So that leaves us with two different definitions of what the boundaries are:
% the image as a logical mask
inpict = imread('unettestfile.png')>128;
% if we're not going to fix open edges
% then just get rid of them
lastpix = nnz(inpict);
currpix = lastpix - 1;
while lastpix ~= currpix
inpict = inpict & ~bwmorph(inpict,'endpoints');
lastpix = currpix;
currpix = nnz(inpict);
end
% convert to a mask describing complete grains
grainmask = imclearborder(~inpict,4);
% INNER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% this is the same as in the prior example
% find the inner (unique) boundary pixels
grbound2 = bwboundaries(grainmask,4);
% find average distance between individual boundary pixels
nblobs = size(grbound2,1);
Dpxinner = zeros(nblobs);
for kr = 1:nblobs
groupA = grbound2{kr};
for kc = kr+1:nblobs
groupB = grbound2{kc};
dr = groupA(:,1) - groupB(:,1).';
dc = groupA(:,2) - groupB(:,2).';
Dpxinner(kr,kc) = mean(hypot(dr,dc),'all');
end
end
Dpxinner = Dpxinner + Dpxinner.'; % make symmetric for easier sorting
% show a sample
Dpxinner(1:10,1:10)
% OUTER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% find the outer (potentially shared) boundary pixels
[L nblobs] = bwlabel(grainmask,4);
grbound1 = cell(nblobs,1);
for k = 1:nblobs
thisgrain = L == k;
thisgrain = imdilate(thisgrain,ones(3)) & inpict;
[r c] = find(thisgrain); % if order doesn't matter, this is faster
grbound1{k} = [r c];
end
% find average distance between individual boundary pixels
nblobs = size(grbound1,1);
Dpxouter = zeros(nblobs);
for kr = 1:nblobs
groupA = grbound1{kr};
for kc = kr+1:nblobs
groupB = grbound1{kc};
dr = groupA(:,1) - groupB(:,1).';
dc = groupA(:,2) - groupB(:,2).';
Dpxouter(kr,kc) = mean(hypot(dr,dc),'all');
end
end
Dpxouter = Dpxouter + Dpxouter.'; % make symmetric for easier sorting
% show a sample
Dpxouter(1:10,1:10)
Some of this might simplify, but we're not at that point yet.
참고 항목
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!