# How to create a centerline between lines in image?

23 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

### See Also

### Categories

### Products

### Community Treasure Hunt

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

Start Hunting!