How to create a centerline between lines in image?
3 views (last 30 days)
Show older comments
Dekel Mashiach
on 3 May 2022
Commented: Image Analyst
on 8 May 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 Comments
Accepted Answer
Image Analyst
on 8 May 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 Comments
Image Analyst
on 8 May 2022
See this:
I haven't used it so can't answer questions about it so call the Mathworks if you have questions.
More Answers (2)
Image Analyst
on 3 May 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 Comments
Image Analyst
on 7 May 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.
See Also
Categories
Find more on Image Processing Toolbox in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!