1. 程式人生 > >8.霍夫變換:線條——動手編碼、霍夫演示_4

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變換函式,調整到最好的結果。


——學會編寫自己的程式碼,才能練出真功夫。