how to straighten lines in an image?

5 views (last 30 days)
hello I'm trying to detect lanes in an image and for that I want a way to choose only the lanes part of the image and straighten it to a rectangle, I think there's some function in OpenCV so I was wondering if there is one in Matlab as well or some other way to straighten the image at certain points.
thanks :).

Accepted Answer

Image Analyst
Image Analyst on 6 Dec 2017
Try imwarp().
  2 Comments
noam Y
noam Y on 7 Dec 2017
Edited: noam Y on 8 Dec 2017
thanks ill give it a try
UPDATE:
it's a nice function but it doesnt serve my purpose all the way.
is there any other way that could virtually transform the image on a certain axel? changing shape from an upright trapezoid to a rectangle. thanks.
Image Analyst
Image Analyst on 9 Dec 2017
You can use imtransform(). Here's a snippet from my program. Go ahead and use/adapt it it you want:
while strcmpi(reply, 'Redraw') > 0
hold off;
imshow(original_RGB_Image);
% hold on;
title('Original Image', 'FontSize', 18);
set(gcf, 'units','normalized','outerposition',[0 0 1 1]); % Maximize figure.
[rows, columns, numberOfColors] = size(original_RGB_Image);
userPrompt = sprintf('Left click at the centers of the corner spots on the 96 well plate\ngoing counter-clockwise from the upper left spot.\nFor the 4th spot (upper right) right-click to finish the quadrilateral.');
uiwait(msgbox(userPrompt));
numberOfVertices = 0;
while numberOfVertices ~= 5
[~, xCorners, yCorners] = roipolyold();
numberOfVertices = length(xCorners);
% Take the first 5 points. If it's less than 5, let them know.
if numberOfVertices > 5
% Take the first 5.
xCorners = xCorners(1:5);
yCorners = yCorners(1:5);
numberOfVertices = length(xCorners); % Recalculate it.
elseif numberOfVertices < 5
userPrompt = sprintf('You clicked %d points.\nPlease click exactly 4 points only.\n\nRemember LEFT-CLICK the first 3 corners,\nthen RIGHT-CLICK the last (4th) point.', numberOfVertices-1);
uiwait(msgbox(userPrompt));
end
end
if printToCommandWindow
fprintf(1, 'x=%.1f ', xCorners);
fprintf(1, '\n');
fprintf(1, 'y=%.1f ', yCorners);
end
% Sort the corners into the first one being the upper left, and then going counter-clockwise after that.
% It won't work otherwise.
[xCorners, yCorners] = sortCorners(xCorners, yCorners, rows, columns);
% Draw the quadrilateral.
hold on;
plot([xCorners(1) xCorners(2) xCorners(3) xCorners(4) xCorners(1)], [yCorners(1) yCorners(2) yCorners(3) yCorners(4) yCorners(1)], 'linewidth', 3, 'color', [1 0 1]); % Top line
caption = sprintf('(%.1f, %.1f)', xCorners(1), yCorners(1));
text(xCorners(1)-25, yCorners(1)+9, caption, 'fontsize', 8, 'Color', [1 1 0]);
caption = sprintf('(%.1f, %.1f)', xCorners(2), yCorners(2));
text(xCorners(2)-25, yCorners(2)+9, caption, 'fontsize', 8, 'Color', [1 1 0]);
caption = sprintf('(%.1f, %.1f)', xCorners(3), yCorners(3));
text(xCorners(3)-25, yCorners(3)+9, caption, 'fontsize', 8, 'Color', [1 1 0]);
caption = sprintf('(%.1f, %.1f)', xCorners(4), yCorners(4));
text(xCorners(4)-25, yCorners(4)+9, caption, 'fontsize', 8, 'Color', [1 1 0]);
% Create the desired coordinates;
x1 = mean([xCorners(1) xCorners(2)]);
x2 = mean([xCorners(3) xCorners(4)]);
y1 = mean([yCorners(1) yCorners(4)]);
y2 = mean([yCorners(2) yCorners(3)]);
% T = maketform('projective',U,X) builds a TFORM struct T for a two-dimensional projective transformation
% that maps each row of U to the corresponding row of X.
% The U and X arguments are each 4-by-2 and define the corners of input and output quadrilaterals.
% No three corners can be collinear.
U = [xCorners(1), yCorners(1);...
xCorners(2), yCorners(2);...
xCorners(3), yCorners(3);...
xCorners(4), yCorners(4)];
X = [x1 y1; x1 y2; x2 y2; x2 y1];
T = maketform('projective', U, X);
% tformfwd([10 20],T)
% Let's see where the corners of the image get moved to.
imageCornersX = [1 1 columns columns];
imageCornersY = [1 rows rows 1];
[mappedCornerLocationsX, mappedCornerLocationsY] = tformfwd(T, imageCornersX, imageCornersY);
if printToCommandWindow
fprintf(1, '%6.3f\n', mappedCornerLocationsX);
fprintf(1, '%6.3f\n', mappedCornerLocationsY);
end
newUpperLeftX = min(mappedCornerLocationsX);
newUpperLeftY = min(mappedCornerLocationsY) ;
% Transform (warp) the image.
transformedImage = imtransform(original_RGB_Image, T);
clear('original_RGB_Image'); % Free up memory for wimpy 32 bit computers.
axes(handles.axesImage);
imshow(transformedImage);
% subplot(1,2,2);
figure(handleToOriginal);
imshow(transformedImage, []);
% set(gcf, 'units','normalized','outerposition',[0 0 1 1]); % Maximize figure.
title('Transformed image', 'FontSize', 18);
drawnow;
hold on;
diameter = UserSettings.circleDiameter; % Diameter of spot or width of rectangle.
% Draw the shapes and bounding box.
% The line was drawn in the centers of the circles, but the circles are drawn with the rectangle function which actually has
% the (x,y) location as the upper left of the bounding box of the circle.
xSpacing = abs(x2 - x1) / (UserSettings.columns - 1);
ySpacing = abs(y2 - y1) / (UserSettings.rows - 1);
% Draw the bounding box.
line([x1 - newUpperLeftX, x2 - newUpperLeftX], [y1 - newUpperLeftY, y1 - newUpperLeftY], 'linewidth', 3, 'color', [1 0 1]); % Top line
line([x1 - newUpperLeftX, x1 - newUpperLeftX], [y1 - newUpperLeftY, y2 - newUpperLeftY], 'linewidth', 3, 'color', [1 0 1]); % Left line
line([x1 - newUpperLeftX, x2 - newUpperLeftX], [y2 - newUpperLeftY, y2 - newUpperLeftY], 'linewidth', 3, 'color', [1 0 1]); % Bottom line
line([x2 - newUpperLeftX, x2 - newUpperLeftX], [y1 - newUpperLeftY, y2 - newUpperLeftY], 'linewidth', 3, 'color', [1 0 1]); % Right line
% Make up arrays of the dpecified shape.
if UserSettings.isCircle
% Initialize an image to hold one single small circle.
smallCircleRadius = diameter / 2.0;
smallCircleImage = zeros(2*smallCircleRadius, 2*smallCircleRadius);
[x, y] = meshgrid(1:smallCircleRadius*2, 1:smallCircleRadius*2);
singleShapeImage = false(2*smallCircleRadius, 2*smallCircleRadius);
singleShapeImage((x - smallCircleRadius).^2 + (y - smallCircleRadius).^2 <= smallCircleRadius.^2) = true;
else
% The shapes are rectangles.
% Initialize an image to hold one single small rectangle.
singleShapeImage = true(diameter);
end
hold off;
% imshow(singleShapeImage, []);
% drawnow;
[transformedRows, transformedCols, transformedNumberOfColors] = size(transformedImage);
shapeMaskArray = false([transformedRows, transformedCols]);
[singleHeight, singleWidth] = size(singleShapeImage);
% x1, x2, y1, and y2 all refer to the center of the circle, not the upper left of the bounding box.
for row = 1 : UserSettings.rows
% yctr0 = (row - 1) * ySpacing + y1;
yctr = (row - 1) * ySpacing + y1 - newUpperLeftY;
boxY = yctr - diameter/2;
for col = 1 : UserSettings.columns
% xctr0 = (col - 1) * xSpacing + x1;
% plot(xctr0, yctr0, '+');
xctr = (col - 1) * xSpacing + x1 - newUpperLeftX;
boxX = xctr - diameter/2;
rectangle('Position',[boxX, boxY, diameter, diameter], 'Curvature',[1,1], 'EdgeColor', [0 .5 0], 'LineWidth', 2);
% caption = sprintf('(%d, %d)', round(xctr), round(yctr));
% text(xctr-25, yctr+9, caption, 'fontsize', 8, 'Color', [1 1 0]);
centers(row, col, 1) = xctr;
centers(row, col, 2) = yctr;
% Find the square in the big image where we're going to add a small circle.
x1b = ClipToRange(boxX, 1, transformedCols);
x2b = ClipToRange((x1b + singleWidth - 1), 1, transformedCols);
y1b = ClipToRange(boxY, 1, transformedRows);
y2b = ClipToRange((y1b + singleHeight - 1), 1, transformedRows);
% Add in one small circle to the existing big image.
shapeMaskArray(y1b:y2b, x1b:x2b) = shapeMaskArray(y1b:y2b, x1b:x2b) + singleShapeImage;
end
end
% It might be 2 if shapes overlap. Make sure the max is 1
shapeMaskArray = min(shapeMaskArray, 1);
% imshow(shapeMaskArray);
% drawnow;
% handleToMaskFigure = figure;
% imshow(circleMaskArray, []);
% set(gcf, 'units','normalized','outerposition',[0 0 1 1]); % Maximize figure.
% Make a visualization where the masked array regions are full brightness but the out of mask regions are half brightness.
% Mask the image using bsxfun() function
maskedRgbImage = bsxfun(@times, transformedImage, cast(shapeMaskArray, class(transformedImage)));
outsideMaskRgbImage = uint8(bsxfun(@times, transformedImage, cast(~shapeMaskArray, class(transformedImage)))/2); % Half brightness.
imshow(maskedRgbImage + outsideMaskRgbImage);
drawnow;
clear('maskedRgbImage', 'outsideMaskRgbImage'); % Free up memory
[labeledImage, numberOfBlobs] = bwlabel(shapeMaskArray, 8); % Label each blob so we can make measurements of it
clear('shapeMaskArray'); % Free up memory.
% Get each plane and its measurements. Then free up the image to reduce memory usage as much as possible for 32 bit computers.
redPlane = transformedImage(:, :, 1);
blobMeasurementsR = regionprops(labeledImage, redPlane, 'all');
clear('redPlane');
greenPlane = transformedImage(:, :, 2);
blobMeasurementsG = regionprops(labeledImage, greenPlane, 'all');
clear('greenPlane');
bluePlane = transformedImage(:, :, 3);
blobMeasurementsBlue = regionprops(labeledImage, bluePlane, 'all');
clear('bluePlane');
if printToCommandWindow
fprintf(1,'Blob # Mean Red, Mean Green, Mean Blue, Centroid-x Centroid-y\n');
end
for k = 1 : numberOfBlobs % Loop through all blobs.
% Find the mean of each blob. (R2008a has a nice way where you can pass the original image
% directly into regionprops.)
thisBlobsPixelsR = blobMeasurementsR(k).PixelIdxList; % Get list of pixels in current blob.
thisBlobsPixelsG = blobMeasurementsG(k).PixelIdxList; % Get list of pixels in current blob.
thisBlobsPixelsBlue = blobMeasurementsBlue(k).PixelIdxList; % Get list of pixels in current blob.
meanGLR = blobMeasurementsR(k).MeanIntensity; % Mean again, but only for version >= R2008a
meanGLG = blobMeasurementsG(k).MeanIntensity; % Mean again, but only for version >= R2008a
meanGLBlue = blobMeasurementsBlue(k).MeanIntensity; % Mean again, but only for version >= R2008a
blobCentroid = blobMeasurementsR(k).Centroid; % Get centroid.
if printToCommandWindow
fprintf(1,' #%d: %8.2f %8.2f %8.2f, %8.1f %8.1f\n', k, meanGLR, meanGLG, meanGLBlue, blobCentroid);
end
text(blobCentroid(1), blobCentroid(2), num2str(k), 'Color', 'g');
end
drawnow;
% Ask user if it's okay.
userPrompt = sprintf('Please verify the mask placement.\nDo you want to accept it, or redraw it?');
reply = questdlg(userPrompt, ...
'Mask OK?', 'Accept', 'Redraw', 'Accept');
drawnow;
% reply = '' for Upper right X, otherwise it's the exact wording.
end

Sign in to comment.

More Answers (0)

Categories

Find more on Image Processing and Computer Vision in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!