【數字圖像處理】霍夫變換實現


 

理論部分來源:霍夫變換

作者:https://home.cnblogs.com/u/php-rearch/

一、霍夫變換(Hough)

  A-基本原理

一條直線可由兩個點A=(X1,Y1)和B=(X2,Y2)確定(笛卡爾坐標)

另一方面,也可以寫成關於(k,q)的函數表達式(霍夫空間):

對應的變換可以通過圖形直觀表示:

變換后的空間成為霍夫空間。即:笛卡爾坐標系中一條直線,對應霍夫空間的一個點

反過來同樣成立(霍夫空間的一條直線,對應笛卡爾坐標系的一個點):

再來看看A、B兩個點,對應霍夫空間的情形:

一步步來,再看一下三個點共線的情況:

可以看出如果笛卡爾坐標系的點共線,這些點在霍夫空間對應的直線交於一點:這也是必然,共線只有一種取值可能。

如果不止一條直線呢?再看看多個點的情況(有兩條直線):

其實(3,2)與(4,1)也可以組成直線,只不過它有兩個點確定,而圖中A、B兩點是由三條直線匯成,這也是霍夫變換的后處理的基本方式選擇由盡可能多直線匯成的點

看看,霍夫空間:選擇由三條交匯直線確定的點(中間圖),對應的笛卡爾坐標系的直線(右圖)。

 到這里問題似乎解決了,已經完成了霍夫變換的求解,但是如果像下圖這種情況呢?

k=∞是不方便表示的,而且q怎么取值呢,這樣不是辦法。因此考慮將笛卡爾坐標系換為:極坐標表示

在極坐標系下,其實是一樣的:極坐標的點→霍夫空間的直線,只不過霍夫空間不再是[k,q]的參數,而是的參數,給出對比圖:

是不是就一目了然了?

給出霍夫變換的算法步驟:

 

 

二、霍夫變換的實現

霍夫變換:在霍夫空間中,一個r和theta可以確定一條直線。

本質上在由r與theta組成的二維空間進行投票。

r:r的最大值取圖像對角線長度。

theta:0-360度,可分也可不分。

#define PI 3.14159265 
#define r      200    //120^2+160^2 = 40000  //斜邊長度
#define count 90      //360度分成90份
#define Use_ROWS 120  //圖像高度
#define Use_Line 160  //圖像寬度 

 
//數據初始化
int jiaodu=0;
float Cos[count]={0},Sin[count]={0};
for(int theta = 0,int i=0;theta<=360;i++)
    {
        Cos[i]=cos(theta*PI/180);
        Sin[i]=sin(theta*PI/180);        
        theta+=4;
    }

//二維投票箱
int res[count][r]={0};

/////////////////////////////////////////////////////////////////////// memset(Image,
255, sizeof(Image)); memset(res, 0, sizeof(res)); //二值化 int Threshold,i,j; Threshold = GetOSTU(Image_Use); for(i = 0; i < Use_ROWS; i++) { for(j =0; j < Use_Line; j++) { if(Image_Use[i][j] >= Threshold) Image_Use[i][j]=255;//白為背景 else Image_Use[i][j]=0; //黑為物體 } } //雙向梯度 for(int i = 1; i < Use_ROWS- 1; i++) { for(int j = 1; j < Use_Line -1; j++) { Image_Use[i][j] = sqrt((Image_Use[i][j+1] - Image_Use[i][j])*(Image_Use[i][j+1] - Image_Use[i][j])+(Image_Use[i+1][j] - Image_Use[i][j])*(Image_Use[i+1][j] - Image_Use[i][j])); } } // 直線檢測 for(int i = 0; i<Use_ROWS;i++) for(int j=0; j<Use_Line;j++) if(Image_Use[i][j]==255)//當該像素點為邊緣點時 { for(int theta = 0;theta<=360;) { jiaodu = theta/4;//這里設置360度,分成多少份 int resu = (int)(i*Cos[jiaodu]+j*Sin[jiaodu]); res[jiaodu][resu] +=1; theta+=4; } } ////////////////////////////////// //找出次數最多的結果 int result = res[0][0]; for(int i=0;i<count;i++) for(int j=0;j<r;j++) { if(result<res[i][j]) result = res[i][j]; } //直線提取 int td =(int)(result * 0.8); int s1[30] = {0},s2[30]={0},d=0; for(int i=0;i<count;i++) { for(int j=0;j<r;j++) { if(res[i][j]>td) { s1[d] = i; //角度 s2[d] = j; //距離 d++; } } } d--; for(int i = 0; i < Use_ROWS; i++) { for(int s = 0 ;s<d;d++) { j = (int)((-1.0/tan[s1[s]])*i+(s2[s])/Sin[s1[s]])); Image[i][j] = 0; } }
///////////////////////////////////////////////////////


免責聲明!

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



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