霍夫變換與直線檢測hough

導讀:
1. houghlines的算法思想
2. houghlines實現需要考慮的要素
3. houghlines的opencv實現,代碼分析
4. houghlines的效率分析,改進

  1. houghlines的算法思想
    檢測直線,houghlines標準算法,不考慮線段,不檢測線段端點。

在直角座標系和極座標系的對應關係,點、直線在兩個座標系中是對偶關係。
即直角座標系中的點是極座標系中的線,直角座標系中的線是極座標系中的點。
反過來,也成立。

圖像可知看做直角座標系,檢測圖像中的直線,可以轉化爲統計檢測極座標系中的點(r,theta)。

  1. houghlines實現需要考慮的因素
    hough空間(離散極座標)的表示
    原因:
    圖像中直線的表示,由斜率和截距表示,而極座標中用(r, theta)表示.
    r = cos(theta)*x + sin(theta)*y

對於點(x0, y0) , 在極座標中就是一條直線(很多對(r,theta)點):
r = cos(theta)*x0 + sin(theta)*y0

r,theta就是一對hough空間的變量表示。
旋轉的theta不容易表示,若將r,theta看成直角座標空間。
一個點(x0, y0), 就是一個正弦曲線。
r = cos(theta)*x0 + sin(theta)*y0

直角座標系中的一點

對應於r-theta空間的一條正弦曲線

多個點在(r,theta)平面上就是多條正弦曲線,而多條正弦曲線會相交,交點就是直角座標系中的直線。

直角座標系中的一條直線上的三個點

對應於r-theta空間中三條曲線,並交於一點

接下來,就是要考慮 將r,theta離散化,形成離散化的hough空間,類似於一個mat矩陣/圖像,用於統計交點的個數。

opencv取rtho,theta參數作爲離散度量,空間分辨率。
則hough空間的大小爲:
numangle = cvRound(CV_PI / theta);
numrho = cvRound(((width + height) * 2 + 1) / rho); // 有冗餘,在r上留有一定的空白

  1. 代碼分析

rho: 霍夫空間的r粒度大小
theta: 旋轉角度的粒度
threshold:直線上有多少個點的閾值
lines:輸出lines結果
linesMax:lines的最大個數
[html] view plain copy
static void
icvHoughLinesStandard( const CvMat* img, float rho, float theta,
int threshold, CvSeq *lines, int linesMax )
{
cv::AutoBuffer _accum, _sort_buf;
cv::AutoBuffer _tabSin, _tabCos;

const uchar* image;    
int step, width, height;    
int numangle, numrho;    
int total = 0;    
float ang;    
int r, n;    
int i, j;    
float irho = 1 / rho;    
double scale;    

CV_Assert( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );    

image = img->data.ptr;    
step = img->step;    
width = img->cols;    
height = img->rows;    

numangle = cvRound(CV_PI / theta);    // 霍夫空間,角度方向的大小    
numrho = cvRound(((width + height) * 2 + 1) / rho);  // r的空間範圍    

_accum.allocate((numangle+2) * (numrho+2));    
_sort_buf.allocate(numangle * numrho);    
_tabSin.allocate(numangle);    
_tabCos.allocate(numangle);    
int *accum = _accum, *sort_buf = _sort_buf;    
float *tabSin = _tabSin, *tabCos = _tabCos;    

memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );    

for( ang = 0, n = 0; n < numangle; ang += theta, n++ ) // 計算正弦曲線的準備工作,查表    
{    
    tabSin[n] = (float)(sin(ang) * irho);    
    tabCos[n] = (float)(cos(ang) * irho);    
}    

// stage 1. fill accumulator    
for( i = 0; i < height; i++ )    
    for( j = 0; j < width; j++ )    
    {    
        if( image[i * step + j] != 0 )      // 將每個非零點,轉換爲霍夫空間的離散正弦曲線,並統計。    
            for( n = 0; n < numangle; n++ )    
            {    
                r = cvRound( j * tabCos[n] + i * tabSin[n] );    
                r += (numrho - 1) / 2;    
                accum[(n+1) * (numrho+2) + r+1]++;    
            }    
    }    

// stage 2. find local maximums  // 霍夫空間,局部最大點,採用四鄰域判斷,比較。(也可以使8鄰域或者更大的方式), 如果不判斷局部最大值,同時選用次大值與最大值,就可能會是兩個相鄰的直線,但實際上是一條直線。選用最大值,也是去除離散的近似計算帶來的誤差,或合併近似曲線。    
for( r = 0; r < numrho; r++ )       
    for( n = 0; n < numangle; n++ )    
    {    
        int base = (n+1) * (numrho+2) + r+1;    
        if( accum[base] > threshold &&    
            accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&    
            accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )    
            sort_buf[total++] = base;    
    }    

// stage 3. sort the detected lines by accumulator value    // 由點的個數排序,依次找出哪些最有可能是直線    
icvHoughSortDescent32s( sort_buf, total, accum );    

// stage 4. store the first min(total,linesMax) lines to the output buffer    
linesMax = MIN(linesMax, total);    
scale = 1./(numrho+2);    
for( i = 0; i < linesMax; i++ )  // 依據霍夫空間分辨率,計算直線的實際r,theta參數    
{    
    CvLinePolar line;    
    int idx = sort_buf[i];    
    int n = cvFloor(idx*scale) - 1;    
    int r = idx - (n+1)*(numrho+2) - 1;    
    line.rho = (r - (numrho - 1)*0.5f) * rho;    
    line.angle = n * theta;    
    cvSeqPush( lines, &line );    
}    

}

  1. 效率分析
    houghlines的計算效率比較低O(n*n*m),耗時較長,而且沒有檢測出直線的端點。
    改進
    統計概論霍夫直線檢測houghlinesP是一個改進,不僅執行效率較高,而且能檢測到直線的兩個端點。
    思想:
    先隨機檢測出一部分直線,然後將直線上點的排查掉,再進行其他直線的檢測

  2. 首先僅統計圖像中非零點的個數,對於已經確認是某條直線上的點就不再變換了。

  3. 對所以有非零點逐個變換到霍夫空間
    a. 並累加到霍夫統計表(圖像)中,並統計最大值
    b. 最大值與閾值比較,小於閾值,則繼續下一個點的變換
    c. 若大於閾值,則有一個新的直線段要產生了
    d. 計算直線上線段的端點、長度,如果符合條件,則保存此線段,並mark這個線段上的點不參與其他線段檢測的變換
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章