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 !
沒有留言:
張貼留言