8.霍夫变换:线条——动手编码、霍夫演示_4

目录

动手编码

霍夫演示


动手编码

我们将在这里花一分钟来演示一下,如何使用Matlab构建霍夫变换。

我再重复一遍,在你们的习题集上,你们要做一些Hough代码。

你不能使用已经存在的Hough实现,也不能使用其他任何人的Hough实现。

因为事实证明,当你去写你的Hough实现的时候某些东西会失效。

在这种经历中,你会了解到它的重要元素是什么。

赶快自己编写一个吧。

代码如下: 

>>
function [ Hough, theta_range, rho_range ] = naiveHough(I)
% NAIVEHOUGH Peforms the Hough transform in a straightforward way.
[rows, cols] = size(I);

theta_maximum = 180;
rho_maximum = floor(sqrt(rows^2 + cols^2)) - 1;
theta_range = -theta_maximum:theta_maximum - 1;
rho_range = -rho_maximum:rho_maximum;

Hough = zeros(length(rho_range), length(theta_range));
for row = 1:rows
    for col = 1:cols
        if I(row, col) > 0 %only find: pixel > 0
            x = col - 1;
            y = row - 1;
            for theta = theta_range
                rho = round((x * cosd(theta)) + (y * sind(theta)));  %approximate
                rho_index = rho + rho_maximum + 1;
                theta_index = theta + theta_maximum + 1;
                Hough(rho_index, theta_index) = Hough(rho_index, theta_index) + 1;
             end
        end
    end
end

 

霍夫演示

为了检测图像中的线条,我们首先需要找到边缘像素。

让我们加载一个图像,把它转换成灰度,然后使用Canny运算找到边缘像素。

>> %% Load image, convert to grayscale and apply Canny operator to find edge pixels
>> img = imread('shapes.png');
>> grays = rgb2gray(img);
>> edge = edge(grays, 'canny');
>>
>> figure , imshow(img), title('original image');
>> figure , imshow(grays), title('Grayscale');
>> figure , imshow(edge), title('Edge pixels');

让我们看看这些是什么样子。

这是原始图像:

如你所见,它有一些线条。

灰度版本:

边缘像素:

现在我们将使用霍夫变换方法来找到直线。为此,我们将使用Matlab中的霍夫函数。

>> %% Apply Hough transform to find candidate lines
>> [accum theta rho] = hough(edges); % Matlab

Matlab文档中可以找到关于这个函数的更多信息:

Octave中的houghtf函数也是同等作用:

第一个返回的值是累加器数组。(一般我们命名为:accum)

第二个是值或角度的向量。(一般我们命名为:theta)

第三个是半径的向量。(一般我们命名为:rho)

我们看看这是什么样子。

>> figure, imagesc(accum, 'XDdata', theta, 'YDdata', rho), title('Hough accumulator');

我们通过 theta 和 rho 值来正确标记每个轴,rho或从原点的距离是沿着Y轴:

角度\theta在x轴上,从 -90° 到 +90°:

好了,我们来找出这个累加器数组中的最大值,我们通过100作为我们感兴趣的最大值:

>> %% Find peaks in the Hough accumulator matrix
>> peaks = houghpeaks(accum, 100); % Matlab

注意,在Octave中需要使用immaximize函数。

让我们在霍夫累加器数组上,画出这些最大值:

>> hold on; plot(theta(peaks(:, 2)), rho(peaks(: ,1)), 'rs'); hold off;

请注意,我们需要使用 \theta 和 ρ 值来正确地绘制最大值:

最大值由红色小框标记。最大值向量的大小是13 * 2:

>> size(peaks);

运行结果:13        2

发现了13个最大值,每行包含一个最大值的位置。

第一列具有行值或 y 值,第二列具有 x 值。

使用这些最大值,我们可以找到线段,在Matlab中使用Hough线函数:

>> %% Find lines (segments) in the image.
>> line_segs = houghlines(edges, theta, rho, peaks); % Matlab
>> lin_segs;

代码运行,结果如下:

看起来发现了28条线段。

LangySeg中的每个元素是一个结构,其中两个端点 \theta 和 ρ 值。让我们画出这些线段:

>>
figure, imshow(img), title('Line segments');
hold on;
for k = 1:length(line_segs)
    endpoints = [line_segs(k).point; line_segs(k).point2];
    plot(endpoints(:, 1), endpoints(:, 2), 'LineWidth', 2, 'Color', 'green');
end
hold off;

代码运行结果:

正如你所看到的,大多数较长的线段已经被检测到,但是很多杂散的线段也出现了。

那么,我们如何才能得到更好的结果呢?

让我们再看一下边缘像素:

我们注意到,在一些区域,在较长的线路上有中断:

还有一组密集的曲线可能会让霍夫探测器偏离轨道:

为了找到一组更清晰或更有意义的线条,我们可以做很多事情。

例如,我们可以增加霍夫最大值的阈值参数:

>> %% Alt.:More precise lines
>> peaks = houghpeaks(accum, 100, 'Threshold', cell(0.6*max(accum(:))), 'NHoodSize', [5,5]);
>> size(peaks);

为了理解这些参数的含义,让我们看一下这个函数的文档。

因此,阙值是累加器数组中的最小值,即支持一行的最小像素数,该行需要作为有效候选。

不考虑具有较少像素的任何可能的线。

这里我们将其设置为0.6乘以累加器数组中的最大值,默认值为0.5乘以最大值。

邻域大小定义了计算局部最大值的区域。('NHoodSize', [5,5])

注意,这不是图像中的区域。

我们在累加器阵列中计算局部最大值,因此在Rho和θ维中定义邻域的大小。

如果邻域大小为5度,则表示一条较强的线将会抑制其他相似但方向稍微偏离的线。

回想一下,我们在最后一次尝试中发现了13个最大值。

这次我们只有7个最大值。代码结果如下:

让我们看看这些峰值在哪里。

>> figure, imagesc(theta, rho, accum), title('Hough accumulator');
>> hold on; plot(theta(peaks(:,2)), rho(peaks(:, 1)), 'rs'); hold off;

代码运行结果:

看起来我们可能会有更干净的结果。

让我们将它与之前的累加器峰值进行比较:

我们看到以前在这一密集区域发现的许多最大值现在都消失了。

新的最大值聚集在三个主要的位置。

Okay,我们还能做什么?

>> line_segs = houghlines(edges, theta, rho, peaks, 'FillGap', 50, 'MinLength', 100);

我们可以利用houghlines的参数。

我们把填充间隙参数增加到50('FillGap', 50),看看怎么样?

这是两个段之间允许的最大像素数,如果它们位于同一条线上,则计为一个像素。

为了关注更长的线条,我们将最小长度增加到100像素。('MinLength', 100)

要更好地理解这些参数,请参阅houghlines的文档。

好,让我们看看新的片段是什么样的:

>> 
figure, imshow(img), title('Line segments');
hold on;
for k = 1:length(line_segs)
    endpoints = [line_segs(k).point1; line_segs(k).point2];
    plot(endpoints(:, 1), endpoints(:, 2), 'LineWidth', 2, 'Color', 'green');
end
hold off;

代码运行,结果:

与之前的结果相比,我们发现杂散的已经基本被排除。(一些先前破碎的部分也被连接在一起。)

显然,你可以更好地处理参数,特别是在这里:

大家可以随意使用huff变换函数,调整到最好的结果。


——学会编写自己的代码,才能练出真功夫。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值