Emgu?

SIFT演算法大家都比較熟悉,網上的版本很多,剛開始接觸時我主要研究的是C++,因為相對於C#,基於OPEN CV C++的SIFT演算法資料更多,但是由於想要實現較為理想的介面效果,最終還是放棄了使用C++轉而使用C#。

C#中SIFT演算法主要分為三種:

1)脫離Emgu cv平臺,完全手動實現所有SIFT演算法函式,這樣的程式雖然實現有些困難,但是完全可藉助已有的C++程式做更改,而且這樣做最大的好處就是對SIFT演算法的原理有更深的理解。

2)實現時使用少量Emgu cv函式(例如影像的讀取,灰度值獲得等),但是大部分工作還是依賴於.net平臺自行完成。

3)基本上程式完全藉助於Emgu cv提供的介面,核心函式完全由Emgu cv提供。

前兩類程式資源較多,大家也很容易下載,第三類程式資源相對較少,因此我今天簡單為大家介紹第三類演算法的實現方法,首先回顧一下SIFT演算法計算步驟:

1. 尺度空間極值檢測:搜尋所有尺度上的影象位置。通過高斯微分函式來識別潛在的對於尺度和旋轉不變的興趣點。

2. 關鍵點定位:在每個候選的位置上,通過一個擬合精細的模型來確定位置和尺度。關鍵點的選擇依據於它們的穩定程度。

3. 方向確定:基於影象區域性的梯度方向,分配給每個關鍵點位置一個或多個方向。所有後面的對影象資料的操作都相對於關鍵點的方向、尺度和位置進行變換,從而提供對於這些變換的不變性。

4. 關鍵點描述:在每個關鍵點周圍的鄰域內,在選定的尺度上測量影象區域性的梯度。這些梯度被變換成一種表示,這種表示允許比較大的區域性形狀的變形和光照變化。

使用Emgu cv實現上述步驟非常簡單,程式如下:

//確定匹配影象

Bitmap bt1 = new Bitmap(@"C:UsersGAOXIANGDesktopI.jpg");

Bitmap bt2 = new Bitmap(@"C:UsersGAOXIANGDesktop’.jpg");

//將影象轉為Emgu cv的處理格式

Image img1 = new Image (bt1);

Image img2 = new Image (bt2);

//使用Emgu cv探測圖片特徵點

SIFTDetector sift = new SIFTDetector();

var f1 = sift.DetectFeatures(img1, null);

var f2 = sift.DetectFeatures(img2, null);

到此已經獲得了兩張相片的特徵點f1,f2,接下來就是將相互匹配的特徵點相連:

for (int i = 0; i < f1.Length; i++)

{ double[] dist = new double[f2.Length];

int n = 0;

int index = 0;

for (int j = 0; j < f2.Length; j++)

{

//計算待比較特徵點描述子的歐式距離

dist[n++] = diedai(f1[i].Descriptor, f2[j].Descriptor);

}

//排序,獲得歐式距離最近點以及次近點

for (int k = 0; k < 2; k++)

{ for (int k1 = k+1; k1 < dist.Length; k1++)

{ if (dist[k] > dist[k1])

{ double temp = dist[k];

dist[k] = dist[k1];

dist[k1] = temp;

//記錄最近點在相片2中的序列

if (k == 0)

{ index = k1; } } } }

//若最近點與次近點比值小於閾值0.49,繪製特徵點連線

if (dist[0]/dist[1] < 0.49)

{ PointF point1 = f1[i].KeyPoint.Point;

PointF point2 = f2[index].KeyPoint.Point;

Graphics g = this.CreateGraphics();

Pen p1 = new Pen(Color.Blue, 3);

g.DrawLine(p1, point1, point2);

//注意:point1,point2位置與具體控制元件,影象佈局有關,請自行調整 }}

//描述子距離計算函式

private double diedai(float[] p1, float[] p2)

{ double sub=0; double sqrt=0;for (int i = 0; i < p1.Length; i++)

{ sub += Math.Pow(p1[i] - p2[i], 2); }

sqrt = Math.Sqrt(sub);

return sqrt;

}

相關問題答案