How to create a centerline between lines in image?
10 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
Dekel Mashiach
le 3 Mai 2022
Commenté : Image Analyst
le 8 Mai 2022
Hi
I'm trying to convert the image to binary and create a centerline between the two white lines. Can someone please help me?
clc;
clearvars;
close all;
workspace;
grayImage = imread('road.png');
if ndims(grayImage) == 3
% It's color. Take the red channel.
grayImage = grayImage(:, :, 1);
end
figure
imshow(grayImage, []);
impixelinfo;
mask = logical(grayImage > 140 & grayImage < 255);
mask = bwareafilt(mask, 2); % Make sure we have only two lines.
mask = bwskel(mask);
figure
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 = ((r1(k) + r2) / 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, 'g.', 'MarkerSize', 10);
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, 'g.', 'MarkerSize', 10);
0 commentaires
Réponse acceptée
Image Analyst
le 8 Mai 2022
Try fitting each lane stripe to a line, then getting the average column for every row. You need to extend the fitted line outside the image so you can get the middle line when only one lane stripe is in the image, like at the bottom of your image.
% Demo by Image Analyst
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 22;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
folder = pwd;
baseFileName = 'road.png';
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~exist(fullFileName, 'file')
% The file doesn't exist -- didn't find it there in that folder.
% Check the entire search path (other folders) for the file by stripping off the folder.
fullFileNameOnSearchPath = baseFileName; % No path this time.
if ~exist(fullFileNameOnSearchPath, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist in the search path folders.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
rgbImage = imread(fullFileName);
% Get the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(rgbImage)
if numberOfColorChannels > 1
% It's not really gray scale like we expected - it's color.
fprintf('It is not really gray scale like we expected - it is color\n');
% Extract the blue channel.
grayImage = rgbImage(:, :, 3);
else
grayImage = rgbImage;
end
%--------------------------------------------------------------------------------------------------------
% Crop away white surrounding frame and other stuff in the screenshot to get the image alone.
grayImage = grayImage(34:752, 83:1362,:);
% Update the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage);
impixelinfo;
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Maximize window.
g = gcf;
g.WindowState = 'maximized';
drawnow;
% Display histogram.
subplot(2, 2, [2,4]);
histogram(grayImage);
grid on;
drawnow;
title('Histogram of Image', 'FontSize', fontSize, 'Interpreter', 'None');
%--------------------------------------------------------------------------------------------------------
% Binarize the image to get a mask.
lowThreshold = 192;
highThreshold = intmax(class(grayImage)) - 1;
% https://www.mathworks.com/matlabcentral/fileexchange/29372-thresholding-an-image?s_tid=srchtitle
% threshold(lowThreshold, highThreshold, grayImage);
mask = grayImage >= lowThreshold & grayImage <= highThreshold;
% Put red threshold line on histogram so they know where it was thresholded at.
xline(lowThreshold, 'Color', 'r', 'LineWidth', 2)
% Take only the two largest blobs.
mask = bwareafilt(mask, 2);
% Display mask image.
subplot(2, 2, 3);
imshow(mask);
hold on;
impixelinfo;
axis('on', 'image');
drawnow;
title('Mask, a Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Label the two blobs so we can fit a line through wach one, one at a time.
[labeledImage, numBlobs] = bwlabel(mask);
% Fit a line through the left blob
leftLine = ismember(labeledImage, 1);
[leftRows, leftCols] = find(leftLine);
coefficients = polyfit(leftRows, leftCols, 1)
% Make sure xFit is plenty wide enough so that y will span the vertical part of the image.
rowFitLeft = -10 * rows : 10 * rows;
colFitLeft = polyval(coefficients, rowFitLeft);
% Get indexes where y is out of the image
badIndexes = (rowFitLeft < 1) | (rowFitLeft > rows);
colFitLeft(badIndexes) = [];
rowFitLeft(badIndexes) = [];
% Plot line in red over road lane marker.
hold on;
plot(colFitLeft, rowFitLeft, 'r-', 'LineWidth', 3);
% Fit a line through the left blob
rightLine = ismember(labeledImage, 2);
[rightRows, rightCols] = find(rightLine);
coefficients = polyfit(rightRows, rightCols, 1)
rowFitRight = -10 * rows : 10 * rows;
colFitRight = polyval(coefficients, rowFitRight);
% Get indexes where y is out of the image
badIndexes = (rowFitRight < 1) | (rowFitRight > rows);
colFitRight(badIndexes) = [];
rowFitRight(badIndexes) = [];
% Plot line in red over road lane marker.
plot(colFitRight, rowFitRight, 'r-', 'LineWidth', 3);
% Get the middle line as the average of the two x values.
middleLineCols = (colFitLeft + colFitRight) / 2;
% Plot line in red over road lane marker.
plot(middleLineCols, rowFitRight, 'r-', 'LineWidth', 3);
2 commentaires
Image Analyst
le 8 Mai 2022
See this:
I haven't used it so can't answer questions about it so call the Mathworks if you have questions.
Plus de réponses (2)
Image Analyst
le 3 Mai 2022
Here are the stps I would try
- Crop the image to get rid of that white frame.
- Threshold the image to get the white lines.
- Call bwareafilt(bw, 2) to take only the 2 largest blobs.
- Scan down line-by-line using find() to get the first and last white pixel on each line.
- The center line is the average of the first column and the last column.
- If you want, you can fit a straight line through the centerline data to remove noise and smooth the line.
7 commentaires
Image Analyst
le 7 Mai 2022
@Abdul Hannan Qureshi that wasn't the post I was thinking of, but thanks. @Dekel Mashiach I just got back from 4 days of traveling. You probably have it solved by now, but if not, write back. I'd probably modify my steps 4-6 above and just fit a line on each side, then get the average x point for each fitted y value.
Voir également
Catégories
En savoir plus sur Image Processing Toolbox dans Help Center et File Exchange
Produits
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!