How to get the length of n curves present in an image in Matlab?

Currently, I was working on obtaining the length of the curve, with the following code I managed to get the length of the curve present in the image.

single curve test image

Then I insert the code I used to get the curve length of a simple image. I have done the following:

  • I got the columns and rows of the image
  • I got columns at x and rows at y
  • Curve coefficients based on the Parable formula are obtained.
  • Build equation
  • Introduce the arc length formula to get the length of the curve

    grayImage = imread(fullFileName); [rows, columns, numberOfColorBands] = size(grayImage); if numberOfColorBands > 1 grayImage = grayImage(:, :, 2); % Take green channel. end subplot(2, 2, 1); imshow(grayImage, []); % Get the rows (y) and columns (x). [rows, columns] = find(binaryImage); coefficients = polyfit(columns, rows, 2); % Gets coefficients of the formula. % Fit a curve to 500 points in the range that x has. fittedX = linspace(min(columns), max(columns), 500); % Now get the y values. fittedY = polyval(coefficients, fittedX); % Plot the fitting: subplot(2,2,3:4); plot(fittedX, fittedY, 'b-', 'linewidth', 4); grid on; xlabel('X', 'FontSize', fontSize); ylabel('Y', 'FontSize', fontSize); % Overlay the original points in red. hold on; plot(columns, rows, 'r+', 'LineWidth', 2, 'MarkerSize', 10) formula = poly2sym([coefficients(1),coefficients(2),coefficients(3)]); % formulaD = vpa(formula) df=diff(formula); df = df^2; f= (sqrt(1+df)); i = int(f,min(columns),max(columns)); j = double(i); disp(j); 

Now I have image 2, which has n curves, I don’t know how to do this to get the length of each curve

test image n curves

+5
source share
4 answers

I suggest you look at the Hough transformation: https://uk.mathworks.com/help/images/hough-transform.html

You will need the Image Processing Toolbox. Otherwise, you must develop your own logic.

https://en.wikipedia.org/wiki/Hough_transform

Update 1

I had a two-hour reflection on your problem, and I can only extract the first curve. The problem is to find the starting points of the curves. In any case, here is the code that I came up with and hopefully gives you some ideas for further development.

 clc;clear;close all; grayImage = imread('2.png'); [rows, columns, numberOfColorBands] = size(grayImage); if numberOfColorBands > 1 grayImage = grayImage(:, :, 2); % Take green channel. end % find edge. bw = edge(grayImage,'canny'); imshow(bw); [x, y] = find(bw == 1); P = [x,y]; % For each point, find a point that is of distance 1 or sqrt(2) to it, ie % find its connectivity. cP = cell(1,length(x)); for i = 1:length(x) px = x(i); py = y(i); dx = x - px*ones(size(x)); dy = y - py*ones(size(y)); distances = (dx.^2 + dy.^2).^0.5; cP{i} = [x(distances == 1), y(distances == 1); x(distances == sqrt(2)), y(distances == sqrt(2))]; end % pick the first point and a second point that is connected to it. fP = P(1,:); Q(1,:) = fP; Q(2,:) = cP{1}(1,:); m = 2; while true % take the previous point from point set Q, when current point is % Q(m,1) pP = Q(m-1,:); % find the index of the current point in point set P. i = find(P(:,1) == Q(m,1) & P(:,2) == Q(m,2)); % Find the distances from the previous points to all points connected % to the current point. dx = cP{i}(:,1) - pP(1)*ones(length(cP{i}),1); dy = cP{i}(:,2) - pP(2)*ones(length(cP{i}),1); distances = (dx.^2 + dy.^2).^0.5; % Take the farthest point as the next point. m = m+1; p_cache = cP{i}(find(distances==max(distances),1),:); % Calculate the distance of this point to the first point. distance = ((p_cache(1) - fP(1))^2 + (p_cache(2) - fP(2))^2).^0.5; if distance == 0 || distance == 1 break; else Q(m,:) = p_cache; end end % By now we should have built the ordered point set Q for the first curve. % However, there is a significant weakness and this weakness prevents us to % build the second curve. 

Update 2

Some more work since the last update. Now I can separate each curve. The only problem I see here is a good fit to the curve. I would suggest B-spline or Bezier curves than polynomial ones. I think I will stop here and leave you to find out the rest. Hope this helps.

Note that the following script uses the Image Processing Toolbox to find the edges of curves.

 clc;clear;close all; grayImage = imread('2.png'); [rows, columns, numberOfColorBands] = size(grayImage); if numberOfColorBands > 1 grayImage = grayImage(:, :, 2); % Take green channel. end % find edge. bw = edge(grayImage,'canny'); imshow(bw); [x, y] = find(bw == 1); P = [x,y]; % For each point, find a point that is of distance 1 or sqrt(2) to it, ie % find its connectivity. cP =[0,0]; % add a place holder for i = 1:length(x) px = x(i); py = y(i); dx = x - px*ones(size(x)); dy = y - py*ones(size(y)); distances = (dx.^2 + dy.^2).^0.5; c = [find(distances == 1); find(distances == sqrt(2))]; cP(end+1:end+length(c),:) = [ones(length(c),1)*i, c]; end cP (1,:) = [];% remove the place holder % remove duplicates cP = unique(sort(cP,2),'rows'); % seperating curves Q{1} = cP(1,:); for i = 2:length(cP) cp = cP(i,:); % search for points in cp in Q. for j = 1:length(Q) check = ismember(cp,Q{j}); if ~any(check) && j == length(Q) % if neither has been saved in Q Q{end+1} = cp; break; elseif sum(check) == 2 % if both points cp has been saved in Q break; elseif sum(check) == 1 % if only one of the points exists in Q, add the one missing. Q{j} = [Q{j}, cp(~check)]; break; end end % review sets in Q, merge the ones having common points for j = 1:length(Q)-1 q = Q{j}; for m = j+1:length(Q) check = ismember(q,Q{m}); if sum(check)>=1 % if there are common points Q{m} = [Q{m}, q(~check)]; % merge Q{j} = []; % delete the merged set break; end end end Q = Q(~cellfun('isempty',Q)); % remove empty cells; end % each cell in Q represents a curve. Note that points are not ordered. figure;hold on;axis equal;grid on; for i = 1:length(Q) x_ = x(Q{i}); y_ = y(Q{i}); coefficients = polyfit(y_, x_, 3); % Gets coefficients of the formula. % Fit a curve to 500 points in the range that x has. fittedX = linspace(min(y_), max(y_), 500); % Now get the y values. fittedY = polyval(coefficients, fittedX); plot(fittedX, fittedY, 'b-', 'linewidth', 4); % Overlay the original points in red. plot(y_, x_, 'r.', 'LineWidth', 2, 'MarkerSize', 1) formula = poly2sym([coefficients(1),coefficients(2),coefficients(3)]); % formulaD = vpa(formula) df=diff(formula); lengthOfCurve(i) = double(int((sqrt(1+df^2)),min(y_),max(y_))); end 

Result:

enter image description here

+2
source

You can get a good approximation of the length of the arc by using regionprops to estimate the perimeter of each area (that is, the arc), and then dividing it by 2. Here's how you do it (requires an Image Processing Tool ):

 img = imread('6khWw.png'); % Load sample RGB image bw = ~imbinarize(rgb2gray(img)); % Convert to grayscale, then binary, then invert it data = regionprops(bw, 'PixelList', 'Perimeter'); % Get perimeter (and pixel coordinate % list, for plotting later) lens = [data.Perimeter]./2; % Compute lengths imshow(bw) % Plot image hold on; for iLine = 1:numel(data), xy = mean(data(iLine).PixelList); % Get mean of coordinates text(xy(1), xy(2), num2str(lens(iLine), '%.2f'), 'Color', 'r'); % Plot text end 

And here is the plot:

enter image description here

As a health check, we can use a simple test image to see how well this gives us the following:

 testImage = zeros(100); % 100-by-100 image testImage(5:95, 5) = 1; % Add a vertical line, 91 pixels long testImage(5, 10:90) = 1; % Add a horizontal line, 81 pixels long testImage(2020:101:6060) = 1; % Add a diagonal line 41-by-41 pixels testImage = logical(imdilate(testImage, strel('disk', 1))); % Thicken lines slightly 

Running the above code on this image, we get the following:

enter image description here

As you can see, the horizontal and vertical line lengths are closer to what we expect, and the diagonal line is slightly larger than sqrt(2)*41 due to the fact that the dilatation step extends its length slightly.

+2
source

I try with this post, but I don’t understand much, but the Colors123 idea sounds great, this is a GUI post https://www.mathworks.com/matlabcentral/fileexchange/24195-gui-utility-to-extract-x- -y-data-series-from-matlab-figures

0
source

I think you need to go through the image and ask if there is β€œ1”, if so, ask the following and thus determine the beginning of the curve, get the length and save it in BD, I'm not very good with the code, But what’s mine idea

-1
source

Source: https://habr.com/ru/post/1266775/


All Articles