Harris角點檢測及程式碼分析(續)
阿新 • • 發佈:2019-02-14
緊接著“Harris角點檢測及程式碼分析”,這裡主要分析OpenCV的cvGoodFeaturesToTrack()函式,這才是角點提取的真正程式碼。
Jianbo Shi, Carlo Tomasi. Good Features to Track. CVPR94
時間:2015-05-25 16:12
演算法步驟
- cvCornerHarris()函式僅計算出每個畫素單元的
R 值,然後再對R 進行過濾,僅留下≥β×maxR 的畫素點; - 非極大值抑制(Non-Maximum Suppression),我看到網上很多人直接Dilate-Image && Origin-Image,但這樣會形成角點塊,除非有下面的步驟;
- 對該階段的角點
R 值進行降序排序; - 距離濾波器,過濾點靠太近的點,留下
R 值高的角點。
程式碼分析
便於理解先看OpenCV1.0的cvGoodFeaturesToTrack()原始碼,已刪除了與理解演算法無關的程式碼。
void cvGoodFeaturesToTrack(...)
{
// 是否使用harris角點響應器
if(use_harris)
{
// harris角點響應值,det(M)-a*(trace(M))^2
cvCornerHarris(img, eig, block_size, 3, harris_k);
}
else
{
// 用最小特徵值作為響應值
cvCornerMinEigenVal(img, eig, block_size, 3);
}
cvMinMaxLoc(eig, 0, &max_val, 0, 0, mask);
cvThreshold(eig, eig, max_val * 0.01, 0, CV_THRESH_TOZERO);
cvDilate(eig, tmp);
min_dist = cvRound(min_distance * min_distance);
// 檢查原響應圖與dilate圖的每個畫素,如果不為0且相等,則為候選角點
for(y = 1, k = 0; y < size.height - 1; y++)
{
for(x = 1; x < size.width - 1; x++)
{
if(eig_data[x] != 0 && eig_data[x] == tmp_data[x])
ptr_data[k++] = eig_data + x;
}
}
// 對候選角點按響應值降序排序
icvSortFeatures( ptr_data, k, 0 );
// 遍歷所有候選角點,如果當前角點與前面所有角點的歐式距離小於min_dist,
// 則標記為真正角點
for(i = 0; i < k; i++)
{
for(j = 0; j < count; j++)
{
int dx = x - ptr[j].x;
int dy = y - ptr[j].y;
int dist = dx * dx + dy * dy;
if(dist < min_dist)
break;
}
if(j == count)
{
ptr[count].x = x;
ptr[count].y = y;
if(++count >= max_count)
break;
}
}
}
演算法優化
OpenCV2.0以上版本在goodFeaturesToTrack()函式中對距離濾波器做了修改,應該是為了加速做的改進。具體方法為:
- 對整張影象劃分網格,每個網格的大小為min_dist * min_dst,網格數量為grid_width * grid_height;
- 建立二維矩陣,grid(grid_width * grid_height),用來存放最終標記的角點;
- 進行距離濾波時,計算出候選角點所在網格,僅需檢測網格8領域的角點與候選角點的距離,就能快速verify。
為了保證能計算出比較多的角點,一般min_dist設定得比較小,如果10,針對一張640 * 480的影象檢測角點,應該能有不錯的效能提升。