Hough变换用于检测和删除线。

时间:2022-09-12 13:38:58

I want to use the Hough transform to detect lines in my image.But instead of plotting the lines I want to delete each line detected in my original image.

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

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

Now after this I have got all the lines. But I want to delete all these lines from my original image, keeping rest of the image as before. Is there some way I can do this?

在这之后,我得到了所有的线。但是我想要从原来的图像中删除所有这些线条,保留原来的图像。有什么办法我能做到吗?

Edit I am uploading an image.I want to delete all the lines and keep the circular part.This is just an example image.Basically my objective is to delete the line segments and keep rest of the image Hough变换用于检测和删除线。

编辑我正在上传一个图像。我要删除所有的行,保留圆形部分。这只是一个例子。基本上我的目标是删除线段并保留图像的剩余部分。

2 个解决方案

#1


2  

The issue you have is that your lines are thicker than one pixel. The lines from the hough transform seem to be one pixel thick and that doesn't help.

你的问题是你的线比一个像素要厚。来自霍夫变换的线条似乎只有一个像素的厚度,这并没有帮助。

I propose that you delete the lines that you get from the Hough transform first. This will sort of divide the hockey rink of whatever it is into segments that will be easier to process.

我建议您先删除从霍夫转换中得到的行。这将会将曲棍球的冰场划分为更容易处理的部分。

Then you label each segment with bwlabel. For each object, find the endpoints and fit a line between the endpoints. If the line and the object have more pixels in common than a certain threshold, then we say that the object is a line and we delete it from the image.

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

You may have to play around with the Hough transform's threshold value.

您可能需要使用Hough转换的阈值。

This technique has some flaws though. It will delete a filled square, rectangle or circle but you haven't got any of those so you should be ok.

不过,这种技术也有一些缺点。它会删除一个填充的正方形,矩形或圆形,但是你没有这些,所以你应该可以。

Results

Hough变换用于检测和删除线。Hough变换用于检测和删除线。


Explanation

This is your code that I modified a bit. I removed the gradient because it it easier to work with solid objects. The gradient gave very thin lines. I also work on the complement image because the bw functions work with 1 as forgound rather than 0 as in your original image.

这是我修改过的代码。我去掉了梯度,因为它更容易处理固体物体。渐变的线条很细。我也在补体图像上工作,因为bw函数的作用是1作为forgound而不是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);

Loop through the lines you have got and delete them

循环遍历您已经拥有并删除它们的行。

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

This is what the image looks after we have deleted the detected lines. Please note that the original hockey rink and been divided into multiple objects.

这是我们删除了检测到的线后图像的样子。请注意原来的曲棍球溜冰场并被分成多个物体。

Hough变换用于检测和删除线。

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.

遍历每个对象并找到端点。然后把线贴到上面。假设有80%的拟合线覆盖了物体,那么它就是一条直线。

A fitted line could look like this. The diagonal blue line represents the fitted line and covers most of the object (the white area). We therefore say that the object is a line.

一条合适的线看起来像这样。对角蓝线表示拟合线,并覆盖大部分物体(白色区域)。因此,我们说对象是一条直线。

Hough变换用于检测和删除线。

% // 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');

Complete example

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

#2


2  

You could use J. E. Bresenham's algorightm. It is implemented by A. Wetzler in the following matlab function, which I tested myself.

你可以使用J. E. Bresenham的algorightm。它由A. Wetzler在下面的matlab函数中实现,我自己测试过。

The algorithm will give you the pixel coordinates of where the line would be, given that you will provide the start and end point of the line, which is already given in lines in your code above.

该算法将给出直线的像素坐标,因为你将提供线的起始点和结束点,这已经在上面的代码行中给出了。

Here is the code I used, which uses the matlab function referenced above:

下面是我使用的代码,它使用了上面提到的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

Remember, download the matlab function first.

记住,首先下载matlab函数。

#1


2  

The issue you have is that your lines are thicker than one pixel. The lines from the hough transform seem to be one pixel thick and that doesn't help.

你的问题是你的线比一个像素要厚。来自霍夫变换的线条似乎只有一个像素的厚度,这并没有帮助。

I propose that you delete the lines that you get from the Hough transform first. This will sort of divide the hockey rink of whatever it is into segments that will be easier to process.

我建议您先删除从霍夫转换中得到的行。这将会将曲棍球的冰场划分为更容易处理的部分。

Then you label each segment with bwlabel. For each object, find the endpoints and fit a line between the endpoints. If the line and the object have more pixels in common than a certain threshold, then we say that the object is a line and we delete it from the image.

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

You may have to play around with the Hough transform's threshold value.

您可能需要使用Hough转换的阈值。

This technique has some flaws though. It will delete a filled square, rectangle or circle but you haven't got any of those so you should be ok.

不过,这种技术也有一些缺点。它会删除一个填充的正方形,矩形或圆形,但是你没有这些,所以你应该可以。

Results

Hough变换用于检测和删除线。Hough变换用于检测和删除线。


Explanation

This is your code that I modified a bit. I removed the gradient because it it easier to work with solid objects. The gradient gave very thin lines. I also work on the complement image because the bw functions work with 1 as forgound rather than 0 as in your original image.

这是我修改过的代码。我去掉了梯度,因为它更容易处理固体物体。渐变的线条很细。我也在补体图像上工作,因为bw函数的作用是1作为forgound而不是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);

Loop through the lines you have got and delete them

循环遍历您已经拥有并删除它们的行。

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

This is what the image looks after we have deleted the detected lines. Please note that the original hockey rink and been divided into multiple objects.

这是我们删除了检测到的线后图像的样子。请注意原来的曲棍球溜冰场并被分成多个物体。

Hough变换用于检测和删除线。

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.

遍历每个对象并找到端点。然后把线贴到上面。假设有80%的拟合线覆盖了物体,那么它就是一条直线。

A fitted line could look like this. The diagonal blue line represents the fitted line and covers most of the object (the white area). We therefore say that the object is a line.

一条合适的线看起来像这样。对角蓝线表示拟合线,并覆盖大部分物体(白色区域)。因此,我们说对象是一条直线。

Hough变换用于检测和删除线。

% // 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');

Complete example

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

#2


2  

You could use J. E. Bresenham's algorightm. It is implemented by A. Wetzler in the following matlab function, which I tested myself.

你可以使用J. E. Bresenham的algorightm。它由A. Wetzler在下面的matlab函数中实现,我自己测试过。

The algorithm will give you the pixel coordinates of where the line would be, given that you will provide the start and end point of the line, which is already given in lines in your code above.

该算法将给出直线的像素坐标,因为你将提供线的起始点和结束点,这已经在上面的代码行中给出了。

Here is the code I used, which uses the matlab function referenced above:

下面是我使用的代码,它使用了上面提到的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

Remember, download the matlab function first.

记住,首先下载matlab函数。