【问题标题】:How to get the length of n curves present in an image in Matlab?如何在 Matlab 中获取图像中存在的 n 条曲线的长度?
【发布时间】:2017-09-11 23:00:36
【问题描述】:

目前我一直在努力获取曲线的长度,通过以下代码我设法获得了图像中曲线的长度。

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

现在我有图像 2,它有 n 条曲线,我不知道如何获得每条曲线的长度

test image n curves

【问题讨论】:

    标签: image matlab curves


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我尝试了这篇文章,但我不太了解,但 Colours123 的想法听起来很棒,这篇文章谈论的是 GUI https://www.mathworks.com/matlabcentral/fileexchange/24195-gui-utility-to-extract-x--y-data-series-from-matlab-figures

      【讨论】:

        【解决方案3】:

        我建议你看看霍夫变换: 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
        

        结果:

        【讨论】:

        • 我需要得到这个图像中所有曲线的函数,因为我变长了,我不使用hought变换
        • 好吧,我错了。霍夫变换仅有助于找到线性边缘。我在这里有一些想法,但有一个主要问题。在您的第二张图片中,曲线的粗细不是 1 个像素。这是我们必须处理的还是曲线通常有 1 个像素厚?
        • 有时粗细会有所不同,但一般都会在最小像素范围内
        • 我正在阅读有关霍夫变换的内容,并且我非常耳熟能详,详细信息是,如果我有可能得到曲线方程,如果我得到方程,我会以直线阅读,但我有曲线给你同样的东西,除了阅读参考书目之外,我还在检查你的更新,看看是否有办法用霍夫变换来做到这一点,以防你有我的代码当霍夫已经为您提供了大部分内容时,这已经是多余的了。
        • 我的主要问题是我不应该使用任何 GUI 或工具箱,如果我设法取得一些进展,我会将其发布在这里与您分享我的知识,我正在检查您的工作,谢谢 :)
        【解决方案4】:

        您可以使用regionprops 估算每个区域的周长(即弧),然后将其除以 2,从而获得弧长的一个很好的近似值。以下是您的操作方法(需要 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 稍长一点,因为膨胀步骤稍微延长了它的长度。

        【讨论】:

          猜你喜欢
          • 2011-12-20
          • 1970-01-01
          • 1970-01-01
          • 2010-10-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多