Mean line of object boundary

I have sample picture as above. I want to find average line of this object. Who have any idea to do that?

 Risposta accettata

Another Approach could be this:
B1=bwmorph(logical( round( double(imread('1_1.bmp'))/255 ) ),'skel','inf');
B2=bwmorph(logical( round( double(imread('1_2.bmp'))/255 ) ),'skel','inf');
B3=bwmorph(logical( round( double(imread('1_3.bmp'))/255 ) ),'skel','inf');
D1=bwdist(B1);
D2=bwdist(B2);
D3=bwdist(B3);
D=D1+D2+D3;
mask=bwmorph(bwmorph(D<50,'thin','inf'),'spur',100);
FinalImage(:,:,1)=B1+mask;
FinalImage(:,:,2)=B2+mask;
FinalImage(:,:,3)=B3+mask;
Although I have to mention that this is not averaging the borders. The resulting border is the white line in the following image:

2 Commenti

Montree
Montree il 4 Gen 2015
Woww...amazing!!!
Thank very much.
Looks like you're all set. If you do want the average though, you can still use my code.

Accedi per commentare.

Più risposte (1)

Image Analyst
Image Analyst il 3 Gen 2015

0 voti

How about this method:
Convert to binary images and AND them then find the centroid and send out rays from the centroid to each perimeter to find the radii. Then average the radii. Could use cart2pol and pol2cart to help.
Can you supply the 3 lists of (x,y) or (row, column) coordinates?

6 Commenti

Montree
Montree il 3 Gen 2015
I can find centriod and get all coordinates of 3 line. See the picture as below. When I get the position of each line and calculate the meaning position it will it will return incorrect result (because 2 line are parallel of radii) and this is 1 sample only. Other sample picture may be difference from this sample so the algorithm must solve this problem in every case.
However Thank for your answer. If you have other idea please tell me. Thank again.
Montree
I think you misunderstood or didn't think it through so maybe I need to give it in a little more detail.
  1. First of all, find the centroid, and you did that so that's good.
  2. Next, use interp1() to make sure each list has the same number of elements in it. That's important because we need to align them and take the average and we can't do that unless they have the same number of elements in them. (You might plot the resized outlines again just to make sure they look right.)
  3. Next, find the y value for each coordinate list that is closest to the centroid, and then use circshift() to align them all so that element 1 is the same line (same Y value). This is probably the trickiest part but I'm sure you can handle it.
  4. Now convert each list to radii with cart2pol() and knowledge of where the radii are.
  5. Then average the 3 lists of radii. Now we have the average radii for each element.
  6. Now use pol2cart() and the centroid location to turn the average radii into outline curves.
Post your code and data, or output image, so we can verify that you did it correctly.
Can you upload the three BW images containing each border in a separate image?
Seems like you're still having trouble, or else you're just enjoying something else over the weekend. So I've done steps 4, 5, and 6 for you, in the latter part of this code. The first half is just code to get the curves (because you didn't supply me with any data).
clear all;
close all;
clc;
xCenter = 12;
yCenter = 10;
theta = 0 : 0.1 : 2*pi;
radius = 5;
x = radius * cos(theta) + xCenter;
y = radius * sin(theta) + yCenter;
plot(x, y, 'k-');
axis square;
xlim([6 18]);
ylim([4 18]);
grid on;
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0 0 1 1]);
% Get 3 wiggly circles for sample data
amplitude = .8;
x1 = x + amplitude * rand(size(x)) - amplitude/2;
y1 = y + amplitude * rand(size(y)) - amplitude/2;
x2 = x + amplitude * rand(size(x)) - amplitude/2;
y2 = y + amplitude * rand(size(y)) - amplitude/2;
x3 = x + amplitude * rand(size(x)) - amplitude/2;
y3 = y + amplitude * rand(size(y)) - amplitude/2;
hold on;
plot(x1,y1, 'r-', 'LineWidth', 2);
plot(x2,y2, 'g-', 'LineWidth', 2);
plot(x3,y3, 'b-', 'LineWidth', 2);
% x1, y1, x2, y2, and x3, y3 are our three curves.
% Now do steps 4, 5, and 6 of my algorithm in the prior comment.
% Now find the distances of each point from the centroid.
radii1 = sqrt((x1 - xCenter).^2 + (y1 - yCenter).^2);
radii2 = sqrt((x2 - xCenter).^2 + (y2 - yCenter).^2);
radii3 = sqrt((x3 - xCenter).^2 + (y3 - yCenter).^2);
% Get the average radii
averageRadii = (radii1 + radii2 + radii3) / 3;
% Get the new mean circle
xMean = averageRadii .* cos(theta) + xCenter;
yMean = averageRadii .* sin(theta) + yCenter;
figure
plot(xMean, yMean, 'k-', 'LineWidth', 2);
axis square;
xlim([6 18]);
ylim([4 18]);
grid on;
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0 0 1 1]);
Montree
Montree il 4 Gen 2015
Sory for late. Thank very much for your answer. This 3 image are sample data.
I follow your step and have a problem as below...
1. I find coordinate of line by use 'bwboundaries' function. The number of element of all line have difference number. So I use 'interp1' for resampling data (the number refer to maximum number of element.) and I have found this error 'The grid vectors are not strictly monotonic increasing.', I solve this problem by add small value to the same value such as.. [9 9] --> [9 9.0001] It can fix but....
(I use 1_1.bmp for testing) 'interp1' can use method 'nearest' only (other method not work) and I cannot solve this problem.
2. I think, I understand your concept but...
2.1) In picture 1. How you can make sure x, y and z are the sequence in them array. if the sequence of x, y and z are difference, your algorithm will have error.
2.2) If you can solve the problem in (2.1), you can calculate mean line by calculate mean of 3 position, this is true. But when the line parallel the radii line (same as picture 2) the mean position of x, y and z cannot calculate from mean of radii but you must calculate it from meaning of theta of 3 point. Do you think same as me? But this problem easy to solve by calculate mean of radii and theta.
Sorry for my english, hope you understand.
This is my code but it is not complete...
clc
clear
%%load image
PIC1 = imread('sample_photo\1_1.bmp');
PIC2 = imread('sample_photo\1_2.bmp');
PIC3 = imread('sample_photo\1_3.bmp');
%%modify edge line
bw1 = im2bw(PIC1);
bw1 = imfill(bw1,'holes');
bw1 = edge(bw1);
bw2 = im2bw(PIC2);
bw2 = imfill(bw2,'holes');
bw2 = edge(bw2);
bw3 = im2bw(PIC3);
bw3 = imfill(bw3,'holes');
bw3 = edge(bw3);
nbw = bw1+bw2+bw3;
%%find centroid of all
stat1 = regionprops(bw1,'centroid');
stat2 = regionprops(bw2,'centroid');
stat3 = regionprops(bw3,'centroid');
cent1 = stat1.Centroid;
cent2 = stat2.Centroid;
cent3 = stat3.Centroid;
%%find coordinate of all line
B1 = bwboundaries(bw1);
B2 = bwboundaries(bw2);
B3 = bwboundaries(bw3);
Line1 = B1{1};
Line2 = B2{1};
Line3 = B3{1};
Line = {Line1,Line2,Line3};
%%Iterpolate (make sure all line have same number of element)
% resampling all line to 1000 element
Xmin = min(Line1(:,2));
Xmax = max(Line1(:,2));
X = linspace(Xmin,Xmax,500);
LX = Line1(:,2)';
LY = Line1(:,1)';
UXL = 0;
UYL = 0;
while(UXL<length(LX))
[UX,ia,ic] = unique(LX,'stable');
LX(ia) = LX(ia)+1e-4;
UXL = length(UX);
end
while(UYL<length(LY))
[UY,ia,ic] = unique(LY,'stable');
LY(ia) = LY(ia)+1e-4;
UYL = length(UY);
end
Y = interp1(LX,LY,X,'nearest');
imshow(bw1);
hold on;
plot(X,Y,'ob')

Accedi per commentare.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by