Clear Filters
Clear Filters

How can I straighten a line in an image?

5 views (last 30 days)
I am trying to write a script that finds the width of a line from a microscope image. This script will be used to iterate through multiple images.
An example of the images that I will be processing and analyzing is below.
Here is my current script.
I=imread('220322_2_0101.jpg');
I=rgb2gray(I);
threshhold=120;
bw=I>threshhold;
%imshow(bw)
props = regionprops(logical(bw), 'Area');
allAreas = sort([props.Area]);
bw = bwareaopen(bw, 25);
bw2 = bwareafilt(bw,1);
BW2 = imfill(bw2,'holes');
line=edge(BW2,'Canny');
imshow(line)
So far, I have been able to process the image and find the edges of the line. I am hoping to translate the wiggly edge lines to straight lines so that I can use their equations to find width of the line. My idea was to find an average of the wiggly lines, however, this is difficult because they are not perfectly horizontal.
Here is the output image.
I would greatly appreciate any assistance or further reccomendations.

Accepted Answer

Matt J
Matt J on 28 Mar 2022
Edited: Matt J on 28 Mar 2022
It sounds like what you would want to do is fit the squiggle with two lines that are constrained to be parallel. That can be done as below. Once you've done that, you can define the line thickness in different ways. In the code below, I define it as the difference in the two y-intercepts of the line fits, but you could of course calculate the perpendicular distance between the lines as well.
load bwImage
reg=regionprops(bwareafilt(BW,2),'PixelList');
xy={reg.PixelList}';
for i=1:2
A{i}=xy{i}(:,1).^[1,0];
A{i}(:,3)=0;
b{i}=xy{i}(:,2);
end
A{2}=A{2}(:,[1,3,2]);
A=cell2mat(A(:)); b=cell2mat(b(:));
coeffs=A\b;
lineThickness=abs(coeffs(3)-coeffs(2))
lineThickness = 198.1814
p1=coeffs(1:2); %polynomial coefficients: line fit 1
p2=coeffs([1,3]); %polynomial coefficients: line fit 2
x=1:size(BW,2);
y1=polyval(p1,x);
y2=polyval(p2,x);
imshow(BW); hold on
plot(x,y1,'c',x,y2,'c'); hold off

More Answers (1)

Image Analyst
Image Analyst on 28 Mar 2022
Edited: Image Analyst on 28 Mar 2022
Why are you messing with the edges of the "line"? I don't see why that's needed. Don't you just want to fit a line though everything? Like (untested):
[y, x] = find(bw); % Find all point coordinates in the image.
coefficients = polyfit(x, y, 1); % Fit to a line.
[rows, columns] = size(bw);
xFit = 1 : columns;
yFit = polyval(coefficients, xFit)
% Plot it over the image.
hold on;
plot(xFit, yFit, 'r-', 'LineWidth', 3);
hold off;
Now, if you want the height (vertical distance) of the "solid part" of the blob, you can find it's area and then divide by the width.
bw2 = bwareafilt(bw, 1); % Take largest blob.
bw2 = imfill(bw2, 'holes'); % Fill holes.
props = regionprops(bw2, 'Area');
meanHeight = sum([props.Area]) / columns % Valid since the blob goes all the way across the image.
Here is a full demo:
% 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 = 16;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
folder = pwd;
baseFileName = 'microscope line.jpeg';
% baseFileName = 'image_2732.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
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 1, 1);
imshow(grayImage);
impixelinfo;
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Maximize window.
g = gcf;
g.WindowState = 'maximized';
drawnow;
%--------------------------------------------------------------------------------------------------------
% Binarize the image to get a mask.
mask = imbinarize(grayImage);
mask = imfill(mask, 'holes');
% Display mask image.
subplot(2, 1, 2);
imshow(mask);
hold on;
impixelinfo;
axis('on', 'image');
drawnow;
title('Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
[y, x] = find(mask); % Find all point coordinates in the image.
coefficients = polyfit(x, y, 1) % Fit to a line.
xFit = 1 : columns;
yFit = polyval(coefficients, xFit)
% Plot it over the images.
hold on;
plot(xFit, yFit, 'r-', 'LineWidth', 3);
hold off;
subplot(2, 1, 1);
hold on;
plot(xFit, yFit, 'r-', 'LineWidth', 3);
hold off;
% Compute the width
props = regionprops(mask, 'Area');
meanHeight = sum([props.Area]) / columns % Valid since the blob goes all the way across the image.
% Tell the user
message = sprintf('Mean Height = %.1f pixels. Width = %d pixels.', meanHeight, columns);
subplot(2, 1, 2);
title(message, 'FontSize', fontSize, 'Interpreter', 'None');
uiwait(helpdlg(message))

Products


Release

R2018b

Community Treasure Hunt

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

Start Hunting!