生活随笔
收集整理的這篇文章主要介紹了
Harris及Shi-Tomasi原理及源码解析
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
本文采用的是opencv2.4.3中的源碼。
轉(zhuǎn)載請注明出處:http://blog.csdn.net/luoshixian099/article/details/48244255
CSDN-勿在浮沙筑高臺
Harris角點檢測
? ?人眼對角點的識別通常是通過一個局部的小窗口內(nèi)完成的,如果在各個方向上移動這個小窗口,窗口內(nèi)的灰度發(fā)生了較大的變化,那么說明窗口內(nèi)存在角點。
? 如果在各個方向移動,灰度幾乎不變,說明是平坦區(qū)域;
? 如果只沿著某一個方向移動,灰度幾乎不變,說明是直線;
? 如果沿各個方向移動,灰度均發(fā)生變化,說明是角點。
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??平坦區(qū)域 ??? ? ? ? ? ? ? ? ? ? ? ? ? ?直線??? ? ? ? ? ? ? ? ? ? ? ? ? ? ?角點 ? ? ? ? ? ? ?
圖像I(x,y),在點(x,y)處平移(u,v)后的自相似性,可以用灰度變化函數(shù)E(u,v)表示
??
? ? ? ? ? ? ? ? ??
泰勒展開:
代入得到:
? ? ? ? ? ? ? ? ? ? ? ??
其中:
? ? ? ? ? ? ? ? ? ? ? ? ?
二次項函數(shù)本質(zhì)上就是一個橢圓函數(shù),橢圓的扁平率和尺寸是由矩陣M的兩個特征值決定的。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
矩陣M的兩個特征值與圖像中的角點,邊緣,平坦區(qū)域的關(guān)系:
Harris定義角點響應(yīng)函數(shù)即,即R=Det(M)-k*trace(M)*trace(M),k為經(jīng)驗常數(shù)0.04~0.06 。
定義當R>threshold時且為局部極大值的點時,定義為角點。
Harris角點檢測算子對圖像亮度和對比度具有部分不變性,且具有旋轉(zhuǎn)不變性,但不具有尺度不變性。
? ? ? ? ? ? ? ? ? ? ? ? ? ?
opencv中調(diào)用cornerHarris函數(shù)檢測角點:
blockSize:為鄰域大小,對每個像素,考慮blockSize×blockSize大小的鄰域S(p),在鄰域上計算圖像的差分的相關(guān)矩陣;
ksize: 為Soble算子核尺寸,如果小于0,采用3×3的Scharr濾波器;
k:為角點響應(yīng)函數(shù)中的經(jīng)驗常數(shù)(0.04~0.06);
[cpp]?view plaincopy print?
int?blockSize?=?2;?? int?apertureSize?=3;?? double?k?=?0.04;?? ?? cornerHarris(?src_gray,?dst,?blockSize,?apertureSize,?k,?BORDER_DEFAULT?);???
[cpp]?view plaincopy print?
void?cv::cornerHarris(?InputArray?_src,?OutputArray?_dst,?int?blockSize,?int?ksize,?double?k,?int?borderType?)?? {?? ????Mat?src?=?_src.getMat();?? ????_dst.create(?src.size(),?CV_32F?);?? ????Mat?dst?=?_dst.getMat();?? ????cornerEigenValsVecs(?src,?dst,?blockSize,?ksize,?HARRIS,?k,?borderType?);?? }??
[cpp]?view plaincopy print?
static?void?? cornerEigenValsVecs(?const?Mat&?src,?Mat&?eigenv,?int?block_size,?? ?????????????????????int?aperture_size,?int?op_type,?double?k=0.,?? ?????????????????????int?borderType=BORDER_DEFAULT?)?? {?? #ifdef?HAVE_TEGRA_OPTIMIZATION?? ????if?(tegra::cornerEigenValsVecs(src,?eigenv,?block_size,?aperture_size,?op_type,?k,?borderType))?? ????????return;?? #endif?? ?? ?? ????int?depth?=?src.depth();?? ????double?scale?=?(double)(1?<<?((aperture_size?>?0???aperture_size?:?3)?-?1))?*?block_size;?? ????if(?aperture_size?<?0?)?? ????????scale?*=?2.;?? ????if(?depth?==?CV_8U?)?? ????????scale?*=?255.;?? ????scale?=?1./scale;?? ????CV_Assert(?src.type()?==?CV_8UC1?||?src.type()?==?CV_32FC1?);?? ?? ?? ????Mat?Dx,?Dy;????? ????if(?aperture_size?>?0?)?? ????{?? ????????Sobel(?src,?Dx,?CV_32F,?1,?0,?aperture_size,?scale,?0,?borderType?);?? ????????Sobel(?src,?Dy,?CV_32F,?0,?1,?aperture_size,?scale,?0,?borderType?);?? ????}?? ????else?????? ????{?? ????????Scharr(?src,?Dx,?CV_32F,?1,?0,?scale,?0,?borderType?);?? ????????Scharr(?src,?Dy,?CV_32F,?0,?1,?scale,?0,?borderType?);?? ????}?? ?? ?? ????Size?size?=?src.size();?? ????Mat?cov(?size,?CV_32FC3?);?? ????int?i,?j;?? ?? ?? ????for(?i?=?0;?i?<?size.height;?i++?)?? ????{?? ????????float*?cov_data?=?(float*)(cov.data?+?i*cov.step);?? ????????const?float*?dxdata?=?(const?float*)(Dx.data?+?i*Dx.step);?? ????????const?float*?dydata?=?(const?float*)(Dy.data?+?i*Dy.step);?? ?? ?? ????????for(?j?=?0;?j?<?size.width;?j++?)?? ????????{?? ????????????float?dx?=?dxdata[j];?? ????????????float?dy?=?dydata[j];?? ?? ?? ????????????cov_data[j*3]?=?dx*dx;???? ????????????cov_data[j*3+1]?=?dx*dy;?? ????????????cov_data[j*3+2]?=?dy*dy;?? ????????}?? ????}?? ?? ?? ????boxFilter(cov,?cov,?cov.depth(),?Size(block_size,?block_size),??? ????????Point(-1,-1),?false,?borderType?);?? ?? ?? ????if(?op_type?==?MINEIGENVAL?)????? ????????calcMinEigenVal(?cov,?eigenv?);?? ????else?if(?op_type?==?HARRIS?)?? ????????calcHarris(?cov,?eigenv,?k?);?? ????else?if(?op_type?==?EIGENVALSVECS?)?? ????????calcEigenValsVecs(?cov,?eigenv?);?? }??
[cpp]?view plaincopy print?
static?void?? calcHarris(?const?Mat&?_cov,?Mat&?_dst,?double?k?)?? {?? ????int?i,?j;?? ????Size?size?=?_cov.size();?? ????if(?_cov.isContinuous()?&&?_dst.isContinuous()?)?? ????{?? ????????size.width?*=?size.height;?? ????????size.height?=?1;?? ????}?? ?? ????for(?i?=?0;?i?<?size.height;?i++?)?? ????{?? ????????const?float*?cov?=?(const?float*)(_cov.data?+?_cov.step*i);?? ????????float*?dst?=?(float*)(_dst.data?+?_dst.step*i);?? ????????j?=?0;?? ????????for(?;?j?<?size.width;?j++?)?? ????????{?? ????????????float?a?=?cov[j*3];?? ????????????float?b?=?cov[j*3+1];?? ????????????float?c?=?cov[j*3+2];?? ????????????dst[j]?=?(float)(a*c?-?b*b?-?k*(a?+?c)*(a?+?c));???? ????????}?? ????}?? }??
Shi-Tomasi角點檢測
由于Harris算法的穩(wěn)定性和k值有關(guān),Shi-Tomasi發(fā)現(xiàn),角點的穩(wěn)定性和矩陣M的較小特征值有關(guān),改進的Harris算法即直接計算出矩陣M的特征值,用較小的特征值與閾值比較,大于閾值的即為強特征點。
? ? ? ? ? ? ? ? ? ? ? ?
opencv中對其實現(xiàn)算法在goodFeaturesToTrack()函數(shù)中:
[cpp]?view plaincopy print?
CV_EXPORTS_W?void?goodFeaturesToTrack(?InputArray?image,?OutputArray?corners,?? ?????????????????????????????????????int?maxCorners,?double?qualityLevel,?double?minDistance,?? ?????????????????????????????????????InputArray?mask=noArray(),?int?blockSize=3,?? ?????????????????????????????????????bool?useHarrisDetector=false,?double?k=0.04?);?? image:輸入圖像
corners:輸出圖像數(shù)組
maxCorners:需要的角點數(shù)目
qualityLevel:最大,最小特征值的乘法因子。定義可接受圖像角點的最小質(zhì)量因子。
minDistance:容忍距離。角點之間的最小距離,采用歐氏距離。
mask:掩碼
blockSize:鄰域大小
useHarrisDetector:采用Harris角點檢測
k:采用Harris角點檢測時的經(jīng)驗常數(shù)k(0.04~0.06)
算法原理:調(diào)用cornerMinEigenVal()函數(shù)求出每個像素點自適應(yīng)矩陣M的較小特征值,保存在矩陣eig中,然后找到矩陣eig中最大的像素值記為maxVal,然后閾值處理,小于qualityLevel*maxVal的特征值排除掉,最后函數(shù)確保所有發(fā)現(xiàn)的角點之間具有足夠的距離。
[cpp]?view plaincopy print?
void?cv::goodFeaturesToTrack(?InputArray?_image,?OutputArray?_corners,?? ??????????????????????????????int?maxCorners,?double?qualityLevel,?double?minDistance,?? ??????????????????????????????InputArray?_mask,?int?blockSize,?? ??????????????????????????????bool?useHarrisDetector,?double?harrisK?)?? {?? ????Mat?image?=?_image.getMat(),?mask?=?_mask.getMat();?? ?? ????CV_Assert(?qualityLevel?>?0?&&?minDistance?>=?0?&&?maxCorners?>=?0?);?? ????CV_Assert(?mask.empty()?||?(mask.type()?==?CV_8UC1?&&?mask.size()?==?image.size())?);?? ?? ????Mat?eig,?tmp;?? ????if(?useHarrisDetector?)??????? ????????cornerHarris(?image,?eig,?blockSize,?3,?harrisK?);???? ????else?? ????????cornerMinEigenVal(?image,?eig,?blockSize,?3?);???? ?? ????double?maxVal?=?0;?? ????minMaxLoc(?eig,?0,?&maxVal,?0,?0,?mask?);?? ????threshold(?eig,?eig,?maxVal*qualityLevel,?0,?THRESH_TOZERO?);?? ????dilate(?eig,?tmp,?Mat());?? ?? ????Size?imgsize?=?image.size();?? ?? ????vector<const?float*>?tmpCorners;?? ?? ?????? ????for(?int?y?=?1;?y?<?imgsize.height?-?1;?y++?)?? ????{?? ????????const?float*?eig_data?=?(const?float*)eig.ptr(y);?? ????????const?float*?tmp_data?=?(const?float*)tmp.ptr(y);?? ????????const?uchar*?mask_data?=?mask.data???mask.ptr(y)?:?0;?? ?? ????????for(?int?x?=?1;?x?<?imgsize.width?-?1;?x++?)?? ????????{?? ????????????float?val?=?eig_data[x];?? ????????????if(?val?!=?0?&&?val?==?tmp_data[x]?&&?(!mask_data?||?mask_data[x])?)?? ????????????????tmpCorners.push_back(eig_data?+?x);?? ????????}?? ????}?? ?? ????sort(?tmpCorners,?greaterThanPtr<float>()?);???? ????vector<Point2f>?corners;?? ????size_t?i,?j,?total?=?tmpCorners.size(),?ncorners?=?0;?? ?? ? ? ?? ????if(minDistance?>=?1)?? ????{?? ??????????? ????????int?w?=?image.cols;?? ????????int?h?=?image.rows;?? ?????????? ????????const?int?cell_size?=?cvRound(minDistance);?? ????????const?int?grid_width?=?(w?+?cell_size?-?1)?/?cell_size;?? ????????const?int?grid_height?=?(h?+?cell_size?-?1)?/?cell_size;?? ?? ????????std::vector<std::vector<Point2f>?>?grid(grid_width*grid_height);?? ?? ????????minDistance?*=?minDistance;?? ?? ????????for(?i?=?0;?i?<?total;?i++?)???? ????????{?? ????????????int?ofs?=?(int)((const?uchar*)tmpCorners[i]?-?eig.data);?? ????????????int?y?=?(int)(ofs?/?eig.step);?? ????????????int?x?=?(int)((ofs?-?y*eig.step)/sizeof(float));?? ?? ????????????bool?good?=?true;?? ?? ????????????int?x_cell?=?x?/?cell_size;?? ????????????int?y_cell?=?y?/?cell_size;?? ?? ????????????int?x1?=?x_cell?-?1;?? ????????????int?y1?=?y_cell?-?1;?? ????????????int?x2?=?x_cell?+?1;?? ????????????int?y2?=?y_cell?+?1;?? ?? ?????????????? ????????????x1?=?std::max(0,?x1);?? ????????????y1?=?std::max(0,?y1);?? ????????????x2?=?std::min(grid_width-1,?x2);?? ????????????y2?=?std::min(grid_height-1,?y2);?? ?? ????????????for(?int?yy?=?y1;?yy?<=?y2;?yy++?)?? ????????????{?? ????????????????for(?int?xx?=?x1;?xx?<=?x2;?xx++?)?? ????????????????{?? ????????????????????vector?<Point2f>?&m?=?grid[yy*grid_width?+?xx];?? ?? ????????????????????if(?m.size()?)?? ????????????????????{?? ????????????????????????for(j?=?0;?j?<?m.size();?j++)?? ????????????????????????{?? ????????????????????????????float?dx?=?x?-?m[j].x;?? ????????????????????????????float?dy?=?y?-?m[j].y;?? ????????????????????????????if(?dx*dx?+?dy*dy?<?minDistance?)?? ????????????????????????????{?? ????????????????????????????????good?=?false;?? ????????????????????????????????goto?break_out;?? ????????????????????????????}?? ????????????????????????}?? ????????????????????}?? ????????????????}?? ????????????}?? ?? ????????????break_out:?? ?? ????????????if(good)?? ????????????{?? ?????????????????? ?????????????????? ????????????????grid[y_cell*grid_width?+?x_cell].push_back(Point2f((float)x,?(float)y));?? ?? ????????????????corners.push_back(Point2f((float)x,?(float)y));?? ????????????????++ncorners;?? ?? ????????????????if(?maxCorners?>?0?&&?(int)ncorners?==?maxCorners?)?? ????????????????????break;?? ????????????}?? ????????}?? ????}?? ????else????? ????{?? ????????for(?i?=?0;?i?<?total;?i++?)?? ????????{?? ????????????int?ofs?=?(int)((const?uchar*)tmpCorners[i]?-?eig.data);?? ????????????int?y?=?(int)(ofs?/?eig.step);?? ????????????int?x?=?(int)((ofs?-?y*eig.step)/sizeof(float));?? ?? ????????????corners.push_back(Point2f((float)x,?(float)y));?? ????????????++ncorners;?? ????????????if(?maxCorners?>?0?&&?(int)ncorners?==?maxCorners?)?? ????????????????break;?? ????????}?? ????}?? ?? ????Mat(corners).convertTo(_corners,?_corners.fixedType()???_corners.type()?:?CV_32F);?? ?? }?? 求矩陣M最小的特征值
[cpp]?view plaincopy print?
static?void?? calcMinEigenVal(?const?Mat&?_cov,?Mat&?_dst?)?? {?? ????int?i,?j;?? ????Size?size?=?_cov.size();?? ????if(?_cov.isContinuous()?&&?_dst.isContinuous()?)?? ????{?? ????????size.width?*=?size.height;?? ????????size.height?=?1;?? ????}?? ?? ????for(?i?=?0;?i?<?size.height;?i++?)?? ????{?? ????????const?float*?cov?=?(const?float*)(_cov.data?+?_cov.step*i);?? ????????float*?dst?=?(float*)(_dst.data?+?_dst.step*i);?? ????????j?=?0;?? ????????for(?;?j?<?size.width;?j++?)?? ????????{?? ????????????float?a?=?cov[j*3]*0.5f;?? ????????????float?b?=?cov[j*3+1];????? ????????????float?c?=?cov[j*3+2]*0.5f;?? ????????????dst[j]?=?(float)((a?+?c)?-?std::sqrt((a?-?c)*(a?-?c)?+?b*b));?? ????????}?? ????}?? }??
參考:http://blog.csdn.net/xw20084898/article/details/21180729
? ? ? ? ?http://wenku.baidu.com/view/f61bc369561252d380eb6ef0.html
? ? ? ? ?http://blog.csdn.net/crzy_sparrow/article/details/7391511? ???
總結(jié)
以上是生活随笔為你收集整理的Harris及Shi-Tomasi原理及源码解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。