如何在Matlab中获取图像中n条曲线的长度?

5

目前我一直在研究如何获取曲线的长度,通过以下代码,我已经成功地获得了图像中曲线的长度。

测试图像一个曲线

然后我粘贴了用于获取简单图像曲线长度的代码。我的做法如下:

  1. I got the columns and rows of the image
  2. I got the columns in x and the rows in y
  3. I obtained the coefficients of the curve, based on the formula of the parable
  4. Build the equation
  5. Implement the arc length formula to obtain 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);
    
现在我有图像2,其中有n条曲线,我不知道如何获取每条曲线的长度。 测试图像n条曲线
4个回答

2

您可以使用regionprops估计每个区域(即弧)的周长,然后将其除以2,从而得到弧长的良好近似值。以下是如何执行此操作的步骤(需要图像处理工具箱):

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

这里是它所产生的绘图:

在此输入图片描述

作为一个健全性检查,我们可以使用一张简单的测试图片来看看这个近似值有多好:

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

在这张图片上运行以上代码,我们得到以下结果:

enter image description here

可以看到,水平线和垂直线的长度接近我们的预期,对角线的长度稍微大于sqrt(2)*41,因为膨胀步骤略微延长了它的长度。请注意保留HTML标签。

2
我建议您查看霍夫变换(Hough Transformation): https://uk.mathworks.com/help/images/hough-transform.html 您需要使用图像处理工具箱(Image Processing Toolbox)。否则,您需要开发自己的逻辑。 https://en.wikipedia.org/wiki/Hough_transform 更新1 我思考了两个小时,只能提取第一条曲线。问题在于定位曲线的起点。无论如何,这是我想出来的代码,希望能给您进一步开发提供一些想法。
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, i.e.
% 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.

更新 2

自上次更新以来做了更多的工作。我现在能够分离每条曲线。我唯一看到的问题是如何拟合好曲线。我建议使用B样条或贝塞尔曲线而不是多项式拟合。我想我会在这里停下来,让你去解决剩下的问题。希望这能帮到你。

请注意,以下脚本使用图像处理工具箱查找曲线的边缘。

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, i.e.
% 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

结果:

这里输入图片描述


我需要获取此图像中所有曲线的函数,因为我得到了长度,我不使用霍夫变换。 - AlexZ
我正在阅读霍夫变换的相关内容,我已经听说过它了,但问题在于如果我能够得到曲线方程,对于直线来说,如果我得到了方程,但是对于曲线来说,是否也可以得到相同的结果。我正在检查您的更新并阅读参考文献,以查看是否有使用霍夫变换的方法来解决这个问题,如果可以的话,我的代码将会变得多余,因为霍夫变换已经提供了大部分的功能。 - AlexZ
我的主要问题是我不应该使用任何GUI或工具箱,如果我取得了一些进展,我会在这里发布它来与您分享我的知识,我正在检查您的工作,谢谢 :) - AlexZ
代码中只有一行 bw = edge(grayImage,'canny'); 需要使用 _图像处理工具箱_。如果您无法使用该工具箱,则可以在 边缘函数文档页面 的底部找到三个参考链接,您可以使用它们编写自己的边缘函数。 - Anthony
好的,谢谢。我会继续努力并希望能分享更多,感谢您的关注。 - AlexZ
显示剩余6条评论

0

-1

我认为你应该浏览这张图片并询问是否有“1”,如果是,就问以下问题,从而确定曲线的起点,获取长度并将其保存在BD中。我对代码不是很擅长,但这是我的想法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接