2013年5月2日 星期四

EmguCV Image Process: Detecting and Matching Interest Points part1

20101219030.jpg
EmguCV Image Process: Detecting and Matching Interest Points

參考OpenCV 2 Computer Vision Application Programming Cookbook第八章

介紹內容如下:

Detecting Harris corners

Detecting FAST features

Detecting the scale-invariant SURF features

Describing SURF features


在電腦視覺中,興趣點(interest points)也常常會稱為

關鍵點(keypoints)或是特徵點(feature points)

常應用於物件識別(object recognition)、影像對位(image registration)、

視覺追蹤(visual tracking)、3D重建(3D reconstruction)...等等

透過影像中某些比較有幫助的特殊點的資訊

取代觀察整張影像的資訊

而這種方法運作的好壞取決於

是否從影像中偵測出足夠量的特徵點

而這些特徵點能夠被精確的定位取決於

這些點位是否具備區別和穩定的特徵

本章節將介紹如何擷取影像中常見的幾種特徵點

並如何應用於影像配對上


在影像中搜尋興趣點的時候

角點(corners)是常被利用的

影像中的角點常出現於人工的物體上

像是牆壁、門、窗戶、桌...等等

而角點的另一個特質就是屬於二維特徵(two-dimensional features)

可以精確的定位出由兩條邊界交會的位置

Harris feature detection就是用來處理偵測角點的方法


在EmguCV中並無直接實作Harris corner

必須以CvInvoke的方式來呼叫cvCornerHarris這個方法

直接看簡單的使用:

Image<Gray, Byte> image = new Image<Gray, Byte>("image.jpg");
//Harris corners strength
Image<Gray, float> cornerStrength = new Image<Gray, float>(image.Size);
CvInvoke.cvCornerHarris(
    image,       //source image
    cornerStrength, //result image
    3,           //neighborhood size
    3,           //aperture size
    0.01);       //Harris parameter
//threshold the corner strengths
cornerStrength._ThresholdBinary(new Gray(0.0001), new Gray(255));

方法很簡單

帶入的來源影像必須是灰階8-bit影像

而輸出結果cornerStrength必須是灰階32-bit影像

然後在分別輸入三個變數值

取得結果的影像

需要透過二值化來呈現

由於cvCornerHarris計算出來的結果的值很小

所以這邊設定的閥值很低,只有0.0001

透過這樣簡單的程式結果如下:

偵測出來的點位都是在影像的角點上


這裡透過一些封裝的方法

讓CvInvoke.cvCornerHarris更容易被使用

在這邊建立一個名為HarrisDetector的類別

透過幾個簡單的方法呼叫

並且能夠將角點繪製在想要的影像上

程式如下:

public class HarrisDetector { //32-bit float image of corner strength private Image<Gray, float> _CornerStrength; //32-bit float image of thresholded corners private Image<Gray, float> _CornerTh; //size of neighborhood for derivatives smoothing int _Neighborhood; //aperture for gradient computation int _Aperture; //Harris parameter double _K; //maximum strength for threshold computation double _MaxStrength; //calculated threshold (internal) double _Threshold; public HarrisDetector() { this._Neighborhood = 3; this._Aperture = 3; this._K = 0.01; this._MaxStrength = 0.0; this._Threshold = 0.01; } /// <summary> /// Compute Harris corners /// </summary> /// <param name="image">source image</param> public void Detect(Image<Gray,Byte> image) { this._CornerStrength=new Image<Gray,float>(image.Size); //Harris computation CvInvoke.cvCornerHarris( image, //source image this._CornerStrength, //result image this._Neighborhood, //neighborhood size this._Aperture, //aperture size this._K); //Harris parameter //internal threshold computation double[] maxStrength; double[] minStrength; //not used Point[] minPoints; //not used Point[] maxPoints; //not used this._CornerStrength.MinMax(out minStrength, out maxStrength, out minPoints, out maxPoints); this._MaxStrength = maxStrength[0]; } /// <summary> /// Get the corner map from computed Harris values /// </summary> /// <param name="qualityLevel">Harris values</param> /// <returns>corner map</returns> public Image<Gray, Byte> GetCornerMap(double qualityLevel) { Image<Gray, Byte> cornerMap; //thresholding the corner strength this._Threshold = qualityLevel * this._MaxStrength; this._CornerTh = this._CornerStrength.ThresholdBinary( new Gray(this._Threshold), new Gray(255)); //convert to 8-bit image cornerMap = this._CornerTh.Convert<Gray, Byte>(); return cornerMap; } /// <summary> /// Get the feature points from the computed Harris value /// </summary> /// <param name="cornerPoints">feature points</param> /// <param name="qualityLevel">Harris value</param> public void GetCorners(List<Point> cornerPoints, double qualityLevel) { Image<Gray, Byte> cornerMap = GetCornerMap(qualityLevel); GetCorners(cornerPoints, cornerMap); } //Get the feature points from the computed corner map void GetCorners(List<Point> cornerPoints, Image<Gray, Byte> cornerMap) { //Interate over the pixels to obtain all features for (int h = 0; h < cornerMap.Height; h++) { for (int w = 0; w < cornerMap.Width; w++) { //if it is a feature point if (cornerMap[h, w].Intensity > 0) { cornerPoints.Add(new Point(w, h)); } } } } /// <summary> /// Draw circles at feature point locations on an image /// </summary> /// <param name="image">image</param> /// <param name="points">feature points</param> public void DrawFeaturePoints(Image<Gray, Byte> image, List<Point> points) { //for all corner foreach (Point point in points) { //draw a circle at each corner location CircleF circle=new CircleF(new PointF(point.X,point.Y),3); image.Draw(circle, new Gray(255), 1); } } }

這裡透過幾個公開方法來使用

Detect做偵測的動作

然後GetCorners取得偵測的角點

DrawFeaturePoints繪製角點影像

呼叫的方式如下:

HarrisDetector harris = new HarrisDetector();
harris.Detect(image);
List<Point> featurePoints=new List<Point>();
harris.GetCorners(featurePoints, 0.01);
harris.DrawFeaturePoints(image, featurePoints);

先建立HarrisDetector的類別

然後呼叫方法Detect傳入來源影像image

然後取得featurePoints角點集合

最後繪製角點影像,以圓圈的方式繪製

結果如下:


與原圖的比對就能夠輕易看出偵測點的位置

都相當準確地位於角點之上

完整一點的實作

還可以把一些在建構式中初始的參數公開讓使用者來設定

這樣就能更有彈性


Harris Corner Detection的演算法還蠻複雜的

有興趣的人可以到OpenCV的官網參考

也可以到Wiki看看較完整的數學公式


下一篇來介紹更實用,更好用的方法good features to track !

沒有留言:

張貼留言