【问题标题】:Hough transform to detect and delete lines霍夫变换检测和删除线
【发布时间】:2015-07-05 08:17:34
【问题描述】:

我想使用 霍夫变换 来检测图像中的线条。但我不想绘制线条,而是想删除原始图像中检测到的每条线条。

image=imread('image.jpg');
image = im2bw(image);
BW=edge(image,'canny');
imshow(BW);
figure,imshow(BW);
[H,T,R] = hough(BW);
P  = houghpeaks(H,100,'threshold',ceil(0.3*max(H(:))));
lines = houghlines(BW,T,R,P,'FillGap',5,'MinLength',7);

在这之后,我得到了所有的台词。但我想从我的原始图像中删除所有这些行,保留图像的其余部分。有什么办法可以做到吗?

编辑我正在上传一张图片。我想删除所有线条并保留圆形部分。这只是一个示例图片。基本上我的目标是删除线段并保留其余部分图片

【问题讨论】:

  • 请发布示例图片。 “删除”一行是什么意思?
  • 为什么你不能只反转你的行的值,使这些行变成0 和其他所有1。这给了你一个面具。将蒙版与您的图像相乘,您就删除了线条。如果您想填补刚刚删除的行留下的空白,那就是另一个问题了。
  • @kkuilla 是的,但为此我需要定位线段的像素。我不想填充线条,只需将它们一一删除即可。
  • @Shai 我已经编辑了我的问题并添加了示例图片。

标签: matlab image-processing


【解决方案1】:

您遇到的问题是您的线条比一个像素粗。 霍夫变换的线条似乎只有一个像素厚, 这没有帮助。

我建议您先删除从霍夫变换中得到的行。 这将把曲棍球场分成几部分 这将更容易处理。

然后用 bwlabel 标记每个段。对于每个对象,找到 端点并在端点之间拟合一条线。如果线和对象 具有比某个阈值更多的共同像素,那么我们说对象 是一条线,我们将其从图像中删除。

您可能不得不使用霍夫变换的阈值。

虽然这种技术有一些缺陷。它将删除一个填充的正方形, 矩形或圆形,但你没有这些,所以你应该没问题。

结果


说明

这是您的代码,我稍作修改。我删除了渐变,因为它 使用实体对象更容易。渐变给出了非常细的线条。 我也处理补图,因为 bw 函数与 1 一起使用 与原始图像中的一样,而不是 0。

org_image_bw=im2bw(double(imread('http://i.stack.imgur.com/hcphc.png')));
image = imcomplement(org_image_bw);
[H,T,R] = hough(image);
P  = houghpeaks(H,100,'threshold',ceil(0.27*max(H(:))));
lines = houghlines(image,T,R,P,'FillGap',5,'MinLength',7);

遍历你得到的行并删除它们

processed_image = image;
for k = 1:length(lines)
   xy = [lines(k).point1; lines(k).point2];

    % // Use the question of a line y = kx + m to calulate x,y

    % // Calculate the maximum number of elements in a line
   numOfElems = max(max(xy(:,1))-min(xy(:,1)),max(xy(:,2))-min(xy(:,2)) ) ;

   % // Cater for the special case where the equation of a line is
   % // undefined, i.e. there is only one x value.
   % // We use linspace rather than the colon operator because we want
   % // x and y to have the same length and be evenly spaced.
   if (diff(xy(:,1)) == 0)           
       y = round(linspace(min(xy(:,2)),max(xy(:,2)),numOfElems));
       x = round(linspace(min(xy(:,1)),max(xy(:,1)),numOfElems));      
   else

       k = diff(xy(:,2)) ./ diff(xy(:,1)); % // the slope
       m = xy(1,2) - k.*xy(1,1); % // The crossing of the y-axis

       x = round(linspace(min(xy(:,1)), max(xy(:,1)), numOfElems));
       y = round(k.*x + m); % // the equation of a line
   end

   processed_image(y,x) = 0; % // delete the line
end

这是我们删除检测到的线条后图像的外观。请注意原来的曲棍球场并被分割成多个对象。

标记剩余的对象

L = bwlabel(processed_image);

遍历每个对象并找到终点。 然后给它画一条线。如果,假设 80% 的拟合线覆盖 对象,那么它就是一条线。

拟合线可能如下所示。蓝色对角线代表拟合线,涵盖了大部分 对象(白色区域)。因此,我们说对象是一条线。

% // Set the threshold
th = 0.8;

% // Loop through the objects
for objNr=1:max(L(:))
   [objy, objx] = find(L==objNr);

   % Find the end points
   endpoints = [min(objx) min(objy) ...
       ;max(objx) max(objy)];

   % Fit a line to it. y = kx + m
   numOfElems = max(max(endpoints(:,1))-min(endpoints(:,1)),max(endpoints(:,2))-min(endpoints(:,2)) ) ;

   % // Cater for the special case where the equation of a line is
   % // undefined, i.e. there is only one x value
   if (diff(endpoints(:,1)) == 0)           
       y = round(linspace(min(endpoints(:,2)),max(endpoints(:,2)),numOfElems));
       x = round(linspace(min(endpoints(:,1)),max(endpoints(:,1)),numOfElems));      
   else
       k = diff(endpoints(:,2)) ./ diff(endpoints(:,1)); % the slope
       m = endpoints(1,2) - k.*endpoints(1,1); % The crossing of the y-axis           
       x = round(linspace(min(endpoints(:,1)), max(endpoints(:,1)), numOfElems));

       y = round(k.*x + m);
       % // Set any out of boundary items to the boundary
       y(y>size(L,1)) = size(L,1);
   end

   % // Convert x and y to an index for easy comparison with the image
   % // We sort them so that we are comparing the same pixels
   fittedInd = sort(sub2ind(size(L),y,x)).';
   objInd = sort(sub2ind(size(L),objy,objx));

   % // Calculate the similarity. Intersect returns unique entities so we
   % // use unique on fittedInd
   fitrate = numel(intersect(fittedInd,objInd)) ./ numel(unique(fittedInd));
   if (fitrate >= th)
       L(objInd) = 0;
       processed_image(objInd) = 0;
       % // figure(1),imshow(processed_image)
   end       
end

显示结果

figure,imshow(image);title('Original');
figure,imshow(processed_image);title('Processed image');

完整示例

org_image_bw=im2bw(double(imread('http://i.stack.imgur.com/hcphc.png')));
image = imcomplement(org_image_bw);

[H,T,R] = hough(image);
P  = houghpeaks(H,100,'threshold',ceil(0.27*max(H(:))));
lines = houghlines(image,T,R,P,'FillGap',5,'MinLength',7);

processed_image = image;
    for k = 1:length(lines)
       xy = [lines(k).point1; lines(k).point2];

        % // Use the question of a line y = kx + m to calulate x,y

        %Calculate the maximum number of elements in a line
        numOfElems = max(max(xy(:,1))-min(xy(:,1)),max(xy(:,2))-min(xy(:,2)) ) ;

       % // Cater for the special case where the equation of a line is
       % // undefined, i.e. there is only one x value.
       % // We use linspace rather than the colon operator because we want
       % // x and y to have the same length and be evenly spaced.
       if (diff(xy(:,1)) == 0)           
           y = round(linspace(min(xy(:,2)),max(xy(:,2)),numOfElems));
           x = round(linspace(min(xy(:,1)),max(xy(:,1)),numOfElems));      
       else

           k = diff(xy(:,2)) ./ diff(xy(:,1)); % the slope
           m = xy(1,2) - k.*xy(1,1); % The crossing of the y-axis

           x = round(linspace(min(xy(:,1)), max(xy(:,1)), numOfElems));
           y = round(k.*x + m); % // the equation of a line
       end

       processed_image(y,x) = 0; % // delete the line
    end


    % // Label the remaining objects
    L = bwlabel(processed_image);

    % // Run through each object and find the end points.
    % // Then fit a line to it. If, let's say 80% the fitted line covers
    % // the object, then it is a line.

    % // Set the threshold
    th = 0.8;

    % // Loop through the objects
    for objNr=1:max(L(:))
       [objy, objx] = find(L==objNr);

       % Find the end points
       endpoints = [min(objx) min(objy) ...
           ;max(objx) max(objy)];

       % Fit a line to it. y = kx + m
       numOfElems = max(max(endpoints(:,1))-min(endpoints(:,1)),max(endpoints(:,2))-min(endpoints(:,2)) ) ;

       % Cater for the special case where the equation of a line is
       % undefined, i.e. there is only one x value
       if (diff(endpoints(:,1)) == 0)           
           y = round(linspace(min(endpoints(:,2)),max(endpoints(:,2)),numOfElems));
           x = round(linspace(min(endpoints(:,1)),max(endpoints(:,1)),numOfElems));      
       else
           k = diff(endpoints(:,2)) ./ diff(endpoints(:,1)); % the slope
           m = endpoints(1,2) - k.*endpoints(1,1); % The crossing of the y-axis           
           x = round(linspace(min(endpoints(:,1)), max(endpoints(:,1)), numOfElems));

           y = round(k.*x + m);
           % // Set any out of boundary items to the boundary
           y(y>size(L,1)) = size(L,1);
       end

       % // Convert x and y to an index for easy comparison with the image
       % // We sort them so that we are comparing the same pixels
       fittedInd = sort(sub2ind(size(L),y,x)).';
       objInd = sort(sub2ind(size(L),objy,objx));

       % Calculate the similarity. Intersect returns unique entities so we
       % use unique on fittedInd
       fitrate = numel(intersect(fittedInd,objInd)) ./ numel(unique(fittedInd));
       if (fitrate >= th)
           L(objInd) = 0;
           processed_image(objInd) = 0;
           % // figure(1),imshow(processed_image)
       end       
    end

   % // Display the result 
   figure,imshow(image);title('Original');
   figure,imshow(processed_image);title('Processed image');

【讨论】:

  • 正如我所说,这将适用于这张图片。但如果我有另一个对象说一个圆圈,那么这将不起作用
  • 但是你已经改变了你的问题。你的问题是专门关于线条的。不是圈子。
  • 是的,我想删除线段,保持图像的其余部分和以前一样。这是我最初的问题,我的问题仍然保持不变。我只想删除线段并将图像的其余部分保留为之前
  • @kkuilla 我认为你的答案在这里不适用。这将从图像中删除所有对象。但我认为 OP 只想删除线条。
  • 好的。我会得到它的。我错了。道歉。您的原始图像使我感到困惑。该代码将无法正常工作。 lines 是一个结构。不是图像。因此,您需要创建一个空图像 (mask) 并使用直线方程将线条绘制到图像上。反转蒙版并相乘。不幸的是,我现在没有时间纠正它。我必须稍后再做。道歉。
【解决方案2】:

您可以使用 J. E. Bresenham 的算法。它是由 A. Wetzler 在下面的matlab function 中实现的,我自己测试过。

该算法将为您提供线所在位置的像素坐标,前提是您将提供线的起点和终点,这已在上面的代码中的 lines 中给出。

这是我使用的代码,它使用了上面引用的matlab函数:

%This is your code above ========
image=imread('hcphc.png');
image = im2bw(image);
BW=edge(image,'canny');
imshow(BW);
figure,imshow(BW);
[H,T,R] = hough(BW);
P  = houghpeaks(H,100,'threshold',ceil(0.3*max(H(:))));
lines = houghlines(BW,T,R,P,'FillGap',5,'MinLength',7);
% =========

% Proposed solution:

% This will work for as many lines as you detected

for k=1:length(lines)

    % Call Bresenham's algorithm
    [x, y] = bresenham(lines(k).point1(1), lines(k).point1(2), ...
                       lines(k).point2(1), lines(k).point2(2));

    % This is where you replace the line, here I use 0, but you can use
    % whatever you want. However, note that if you use BW, you should only
    % replace with 0 or 1, because is a logical image. If you want to use 
    % the original image, well, you know what to do.
    BW(y, x) = 0;

    % And now watch the lines disapear!  (you can remove this line)
    imagesc(BW), drawnow; pause(1);
end

记住,先下载matlab function

【讨论】:

    猜你喜欢
    • 2013-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-20
    • 1970-01-01
    相关资源
    最近更新 更多