1. 程式人生 > >OpenCV角點檢測goodFeaturesToTrack()原始碼分析

OpenCV角點檢測goodFeaturesToTrack()原始碼分析

  上面一篇部落格分析了HARRIS和ShiTomasi角點檢測的原始碼。而為了提取更準確的角點,OpenCV中提供了goodFeaturesToTrack()這個API函式,來獲取更加準確的角點位置。這篇部落格主要分析goodFeaturesToTrack()的原始碼。

  函式原型如下:

void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
                              int maxCorners, double qualityLevel, double minDistance,
                              InputArray _mask, 
int blockSize, int gradientSize, bool useHarrisDetector, double harrisK )

  _image為輸入的單通道影象;_corners為輸出提取的角點座標;maxCorners為設定的最大角點個數,程式中會按照角點強度降序排序,超過maxCorners的角點將被捨棄;qualityLevel為角點強度的閾值係數,如果檢測出所有角點中的最大強度為max,則強度值<max*qualityLevel得角點會被捨棄;minDistance為角點與其鄰域強角點之間的歐式距離,與鄰域強角點距離小於minDistance的角點將被捨棄;_mask為設定的感興趣區域,通常可不設定;blockSize是協方差矩陣濾波的視窗大小;gradientSize為sobel運算元求微分的視窗的大小;useHarrisDetector為是否使用Harris角點檢測;harrisK為Harris角點檢測特徵表示式中的常數k值。

  接下來看原始碼,首先根據useHarrisDetector這個flg值的設定選取不同的方法提取初始角點:

   //提取初始角點
  if
( useHarrisDetector ) cornerHarris( image, eig, blockSize, gradientSize, harrisK ); else cornerMinEigenVal( image, eig, blockSize, gradientSize );

  然後選取出所有角點特徵值的最大值maxVal,並進行閾值化,將小於maxVal*qulityLevel的特徵值捨棄掉(置為0),其餘保持不變。並用3x3的方形膨脹核對特徵值矩陣進行膨脹操作,膨脹的目的是使孤立的區域性最大值擴大化,膨脹過後3x3鄰域的非區域性最大值點被區域性最大值取代。膨脹過後的特徵值影象為tmp,後面會用到。

    //獲取最大角點特徵值
    double maxVal = 0;
    minMaxLoc( eig, 0, &maxVal, 0, 0, _mask );
    threshold( eig, eig, maxVal*qualityLevel, 0, THRESH_TOZERO );
    dilate( eig, tmp, Mat());

  取出區域性最大值點,並將其地址儲存到tmpCorners這個容器中。(val==tem_data[x]表示該點未被膨脹操作影響,就是區域性極大值點)

// collect list of pointers to features - put them into temporary image
    Mat mask = _mask.getMat();
    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);
        }
    }

  然後將tmpCorners中指標指向的值進行降序排列,(其實是隻改變指標指向的位置):

 std::sort( tmpCorners.begin(), tmpCorners.end(), greaterThanPtr() ); 

  接下來是不太好理解的地方,首先進行minDistance的判斷。如果minDistance<1,也就是不進行minDistance的條件限制,直接儲存前maxCorners個角點並返回;如果minDistance>=1,則執行if{}中的程式碼段。

  首先弄清楚grid這個是什麼東西,grid容器中元素個數是影象畫素點個數的1/(cell_size*cell_size)倍,但是它是一個vector<vector<Point2f>>,也就是指grid中的每一個元素是一個vetcor<Point2f>(意思就是一個元素對應n個2維座標點)。這個理解起來就是grid中相差一個畫素,相當於原影象中相差minDistance個畫素。原影象中以當前畫素為中心的minDistance範圍內的點在grid中其實視為一個畫素的3x3鄰域(一對多的關係)。

  接下來的分析見註釋:

if (minDistance >= 1)
    {
         // Partition the image into larger grids
        int w = image.cols;
        int h = image.rows;

        const int cell_size = cvRound(minDistance);
    
     //grid中元素(vector)個數為grid_width*grid_height個,+cell_size-1的目的是保證能夠覆蓋所有的畫素點
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.ptr()); int y = (int)(ofs / eig.step); int x = (int)((ofs - y*eig.step)/sizeof(float)); //假設開始所有的角點是good bool good = true; //將原圖中角點座標歸一化到mindistance鄰域 int x_cell = x / cell_size; int y_cell = y / cell_size; //取歸一化後點的鄰域4個點座標(不是4鄰域,而是4個角),在grid中的座標 int x1 = x_cell - 1; int y1 = y_cell - 1; int x2 = x_cell + 1; int y2 = y_cell + 1; // boundary check 邊界判斷 x1 = std::max(0, x1); y1 = std::max(0, y1); x2 = std::min(grid_width-1, x2); y2 = std::min(grid_height-1, y2); //遍歷鄰域4個點, grid中的鄰域座標 for( int yy = y1; yy <= y2; yy++ ) { for( int xx = x1; xx <= x2; xx++ ) {
//取出grid中一個元素對應的所有強角點座標位置 std::vector
<Point2f> &m = grid[yy*grid_width + xx]; //如果某元素對應的原影象角點容器中有已經儲存的強角點,則需要進行距離判斷。否則指定原影象中該角點就是強角點 if( m.size() ) {
//遍歷其對應容器內的其他強角點,並依次判斷原影象中當前角點與其鄰域內其他強角點之間的歐式距離,如果歐式距離小於minDistance,則將當前角點標誌置為good=false(拋棄),並跳出
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:        //如果角點為good,則將該角點儲存在當前grid中一個元素對應的容器中,同時儲存在輸出容器corners中,並累加計數器ncorners。由於已經進行過降序排序,前面儲存的都是強角點。 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.ptr()); 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);

  結束!

相關推薦

OpenCV檢測goodFeaturesToTrack原始碼分析

  上面一篇部落格分析了HARRIS和ShiTomasi角點檢測的原始碼。而為了提取更準確的角點,OpenCV中提供了goodFeaturesToTrack()這個API函式,來獲取更加準確的角點位置。這篇部落格主要分析goodFeaturesToTrack()的原始碼。   函式原型如下: void cv

【OpenCV3經典程式設計100例】242D特徵:Harris檢測cornerHarris

一、2d特徵相關知識Learn about how to use the feature points detectors, descriptors and matching inside OpenCV

OpenCV檢測原始碼分析Harris和ShiTomasi

1 #include <opencv2\opencv.hpp> 2 #include <iostream> 3 #include <string> 4 5 using namespace std; 6 7 #define HARRIS

OpenCV檢測源代碼分析Harris和ShiTomasi

mine res output 判斷 代數 void pos tar def OpenCV中常用的角點檢測為Harris角點和ShiTomasi角點。 以OpenCV源代碼文件 .\opencv\sources\samples\cpp\tutorial_code\Track

opencv: 檢測原始碼分析

以下6個函式是opencv有關角點檢測的函式 ConerHarris, cornoerMinEigenVal,CornorEigenValsAndVecs, preConerDetect, conerSubPix, goodFeaturesToTracks, 其中, 前三個都呼叫靜態函式cornerEigen

OpenCV特徵檢測------Surf特徵

Surf(Speed Up Robust Feature)Surf演算法的原理                                                                          1.構建Hessian矩陣構造高斯金字塔尺度空間其

檢測運算元Harris, KLT, SIFT,SUSAN

角點檢測:        角點:最直觀的印象就是在水平、豎直兩個方向上變化均較大的點,即Ix、Iy都較大 。         邊緣:僅在水平、或者僅在豎直方向有較大的變化量,即Ix和Iy只有其一較大。         平坦地區:在水平、豎直方向的變化量均較小,即Ix、Iy

基於生長的棋盤格檢測方法--2程式碼詳解

上一篇介紹了基於生長的棋盤格角點檢測方法的大概原理,詳見:基於生長的棋盤格角點檢測方法–(1)原理介紹 本文進一步從程式碼解讀角度出發,更深入地理解工程中是如何實現的。 本文中用到的程式碼可以從以下連結下載 http://www.cvlibs.net/so

opencv-檢測之Harris檢測

trunc get data 圖像旋轉 ror 協方差矩陣 -a double 特定 轉自:https://blog.csdn.net/poem_qianmo/article/details/29356187 先看看程序運行截圖: 一、引言:關於興趣點(i

OpenCV 檢測(三) Shi-Tomasi

Shi-Tomasi運算元 就像Harrise運算元是在Moravec運算元的基礎上改進得到的一樣: http://blog.csdn.net/chaipp0607/article/details/54692818 Shi-Tomasi運算元是在Harri

opencv 檢測

四、亞畫素角點檢測上述講到的兩種角點檢測演算法能較好的找到角點,但其實結果並不精確。當我們需要進行精確的角點計算時,就要用到亞畫素角點檢測(顧名思義,都亞畫素了,能不精確一點嗎)。亞畫素角點檢測在攝像機標定、跟蹤並重建攝像機的軌跡或進行三維重建時有著重要作用。那亞畫素到底“亞”在哪兒了?通常我們計算出的座標都

opencv——檢測

cvGoodFeaturesToTrack() #include"cv.h" #include"highgui.h" #include"stdio.h" #define max_corners 50 int main(int argc, char** arg

x264_param_default_preset原始碼分析

原始碼分析 h264編碼原理複雜,引數眾多。為了方便使用無論x264還是其他編碼的實現框架,都封裝了幾種現有的編碼模型,只需要根據編碼速度的要求和視訊質量的要求選擇模型,並修改部分視訊引數即可編碼。 模型的選擇就是通過x264_param_default_pre

applyMiddleware 原始碼分析

// 這個函式應該是整個原始碼中最難理解的一塊了 // 該函式返回一個柯里化的函式 // 所以呼叫這個函式應該這樣寫 applyMiddleware(...middlewares)(createStore)(...args) export default function applyMiddlewa

x264_param_default原始碼分析

/****************************************************************************  * x264_param_default:  ***********************************

OpenCV探索之路十五檢測

回調函數 閾值 source and 類型 幾何 擁有 .com named 角點檢測是計算機視覺系統中用來獲取圖像特征的一種方法。我們都常說,這幅圖像很有特點,但是一問他到底有哪些特點,或者這幅圖有哪些特征可以讓你一下子就識別出該物體,你可能就說不出來了。其實說圖像的特征

Python OpenCV _3形態學處理腐蝕膨脹,開閉運算,以及利用形態學進行邊緣檢測

Python OpenCV這個初級影象處理系列是參考他人的文章寫的,有些地方做了一些改動,沒有太多理論,側重程式碼實現,主要目的是將這些基本操作程式碼系統地梳理一遍,也是為了以後能快速查詢。 此係列原始碼在我的GitHub裡:https://github.com/yeyujujishou19/P

cornerSubPixel亞畫素檢測原始碼分析最小二乘法

OpenCV的中有cornerSubPixel()這個API函式用來針對初始的整數角點座標進行亞畫素精度的優化,該函式原型如下: C++: void cornerSubPix(InputArray image, InputOutputArray corners, Siz

OpenCV學習筆記14:形態學濾波對影象進行邊緣及檢測

</pre><pre name="code" class="cpp">#include "stdafx.h" #include<opencv2/opencv.hpp> using namespace cv; class MorphoFe

Harris檢測原理與opencvpython實現

在學習時主要參考了1.http://blog.csdn.net/xiaowei_cqu/article/details/7805206和opencv-python官方的關於harris的文件(http://opencv-python-tutroals.readthedocs