How to create a centerline between lines in image
5 ビュー (過去 30 日間)
古いコメントを表示
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 件のコメント
Matt J
2022 年 4 月 23 日
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.
採用された回答
Image Analyst
2022 年 4 月 23 日
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 件のコメント
Image Analyst
2022 年 4 月 23 日
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.
その他の回答 (2 件)
Image Analyst
2022 年 4 月 23 日
編集済み: Image Analyst
2022 年 4 月 23 日
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 件のコメント
Image Analyst
2022 年 4 月 23 日
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?
参考
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!