程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 圖像特征檢測(Image Feature Detection)(一)

圖像特征檢測(Image Feature Detection)(一)

編輯:關於.NET

前言

圖像特征提取是計算機視覺和圖像處理中的一個概念。它指的是使用計算機提取圖像信 息,決定每個圖像的點是否屬於一個圖像特征。本文主要探討如何提取圖像中的“角點”這 一特征,及其相關的內容。而諸如直方圖、邊緣、區域等內容在前文中有所提及,請查看相 關文章。OpenCv(EmguCv)中實現了多種角點特征的提取方法,包括:Harris角點、 ShiTomasi角點、亞像素級角點、SURF角點、Star關鍵點、FAST關鍵點、Lepetit關鍵點等等 ,本文將逐一介紹如何檢測這些角點。在此之前將會先介紹跟角點檢測密切相關的一些變換 ,包括Sobel算子、拉普拉斯算子、Canny算子、霍夫變換。另外,還會介紹一種廣泛使用而 OpenCv中並未實現的SIFT角點檢測,以及最近在OpenCv中實現的MSER區域檢測。所要講述的 內容會很多,我這裡盡量寫一些需要注意的地方及實現代碼,而參考手冊及書本中有的內容 將一筆帶過或者不會提及。

Sobel算子

Sobel算子用多項式計算來擬合導數計算,可以用OpenCv中的cvSobel函數或者EmguCv中 的 Image<TColor,TDepth>.Sobel方法來進行計算。需要注意的是,xorder和yorder 中必須且只能有一個為非零值,即只能計算x方向或者y反向的導數;如果將方形濾波器的寬 度設置為特殊值CV_SCHARR(-1),將使用Scharr濾波器代替Sobel濾波器。

使用Sobel濾波器的示例代碼如下:

Sobel算子

private string SobelFeatureDetect()
         {
             //獲取參數
             int xOrder = int.Parse((string) cmbSobelXOrder.SelectedItem);
             int yOrder = int.Parse((string) cmbSobelYOrder.SelectedItem);
             int apertureSize = int.Parse((string) cmbSobelApertureSize.SelectedItem);
             if ((xOrder == 0 && yOrder == 0) ||  (xOrder != 0 && yOrder != 0))
                 return "Sobel算子,參數錯誤:xOrder和yOrder 中必須且只能有一個非零。\r\n";
             //計算
             Stopwatch sw = new Stopwatch();
             sw.Start();
             Image<Gray, Single> imageDest =  imageSourceGrayscale.Sobel(xOrder, yOrder, apertureSize);
             sw.Stop();
             //顯示
             pbResult.Image = imageDest.Bitmap;
             //釋放資源
             imageDest.Dispose();
             //返回
             return string.Format("·Sobel算子,用時{0:F05}毫秒, 參數(x方向求導階數:{1},y方向求導階數:{2},方形濾波器寬度:{3})\r\n",  sw.Elapsed.TotalMilliseconds, xOrder, yOrder, apertureSize);
         }

拉普拉斯算子

拉普拉斯算子可以用作邊緣檢測;可以用OpenCv中的cvLaplace函數或者EmguCv中的 Image<TColor,TDepth>.Laplace方法來進行拉普拉斯變換。需要注意的是:OpenCv的 文檔有點小錯誤,apertureSize參數值不能為CV_SCHARR(-1)。

使用拉普拉斯變換的示例代碼如下:

拉普拉斯算子

private string LaplaceFeatureDetect()
         {
             //獲取參數
             int apertureSize = int.Parse((string) cmbLaplaceApertureSize.SelectedItem);
             //計算
             Stopwatch sw = new Stopwatch();
             sw.Start();
             Image<Gray, Single> imageDest =  imageSourceGrayscale.Laplace(apertureSize);
             sw.Stop();
             //顯示
             pbResult.Image = imageDest.Bitmap;
             //釋放資源
             imageDest.Dispose();
             //返回
             return string.Format("·拉普拉斯變換,用時{0:F05}毫 秒,參數(方形濾波器寬度:{1})\r\n", sw.Elapsed.TotalMilliseconds,  apertureSize);
         }

Canny算子

Canny算子也可以用作邊緣檢測;可以用OpenCv中的cvCanny函數或者EmguCv中的 Image<TColor,TDepth>.Canny方法來進行Canny邊緣檢測。所不同的是, Image<TColor,TDepth>.Canny方法可以用於檢測彩色圖像的邊緣,但是它只能使用 apertureSize參數的默認值3;

而cvCanny只能處理灰度圖像,不過可以自定義apertureSize。cvCanny和Canny的方法參 數名有點點不同,下面是參數對照表。

Image<TColor,TDepth>.Canny    CvInvoke.cvCanny
thresh                                          lowThresh
threshLinking                                highThresh
3                                                 apertureSize

值得注意的是,apertureSize只能取3,5或者7,這可以在cvcanny.cpp第87行看到:

aperture_size &= INT_MAX;    if( (aperture_size & 1)  == 0 || aperture_size < 3 || aperture_size > 7 )         CV_ERROR( CV_StsBadFlag, "" );

使用Canny算子的示例代碼如下:

Canny算子

private string CannyFeatureDetect()
         {
             //獲取參數
             double lowThresh = double.Parse (txtCannyLowThresh.Text);
             double highThresh = double.Parse (txtCannyHighThresh.Text);
             int apertureSize = int.Parse((string) cmbCannyApertureSize.SelectedItem);
             //計算
             Stopwatch sw = new Stopwatch();
             sw.Start();
             Image<Gray, Byte> imageDest = null;
             Image<Bgr, Byte> imageDest2 = null;
             if (rbCannyUseCvCanny.Checked)
             {
                 imageDest = new Image<Gray, byte> (imageSourceGrayscale.Size);
                 CvInvoke.cvCanny(imageSourceGrayscale.Ptr,  imageDest.Ptr, lowThresh, highThresh, apertureSize);
             }
             else
                 imageDest2 = imageSource.Canny(new Bgr (lowThresh, lowThresh, lowThresh), new Bgr(highThresh, highThresh,  highThresh));
             sw.Stop();
             //顯示
             pbResult.Image = rbCannyUseCvCanny.Checked ?  imageDest.Bitmap : imageDest2.Bitmap;
             //釋放資源
             if (imageDest != null)
                 imageDest.Dispose();
             if (imageDest2 != null)
                 imageDest2.Dispose();
             //返回
             return string.Format("·Canny算子,用時{0:F05}毫秒, 參數(方式:{1},閥值下限:{2},閥值上限:{3},方形濾波器寬度:{4})\r\n",  sw.Elapsed.TotalMilliseconds, rbCannyUseCvCanny.Checked ? "cvCanny" :  "Image<TColor, TDepth>.Canny", lowThresh, highThresh,  apertureSize);
         }

另外,在http://www.china-vision.net/blog/user2/15975/archives/2007/804.html有 一種自動獲取Canny算子高低閥值的方法,作者提供了用C語言實現的代碼。我將其改寫成了 C#版本,代碼如下:

計算圖像的自適應Canny算子閥值

/// <summary>
         /// 計算圖像的自適應Canny算子閥值
         /// </summary>
         /// <param name="imageSrc">源圖像,只能是256級灰度圖 像</param>
         /// <param name="apertureSize">方形濾波器的寬度 </param>
         /// <param name="lowThresh">閥值下限 </param>
         /// <param name="highThresh">閥值上限 </param>
         unsafe void AdaptiveFindCannyThreshold(Image<Gray,  Byte> imageSrc, int apertureSize, out double lowThresh, out double  highThresh)
         {
             //計算源圖像x方向和y方向的1階Sobel算子
             Size size = imageSrc.Size;
             Image<Gray, Int16> imageDx = new  Image<Gray, short>(size);
             Image<Gray, Int16> imageDy = new  Image<Gray, short>(size);
             CvInvoke.cvSobel(imageSrc.Ptr, imageDx.Ptr, 1, 0,  apertureSize);
             CvInvoke.cvSobel(imageSrc.Ptr, imageDy.Ptr, 0, 1,  apertureSize);
             Image<Gray, Single> image = new  Image<Gray, float>(size);
             int i, j;
             DenseHistogram hist = null;
             int hist_size = 255;
             float[] range_0 = new float[] { 0, 256 };
             double PercentOfPixelsNotEdges = 0.7;
             //計算邊緣的強度,並保存於圖像中
             float maxv = 0;
             float temp;
             byte* imageDataDx = (byte*) imageDx.MIplImage.imageData.ToPointer();
             byte* imageDataDy = (byte*) imageDy.MIplImage.imageData.ToPointer();
             byte* imageData = (byte*) image.MIplImage.imageData.ToPointer();
             int widthStepDx = imageDx.MIplImage.widthStep;
             int widthStepDy = widthStepDx;
             int widthStep = image.MIplImage.widthStep;
             for (i = 0; i < size.Height; i++)
             {
                 short* _dx = (short*)(imageDataDx +  widthStepDx * i);
                 short* _dy = (short*)(imageDataDy +  widthStepDy * i);
                 float* _image = (float*)(imageData +  widthStep * i);
                 for (j = 0; j < size.Width; j++)
                 {
                     temp = (float)(Math.Abs(*(_dx +  j)) + Math.Abs(*(_dy + j)));
                     *(_image + j) = temp;
                     if (maxv < temp)
                         maxv = temp;
                 }
             }
             //計算直方圖
             range_0[1] = maxv;
             hist_size = hist_size > maxv ? (int)maxv :  hist_size;
             hist = new DenseHistogram(hist_size, new RangeF (range_0[0], range_0[1]));
             hist.Calculate<Single>(new Image<Gray,  Single>[] { image }, false, null);
             int total = (int)(size.Height * size.Width *  PercentOfPixelsNotEdges);
             double sum = 0;
             int icount = hist.BinDimension[0].Size;
             for (i = 0; i < icount; i++)
             {
                 sum += hist[i];
                 if (sum > total)
                     break;
             }
             //計算閥值
             highThresh = (i + 1) * maxv / hist_size;
             lowThresh = highThresh * 0.4;
             //釋放資源
             imageDx.Dispose();
             imageDy.Dispose(); image.Dispose();
             hist.Dispose();
         }

霍夫變換

霍夫變換是一種在圖像中尋找直線、圓及其他簡單形狀的方法,在OpenCv中實現了霍夫 線變換和霍夫圓變換。值得注意的地方有以下幾點:(1)HoughLines2需要先計算Canny邊 緣,然後再檢測直線;(2)HoughLines2計算結果的獲取隨獲取方式的不同而不同;(3) HoughCircles檢測結果似乎不正確。

使用霍夫變換的示例代碼如下所示:

霍夫變換

private string HoughLinesFeatureDetect()
         {
             //獲取參數
             HOUGH_TYPE method = rbHoughLinesSHT.Checked ?  HOUGH_TYPE.CV_HOUGH_STANDARD : (rbHoughLinesPPHT.Checked ?  HOUGH_TYPE.CV_HOUGH_PROBABILISTIC : HOUGH_TYPE.CV_HOUGH_MULTI_SCALE);
             double rho = double.Parse (txtHoughLinesRho.Text);
             double theta = double.Parse (txtHoughLinesTheta.Text);
             int threshold = int.Parse (txtHoughLinesThreshold.Text);
             double param1 = double.Parse (txtHoughLinesParam1.Text);
             double param2 = double.Parse (txtHoughLinesParam2.Text);
             MemStorage storage = new MemStorage();
             int linesCount = 0;
             StringBuilder sbResult = new StringBuilder();
             //計算,先運行Canny邊緣檢測(參數來自Canny算子屬性頁 ),然後再用計算霍夫線變換
             double lowThresh = double.Parse (txtCannyLowThresh.Text);
             double highThresh = double.Parse (txtCannyHighThresh.Text);
             int apertureSize = int.Parse((string) cmbCannyApertureSize.SelectedItem);
             Image<Gray, Byte> imageCanny = new  Image<Gray, byte>(imageSourceGrayscale.Size);
             CvInvoke.cvCanny(imageSourceGrayscale.Ptr,  imageCanny.Ptr, lowThresh, highThresh, apertureSize);
             Stopwatch sw = new Stopwatch();
             sw.Start();
             IntPtr ptrLines = CvInvoke.cvHoughLines2 (imageCanny.Ptr, storage.Ptr, method, rho, theta, threshold, param1,  param2);
             Seq<LineSegment2D> linesSeq = null;
             Seq<PointF> linesSeq2 = null;
             if (method == HOUGH_TYPE.CV_HOUGH_PROBABILISTIC)
                 linesSeq = new Seq<LineSegment2D> (ptrLines, storage);
             else
                 linesSeq2 = new Seq<PointF> (ptrLines, storage);
             sw.Stop();
             //顯示
             Image<Bgr, Byte> imageResult =  imageSourceGrayscale.Convert<Bgr, Byte>();
             if (linesSeq != null)
             {
                 linesCount = linesSeq.Total;
                 foreach (LineSegment2D line in linesSeq)
                 {
                     imageResult.Draw(line, new Bgr (255d, 0d, 0d), 4);
                     sbResult.AppendFormat("{0}-{1},",  line.P1, line.P2);
                 }
             }
             else
             {
                 linesCount = linesSeq2.Total;
                 foreach (PointF line in linesSeq2)
                 {
                     float r = line.X;
                     float t = line.Y;
                     double a = Math.Cos(t), b =  Math.Sin(t);
                     double x0 = a * r, y0 = b *  r;
                     int x1 = (int)(x0 + 1000 * (- b));
                     int y1 = (int)(y0 + 1000 *  (a));
                     int x2 = (int)(x0 - 1000 * (- b));
                     int y2 = (int)(y0 - 1000 *  (a));
                     Point pt1 = new Point(x1,  y1);
                     Point pt2 = new Point(x2,  y2);
                     imageResult.Draw(new LineSegment2D (pt1, pt2), new Bgr(255d, 0d, 0d), 4);
                     sbResult.AppendFormat("{0}-{1},",  pt1, pt2);
                 }
             }
             pbResult.Image = imageResult.Bitmap;
             //釋放資源
             imageCanny.Dispose();
             imageResult.Dispose();
             storage.Dispose();
             //返回
             return string.Format("·霍夫線變換,用時{0:F05}毫秒 ,參數(變換方式:{1},距離精度:{2},弧度精度:{3},閥值:{4},參數1:{5},參數 2:{6}),找到{7}條直線\r\n{8}",
                 sw.Elapsed.TotalMilliseconds,  method.ToString("G"), rho, theta, threshold, param1, param2, linesCount,  linesCount != 0 ? (sbResult.ToString() + "\r\n") : "");
         }
         //霍夫圓變換
         private string HoughCirclesFeatureDetect()
         {
             //獲取參數
             double dp = double.Parse (txtHoughCirclesDp.Text);
             double minDist = double.Parse (txtHoughCirclesMinDist.Text);
             double param1 = double.Parse (txtHoughCirclesParam1.Text);
             double param2 = double.Parse (txtHoughCirclesParam2.Text);
             int minRadius = int.Parse (txtHoughCirclesMinRadius.Text);
             int maxRadius = int.Parse (txtHoughCirclesMaxRadius.Text);
             StringBuilder sbResult = new StringBuilder();
             //計算
             Stopwatch sw = new Stopwatch();
             sw.Start();
             CircleF[][] circles =  imageSourceGrayscale.HoughCircles(new Gray(param1), new Gray(param2), dp,  minDist, minRadius, maxRadius);
             sw.Stop();
             //顯示
             Image<Bgr, Byte> imageResult =  imageSourceGrayscale.Convert<Bgr, Byte>();
             int circlesCount = 0;
             foreach (CircleF[] cs in circles)
             {
                 foreach (CircleF circle in cs)
                 {
                     imageResult.Draw(circle, new Bgr (255d, 0d, 0d), 4);
                     sbResult.AppendFormat("圓心{0}半徑{1} ,", circle.Center, circle.Radius);
                     circlesCount++;
                 }
             }
             pbResult.Image = imageResult.Bitmap;
             //釋放資源
             imageResult.Dispose();
             //返回
             return string.Format("·霍夫圓變換,用時{0:F05}毫秒 ,參數(累加器圖像的最小分辨率:{1},不同圓之間的最小距離:{2},邊緣閥值:{3}, 累加器閥值:{4},最小圓半徑:{5},最大圓半徑:{6}),找到{7}個圓\r\n{8}",
                 sw.Elapsed.TotalMilliseconds, dp, minDist,  param1, param2, minRadius, maxRadius, circlesCount, sbResult.Length >  0 ? (sbResult.ToString() + "\r\n") : "");
         }

Harris角點

cvCornerHarris函數檢測的結果實際上是一幅包含Harris角點的浮點型單通道圖像,可 以使用類似下面的代碼來計算包含Harris角點的圖像:

Harris角點

private string CornerHarrisFeatureDetect()
         {
             //獲取參數
             int blockSize = int.Parse (txtCornerHarrisBlockSize.Text);
             int apertureSize = int.Parse (txtCornerHarrisApertureSize.Text);
             double k = double.Parse (txtCornerHarrisK.Text);
             //計算
             Image<Gray, Single> imageDest = new  Image<Gray, float>(imageSourceGrayscale.Size);
             Stopwatch sw = new Stopwatch();
             sw.Start();
             CvInvoke.cvCornerHarris(imageSourceGrayscale.Ptr,  imageDest.Ptr, blockSize, apertureSize, k);
             sw.Stop();
             //顯示
             pbResult.Image = imageDest.Bitmap;
             //釋放資源
             imageDest.Dispose();
             //返回
             return string.Format("·Harris角點,用時{0:F05}毫秒 ,參數(鄰域大小:{1},方形濾波器寬度:{2},權重系數:{3})\r\n",  sw.Elapsed.TotalMilliseconds, blockSize, apertureSize, k);
         }

如果要計算Harris角點列表,需要使用cvGoodFeatureToTrack函數,並傳遞適當的參數 。

ShiTomasi角點

在默認情況下,cvGoodFeatureToTrack函數計算ShiTomasi角點;不過如果將參數 use_harris設置為非0值,那麼它會計算harris角點。

使用cvGoodFeatureToTrack函數的示例代碼如下:

ShiTomasi角點

private string CornerShiTomasiFeatureDetect()
         {
             //獲取參數
             int cornerCount = int.Parse (txtGoodFeaturesCornerCount.Text);
             double qualityLevel = double.Parse (txtGoodFeaturesQualityLevel.Text);
             double minDistance = double.Parse (txtGoodFeaturesMinDistance.Text);
             int blockSize = int.Parse (txtGoodFeaturesBlockSize.Text);
             bool useHarris =  cbGoodFeaturesUseHarris.Checked;
             double k = double.Parse (txtGoodFeaturesK.Text);
             //計算
             Stopwatch sw = new Stopwatch();
             sw.Start();
             PointF[][] corners =  imageSourceGrayscale.GoodFeaturesToTrack(cornerCount, qualityLevel,  minDistance, blockSize, useHarris, k);
             sw.Stop();
             //顯示
             Image<Bgr, Byte> imageResult =  imageSourceGrayscale.Convert<Bgr, Byte>();
             int cornerCount2 = 0;
             StringBuilder sbResult = new StringBuilder();
             int radius = (int)(minDistance / 2) + 1;
             int thickness = (int)(minDistance / 4) +  1;
             foreach (PointF[] cs in corners)
             {
                 foreach (PointF p in cs)
                 {
                     imageResult.Draw(new CircleF(p,  radius), new Bgr(255d, 0d, 0d), thickness);
                     cornerCount2++;
                     sbResult.AppendFormat("{0},",  p);
                 }
             }
             pbResult.Image = imageResult.Bitmap;
             //釋放資源
             imageResult.Dispose();
             //返回
             return string.Format("·ShiTomasi角點,用時{0:F05}毫 秒,參數(最大角點數目:{1},最小特征值:{2},角點間的最小距離:{3},鄰域大小: {4},角點類型:{5},權重系數:{6}),檢測到{7}個角點\r\n{8}",
                 sw.Elapsed.TotalMilliseconds, cornerCount,  qualityLevel, minDistance, blockSize, useHarris ? "Harris" : "ShiTomasi",  k, cornerCount2, cornerCount2 > 0 ? (sbResult.ToString() + "\r\n")  : "");
         }

亞像素級角點

在檢測亞像素級角點前,需要提供角點的初始為止,這些初始位置可以用本文給出的其 他的角點檢測方式來獲取,不過使用GoodFeaturesToTrack得到的結果最方便直接使用。

亞像素級角點檢測的示例代碼如下:

亞像素級角點

private string CornerSubPixFeatureDetect()
         {
             //獲取參數
             int winWidth = int.Parse (txtCornerSubPixWinWidth.Text);
             int winHeight = int.Parse (txtCornerSubPixWinHeight.Text);
             Size win = new Size(winWidth, winHeight);
             int zeroZoneWidth = int.Parse (txtCornerSubPixZeroZoneWidth.Text);
             int zeroZoneHeight = int.Parse (txtCornerSubPixZeroZoneHeight.Text);
             Size zeroZone = new Size(zeroZoneWidth,  zeroZoneHeight);
             int maxIter=int.Parse (txtCornerSubPixMaxIter.Text);
             double epsilon=double.Parse (txtCornerSubPixEpsilon.Text);
             MCvTermCriteria criteria = new MCvTermCriteria (maxIter, epsilon);
             //先計算得到易於跟蹤的點(ShiTomasi角點)
             int cornerCount = int.Parse (txtGoodFeaturesCornerCount.Text);
             double qualityLevel = double.Parse (txtGoodFeaturesQualityLevel.Text);
             double minDistance = double.Parse (txtGoodFeaturesMinDistance.Text);
             int blockSize = int.Parse (txtGoodFeaturesBlockSize.Text);
             bool useHarris =  cbGoodFeaturesUseHarris.Checked;
             double k = double.Parse (txtGoodFeaturesK.Text);
             PointF[][] corners =  imageSourceGrayscale.GoodFeaturesToTrack(cornerCount, qualityLevel,  minDistance, blockSize, useHarris, k);
             //計算
             Stopwatch sw = new Stopwatch();
             sw.Start();
             imageSourceGrayscale.FindCornerSubPix(corners, win,  zeroZone, criteria);
             sw.Stop();
             //顯示
             Image<Bgr, Byte> imageResult =  imageSourceGrayscale.Convert<Bgr, Byte>();
             int cornerCount2 = 0;
             StringBuilder sbResult = new StringBuilder();
             int radius = (int)(minDistance / 2) + 1;
             int thickness = (int)(minDistance / 4) +  1;
             foreach (PointF[] cs in corners)
             {
                 foreach (PointF p in cs)
                 {
                     imageResult.Draw(new CircleF(p,  radius), new Bgr(255d, 0d, 0d), thickness);
                     cornerCount2++;
                     sbResult.AppendFormat("{0},",  p);
                 }
             }
             pbResult.Image = imageResult.Bitmap;
             //釋放資源
             imageResult.Dispose();
             //返回
             return string.Format("·亞像素級角點,用時{0:F05}毫 秒,參數(搜索窗口:{1},死區:{2},最大迭代次數:{3},亞像素值的精度:{4}),檢 測到{5}個角點\r\n{6}",
                 sw.Elapsed.TotalMilliseconds, win,  zeroZone, maxIter, epsilon, cornerCount2, cornerCount2 > 0 ?  (sbResult.ToString() + "\r\n") : "");
         }

SURF角點

OpenCv中的cvExtractSURF函數和EmguCv中的Image<TColor,TDepth>.ExtractSURF 方法用於檢測SURF角點。

SURF角點檢測的示例代碼如下:

SURF角點

private string SurfFeatureDetect()
         {
             //獲取參數
             bool getDescriptors =  cbSurfGetDescriptors.Checked;
             MCvSURFParams surfParam = new MCvSURFParams ();
             surfParam.extended=rbSurfBasicDescriptor.Checked ?  0 : 1;
             surfParam.hessianThreshold=double.Parse (txtSurfHessianThreshold.Text);
             surfParam.nOctaves=int.Parse (txtSurfNumberOfOctaves.Text);
             surfParam.nOctaveLayers=int.Parse (txtSurfNumberOfOctaveLayers.Text);
             //計算
             SURFFeature[] features = null;
             MKeyPoint[] keyPoints = null;
             Stopwatch sw = new Stopwatch();
             sw.Start();
             if (getDescriptors)
                 features =  imageSourceGrayscale.ExtractSURF(ref surfParam);
             else
                 keyPoints = surfParam.DetectKeyPoints (imageSourceGrayscale, null);
             sw.Stop();
             //顯示
             bool showDetail = cbSurfShowDetail.Checked;
             Image<Bgr, Byte> imageResult =  imageSourceGrayscale.Convert<Bgr, Byte>();
             StringBuilder sbResult = new StringBuilder();
             int idx = 0;
             if (getDescriptors)
             {
                 foreach (SURFFeature feature in  features)
                 {
                     imageResult.Draw(new CircleF (feature.Point.pt, 5), new Bgr(255d, 0d, 0d), 2);
                     if (showDetail)
                     {
                         sbResult.AppendFormat("第{0} 點(坐標:{1},尺寸:{2},方向:{3}°,hessian值:{4},拉普拉斯標志:{5},描述: [",
                             idx,  feature.Point.pt, feature.Point.size, feature.Point.dir,  feature.Point.hessian, feature.Point.laplacian);
                         foreach (float d in  feature.Descriptor)
                             sbResult.AppendFormat("{0},", d);
                         sbResult.Append("]),");
                     }
                     idx++;
                 }
             }
             else
             {
                 foreach (MKeyPoint keypoint in  keyPoints)
                 {
                     imageResult.Draw(new CircleF (keypoint.Point, 5), new Bgr(255d, 0d, 0d), 2);
                     if (showDetail)
                         sbResult.AppendFormat("第{0} 點(坐標:{1},尺寸:{2},方向:{3}°,響應:{4},octave:{5}),",
                             idx, keypoint.Point,  keypoint.Size, keypoint.Angle, keypoint.Response, keypoint.Octave);
                     idx++;
                 }
             }
             pbResult.Image = imageResult.Bitmap;
             //釋放資源
             imageResult.Dispose();
             //返回
             return string.Format("·SURF角點,用時{0:F05}毫秒, 參數(描述:{1},hessian閥值:{2},octave數目:{3},每個octave的層數:{4},檢測 到{5}個角點\r\n{6}",
                 sw.Elapsed.TotalMilliseconds, getDescriptors  ? (surfParam.extended == 0 ? "獲取基本描述" : "獲取擴展描述") : "不獲 取描述", surfParam.hessianThreshold,
                 surfParam.nOctaves, surfParam.nOctaveLayers,  getDescriptors ? features.Length : keyPoints.Length, showDetail ?  sbResult.ToString() + "\r\n" : "");
         }

Star關鍵點

OpenCv中的cvGetStarKeypoints函數和EmguCv中的 Image<TColor,TDepth>.GetStarKeypoints方法用於檢測“星型”附近的點。

Star關鍵點檢測的示例代碼如下:

Star關鍵點

private string StarKeyPointFeatureDetect()
         {
             //獲取參數
             StarDetector starParam = new StarDetector();
             starParam.MaxSize = int.Parse((string) cmbStarMaxSize.SelectedItem);
             starParam.ResponseThreshold = int.Parse (txtStarResponseThreshold.Text);
             starParam.LineThresholdProjected = int.Parse (txtStarLineThresholdProjected.Text);
             starParam.LineThresholdBinarized = int.Parse (txtStarLineThresholdBinarized.Text);
             starParam.SuppressNonmaxSize = int.Parse (txtStarSuppressNonmaxSize.Text);
             //計算
             Stopwatch sw = new Stopwatch();
             sw.Start();
             MCvStarKeypoint[] keyPoints =  imageSourceGrayscale.GetStarKeypoints(ref starParam);
             sw.Stop();
             //顯示
             Image<Bgr, Byte> imageResult =  imageSourceGrayscale.Convert<Bgr, Byte>();
             StringBuilder sbResult = new StringBuilder();
             int idx = 0;
             foreach (MCvStarKeypoint keypoint in keyPoints)
             {
                 imageResult.Draw(new CircleF(new PointF (keypoint.pt.X, keypoint.pt.Y), keypoint.size / 2), new Bgr(255d, 0d,  0d), keypoint.size / 4);
                 sbResult.AppendFormat("第{0}點(坐標:{1},尺 寸:{2},強度:{3}),", idx, keypoint.pt, keypoint.size,  keypoint.response);
                 idx++;
             }
             pbResult.Image = imageResult.Bitmap;
             //釋放資源
             imageResult.Dispose();
             //返回
             return string.Format("·Star關鍵點,用時{0:F05}毫秒 ,參數(MaxSize:{1},ResponseThreshold:{2},LineThresholdProjected:{3}, LineThresholdBinarized:{4},SuppressNonmaxSize:{5}),檢測到{6}個關鍵點\r\n {7}",
                 sw.Elapsed.TotalMilliseconds,  starParam.MaxSize, starParam.ResponseThreshold,  starParam.LineThresholdProjected, starParam.LineThresholdBinarized,  starParam.SuppressNonmaxSize, keyPoints.Length, keyPoints.Length > 0 ?  (sbResult.ToString() + "\r\n") : "");
         }

源碼:http://files.cnblogs.com/xrwang/特征檢測 .rar

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved