Hough變換


 Hough變換可以檢測出直線與圓。

 原理介紹:

       假設直線l的斜截式方程為y=kx+b.(x,y)為圖像中的像素值,如果直線上的所有點對(x,y)都滿足這個式子,即他們有相同的參數(b,k),所以他們在同一條直線上,所以思路很清晰:例如某10個點在同一條直線上,那么這10個點共享一個參數集(b1,k1),又有另外幾個點構成了另一條直線,那么這幾個點又共享另一組參數(b2,k2)。所以說有多少個這樣的參數集,就有多少條直線!
       Hough這樣理解:將斜截式改為:b=-xk+y。將(x,y)空間轉為(b,k)空間坐標系下,將k軸等分i份,將b軸等分j份,那么可以將每一個單元稱為一個累加器單元,其值用A(i,j)表示,初值為零。

                                        

          對於圖像中每個點(x,y),令參數k依次取值為k軸上的每個細分值,將其帶入b=-xk+y,得到b,通過對b近似將其划分至距離累加器中最近的單元格b中。每得到一對(k,b),將其相應的累加器單元的值進行累加,即A(p,q)=A(p,q)+1.那么很好理解:A的非零值個數為直線個數,A(i,j)得值即為直線上的點個數。

           因為當直線垂直時,斜率無窮大,所以采用直線的標准表達式:ρ=xcosθ+ysinθ.基本沒什么變化,就是將(k,b)變為(ρ,θ).θ一般取值為[-90,90],或[0,180]度。ρ取值為[-D,D],D為圖像對角線長度。

                                     

 代碼:      

function Hough_LineDetect(filename,degree_range,line_length,dtheta,drho)
%Hough變換檢測直線
%參數:filename:被檢測圖像文件名
%     degree_range:檢測直線的角度范圍,1*2矩陣:默認值為[-90 90]
%     line_length:檢測直線的最小長度;默認值為100
%     dtheta:theta的步長;默認值為1(角度)
%     drho:rho的步長;默認值為1(像素)
%功能:從被檢測圖像中檢測出滿足指定角度和長度的直線。
if nargin < 5
    drho=1;
end
if nargin<4
    dtheta=1;
end
if nargin<3
    line_length=100;
end
if nargin<2
    degree_range=[-90 90]
end

I=imread(filename);
[width,height]=size(I);   %圖像尺寸
BI=edge(I);   %邊緣提取

dtheta=dtheta*pi/180;
radian_upper=max(degree_range*pi/180);
radian_lower=min(degree_range*pi/180);
radian_range=radian_upper-radian_lower;

rho_max=(sqrt(width^2+height^2));
nrho=ceil(2*rho_max/drho);
theta_value=[radian_lower:dtheta:radian_upper];    %theta值
ntheta=length(theta_value);

rho_matrix=zeros(nrho,ntheta);     %對於某一rho和theta值,點的個數
hough_line=zeros(width,height);

%Hough 變換
%將圖像空間(x,y)變換到參數空間(rho,theta):rho=xcos(theta)+ysin(theta)
[rows,cols]=find(BI);    
pointcount=length(rows);       %邊緣點數個數
rho_value=zeros(pointcount,ntheta);   %rho取值,對於每個點對應一個theta
for i=1:pointcount
    m=rows(i);
    n=cols(i);
    for k=1:ntheta
        rho=(m*cos(theta_value(k)))+(n*sin(theta_value(k)));  %根據x,y,theta求rho
        rho_index = round((rho+rho_max)/drho);  %求索引
        rho_matrix(rho_index,k)=rho_matrix(rho_index,k)+1;
        rho_value(rho_index,k)=rho;  
    end
end

%搜索同一直線上的點
index=find(rho_matrix>line_length);  %求滿足條件的索引值
for k=1:length(index)
    [rho_th,theta_th]=ind2sub(size(rho_matrix),index(k)); %根據索引求參數值
    theta=theta_value(theta_th);
    rho=rho_value(rho_th,theta_th);
    for i=1:pointcount
        x=rows(i);
        y=cols(i);
        rate=(x*cos(theta)+y*sin(theta))/rho;   %求rate來設定條件
        if (rate>1-10^-3 & rate<1+10^-3)   %滿足條件
            hough_line(x,y)=1;  %將滿足條件即直線的點塗黑
        end
    end
end

figure;imshow(I);title('原始圖像');
figure;imshow(BI);title('邊緣檢測后的圖像');
figure;imshow(hough_line);title('hough變換檢測到的直線');

                   

     檢測圓:原理類似,和(ρ,θ)來表示一條直線相似,使用(a,b,r)來確定一個圓心為(a,b)半徑為 r  的圓。

                 某個圓過點(x1,y1),則有:(x1-a1)^2 + (y1-b1)^2 = r1^2 。所以在圓(a1,b1,r1)上的點共用這一套參數集。參數集的個數代表圓的個數,共用某一參數集的點數目即為此圓上的點數。

    代碼:

function hough_CircleDetect(filename,radius_range,step_angle,step_radius)
%Hough變換檢測圓
%參數:filename:被檢測圖像文件名
%     radius_range:檢測圓的半徑范圍,1*2矩陣,默認值為[10 100]
%     step_angle:角度步長;默認值為5(角度)
%     step_radius:半徑步長;默認值為1(像素)
%功能:從被檢測圖像中檢測出滿足指定半徑的圓。
if nargin<4
    step_radius=1;
end
if nargin<3
    step_angle=5;
end
if nargin<2
    radius_range=[10 100];
end
radius_min=min(radius_range);
radius_max=max(radius_range);
step_angle=step_angle*pi/180;

I=imread(filename);
[m,n,l]=size(I);
if l>1
    I=rgb2gray(I);
end
BI=edge(I);
[rows,cols]=find(BI);
PointCount=size(rows);

RadiusCount=ceil((radius_max-radius_min)/step_radius);
AngleCount=ceil(2*pi/step_angle);
hough_space=zeros(m,n,RadiusCount);

%Hought變換
%將圖像空間(x,y)變換到參數空間(a,b,r)
%a=x-r*cos(theta);
%b=y-r*sin(theta);
for i=1:PointCount
    for r=1:RadiusCount
        for k=1:AngleCount
            a=round(rows(i)-(radius_min+(r-1)*step_radius)*cos(k*step_angle));
            b=round(cols(i)-(radius_min+(r-1)*step_radius)*sin(k*step_angle));
            if(a>0 & a<=m & b>0 &b<=n)
                hough_space(a,b,r)=hough_space(a,b,r)+1;
            end
        end
    end
end

%搜索同一圓上的點
thresh = 0.7;
max_PointCount=max(max(max(hough_space)));
index=find(hough_space>=max_PointCount*thresh);
length=size(index);
hough_circle=zeros(m,n);
size_hough_space = size(hough_space);
for i=1:PointCount
    for k=1:length
        [a,b,r]=ind2sub(size_hough_space,index(k));
        rate=((rows(i)-a)^2+(cols(i)-b)^2)/(radius_min+(r-1)*step_radius)^2;
        if(rate<1.1)
            hough_circle(rows(i),cols(i))=1;
        end
    end
end

figure;imshow(I);title('原始圖像');
figure;imshow(BI);title('邊緣檢測后的圖像');
figure;imshow(hough_circle);title('hough變換檢測到的圓');

%hough_CircleDetect('line_circle.bmp')
%hough_CircleDetect('line_circle.bmp',[5,20])
%hough_CircleDetect('line_circle.bmp',[5,100])
%hough_CircleDetect('line_circle.bmp',[5,200])

              

 

其他參考資料:

http://cn.mathworks.com/help/images/ref/imfindcircles.html

http://cn.mathworks.com/matlabcentral/fileexchange/26978-hough-transform-for-circles?focused=6019424&tab=example

https://stackoverflow.com/questions/27171527/circle-detection-from-gray-level-image-in-matlab


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM