How to create a centerline between lines in image

Hi,
I'm trying to create a centerline between the two lines. Can someone help me?
[rows, columns] = size(birdsEyeImage);
leftEdges = nan(rows, 1);
rightEdges = nan(rows, 1);
for row = 1 : rows
t = find(birdsEyeImage(row, :), 1, 'first');
if ~isempty(t)
leftEdges(row) = t;
rightEdges(row) = find(birdsEyeImage(row, :), 1, 'last');
end
end
midPoints = ((leftEdges + rightEdges) / 2);
imshow(birdsEyeImage)
hold on
%x = 1:rows;
plot(midPoints, '*')

2 Comments

I'm trying to create a centerline between the two lines.
I see 4 lines in the image you have posted, two white and two blue.
yes, I want to find a centerline between the two white lines. I tried with my sample code and it gave me the two blue lines instead of what i wanted.

Sign in to comment.

 Accepted Answer

If you want no breaks, then interpolate. Like this. midX and midY are the line coordinates.
% Initialization steps.
clc;
clearvars;
close all;
workspace;
fontSize = 16;
grayImage = imread('2 lines.png');
if ndims(grayImage) == 3
% It's color. Take the red channel.
grayImage = grayImage(:, :, 1);
end
imshow(grayImage, []);
impixelinfo;
axis('on', 'image')
mask = logical(grayImage > 140 & grayImage < 255);
mask = bwareafilt(mask, 2); % Make sure we have only two lines.
mask = bwskel(mask);
imshow(mask);
impixelinfo;
axis('on', 'image')
labeledImage = bwlabel(mask);
line1 = ismember(labeledImage, 1);
line2 = ismember(labeledImage, 2);
% Get rows and columns of each line.
[r1, c1] = find(line1);
[r2, c2] = find(line2);
for k = 1 : length(r1)
distances = sqrt((r1(k) - r2) .^ 2 + (c1(k) - c2) .^ 2);
[minDistance, index] = min(distances);
% Find the midPoint
midX(k) = mean([c1(k), c2(index)]);
midY(k) = mean([r1(k), r2(index)]);
% Burn into mask
mask(round(midY(k)), round(midX(k))) = true;
end
% Need to add a small amount of noise to x to make the values unique.
midX = midX + 0.001 * rand(size(midX));
midY = midY + 0.001 * rand(size(midY));
% Interpolate x and y to make sure there are no gaps.
kVec = 1 : length(midX);
kFit = linspace(1, kVec(end), 10000);
xFit = interp1(kVec, midX, kFit, 'linear');
yFit = interp1(kVec, midY, kFit, 'linear');
% Remove duplicate values
xy = unique(round([xFit(:), yFit(:)]), "rows");
% Extract individual x and y.
midX = xy(:, 1);
midY = xy(:, 2);
hold on;
plot(midX, midY, 'r.', 'MarkerSize', 10);

2 Comments

If it worked, the usual thing to do is to click the "Accept this answer", 🙂 unless you want to wait to see if anyone else will offer a better answer.

Sign in to comment.

More Answers (2)

Make it easy for us to help you. Attach the actual PNG image file, not a Fig file. Then we can open it with imread() and not have any other stuff surrounding it like tick marks, etc. Just attach the one with white lines, not white and blue lines.
What I'd to is to skeletonize and label the image. Then I'd loop over all pixels in the one line and use sqrt() to get distances to all the other pixels in the other line. Then use min() to get the index of the closest one. Then get the average of the two pixels x and y values and assign that point to be true or use plot() to drop a marker there. Here's a start
mask = logical(imread(filename));
mask = bwareafilt(mask, 2); % Make sure we have only two lines.
mask = bwskel(mask);
imshow(mask);
labeledImage = bwlabel(mask);
line1 = ismember(labeledImage, 1);
line2 = ismember(labeledImage, 2);
% Get rows and columns of each line.
[r1, c1] = find(line1);
[r2, c2] = find(line2);
for k = 1 : length(r1)
distances = sqrt((r1(k) - r2) .^ 2 + (c1(k) - c2) .^ 2);
[minDistance, index] = min(distances);
% Find the midPoint
midX = mean([c1(k), c2(index)]);
midY = mean([r1(k), r2(index)]);
% Burn into mask
mask(round(midY), round(midX)) = true;
% Optionally drop a marker there
hold on;
plot(midX, midY, 'r.', 'MarkerSize', 10);
end

2 Comments

thanks. the PNG image is included.
OK, that's a color image, not a binary image. So I need to do a little extra color segmentation to get just the two lines. But I did it for you and here it is:
% Initialization steps.
clc;
clearvars;
close all;
workspace;
fontSize = 16;
grayImage = imread('2 lines.png');
if ndims(grayImage) == 3
% It's color. Take the red channel.
grayImage = grayImage(:, :, 1);
end
imshow(grayImage, []);
impixelinfo;
mask = logical(grayImage > 140 & grayImage < 255);
mask = bwareafilt(mask, 2); % Make sure we have only two lines.
mask = bwskel(mask);
imshow(mask);
labeledImage = bwlabel(mask);
line1 = ismember(labeledImage, 1);
line2 = ismember(labeledImage, 2);
% Get rows and columns of each line.
[r1, c1] = find(line1);
[r2, c2] = find(line2);
for k = 1 : length(r1)
distances = sqrt((r1(k) - r2) .^ 2 + (c1(k) - c2) .^ 2);
[minDistance, index] = min(distances);
% Find the midPoint
midX = mean([c1(k), c2(index)]);
midY = mean([r1(k), r2(index)]);
% Burn into mask
mask(round(midY), round(midX)) = true;
% Optionally drop a marker there
hold on;
plot(midX, midY, 'r.', 'MarkerSize', 10);
end
If you want the line to be unbroken, you can use interp1() to get a value for either every row or every column. Just index your midpoints and call interp1(). I think you can do it, right?

Sign in to comment.

thank you!!!! ,you helped me so much and i'm trying to make the line unbroken. just a final question: can you elaborate what parameters should go into the interp1() function?

Categories

Community Treasure Hunt

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

Start Hunting!