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

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

目前我一直致力于获取曲线的长度,使用以下代码我已经设法获取图像中存在的曲线长度。

test image one curve

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

  1. 我得到了图像的列和行
  2. 我得到了 x 中的列和 y 中的行
  3. 我根据公式得到了曲线的系数 寓言
  4. 构建方程式
  5. 执行弧长公式得到曲线的长度

    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);
    

现在我有一个有n条曲线的图像2,我不知道如何才能得到每条曲线的长度

test image n curves

我认为你应该通过图像并询问是否有'1'如果有,请询问以下内容从而识别曲线的开头,获取长度并将其保存在BD中,我是代码不是很好,但这是我的想法

我试着用这个 post 但我不太了解,但是 Colours123 的想法听起来不错,这个 post 谈论 GUI https://www.mathworks.com/matlabcentral/fileexchange/24195-gui-utility-to-extract-x--y-data-series-from-matlab-figures

我建议你看看霍夫变换: https://uk.mathworks.com/help/images/hough-transform.html

您将需要图像处理工具箱。否则,你必须发展自己的逻辑。

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 样条曲线或贝塞尔曲线而不是多项式拟合。我想我会在这里停下来,让您自己解决剩下的问题。希望这有帮助。

请注意,以下脚本使用 Image Processing Toolbox 来查找曲线的边缘。

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

结果:

您可以使用 regionprops to estimate the perimeter of each region (i.e. arc) and then dividing that by 2. Here's how you would do this (requires the Image Processing Toolbox):

获得很好的弧长近似值
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

运行上面的代码在这张图片上,我们得到如下:

如您所见,水平线和垂直线的长度接近我们的预期,并且由于扩张步骤稍微延长了对角线的长度,对角线比 sqrt(2)*41 多一点。