/// <summary> /// 建構子 /// </summary> /// <param name="indices"></param> /// <param name="homography">用來繪製ROI的矩陣</param> /// <param name="mask"></param> /// <param name="matchedCount">匹配點</param> /// <param name="template">樣板特徵類別</param> public SURFMatchedData(Matrix <int> indices, HomographyMatrix homography, Matrix <byte> mask, int matchedCount, SURFFeatureData template) { this.indices = indices; this.homography = homography; this.mask = mask; this.matchedCount = matchedCount; this.templateSURFData = template; }
/// <summary> /// 顯示畫出匹配的視窗 /// </summary> /// <param name="matchData">匹配後回傳的資料類別</param> /// <param name="observedScene">觀察景象特徵資料</param> public static void ShowSURFMatchForm(SURFMatchedData matchData, SURFFeatureData observedScene) { PointF[] matchPts = GetMatchBoundingBox(matchData.GetHomography(), matchData.GetTemplateSURFData()); //Draw the matched keypoints Image <Bgr, Byte> result = Features2DToolbox.DrawMatches(matchData.GetTemplateSURFData().GetImg(), matchData.GetTemplateSURFData().GetKeyPoints(), observedScene.GetImg(), observedScene.GetKeyPoints(), matchData.GetIndices(), new Bgr(255, 255, 255), new Bgr(255, 255, 255), matchData.GetMask(), Features2DToolbox.KeypointDrawType.DEFAULT); if (matchPts != null) { result.DrawPolyline(Array.ConvertAll <PointF, Point>(matchPts, Point.Round), true, new Bgr(Color.Red), 2); } new ImageViewer(result, "顯示匹配圖像").Show(); }
/// <summary> /// 匹配較快速但精確度較低 /// </summary> /// <param name="template">樣板的特徵點類別</param> /// <param name="observedScene">被觀察的場景匹配的特徵點</param> /// <returns>回傳匹配的資料類別</returns> public static SURFMatchedData MatchSURFFeatureByFLANN(SURFFeatureData template, SURFFeatureData observedScene) { Matrix <byte> mask; int k = 2; double uniquenessThreshold = 0.3; Matrix <int> indices; HomographyMatrix homography = null; Stopwatch watch; Matrix <float> dists; try { watch = Stopwatch.StartNew(); #region FLANN Match CPU //match Index flann = new Index(template.GetDescriptors(), 4); indices = new Matrix <int>(observedScene.GetDescriptors().Rows, k); using (dists = new Matrix <float>(observedScene.GetDescriptors().Rows, k)) { flann.KnnSearch(observedScene.GetDescriptors(), indices, dists, k, 2); mask = new Matrix <byte>(dists.Rows, 1); mask.SetValue(255); Features2DToolbox.VoteForUniqueness(dists, uniquenessThreshold, mask); } int nonZeroCount = CvInvoke.cvCountNonZero(mask); Console.WriteLine("-----------------\nVoteForUniqueness pairCount => " + nonZeroCount.ToString() + "\n-----------------"); if (nonZeroCount >= 4) //原先是4 { nonZeroCount = Features2DToolbox.VoteForSizeAndOrientation(template.GetKeyPoints(), observedScene.GetKeyPoints(), indices, mask, 1.2, 30); Console.WriteLine("VoteForSizeAndOrientation pairCount => " + nonZeroCount.ToString() + "\n-----------------"); //filter out all unnecessary pairs based on distance between pairs if (nonZeroCount >= 30) //原先是4 { homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(template.GetKeyPoints(), observedScene.GetKeyPoints(), indices, mask, 5); //原先是5 } } #endregion watch.Stop(); Console.WriteLine("Cal SURF Match time => " + watch.ElapsedMilliseconds.ToString() + "\n-----------------"); return(new SURFMatchedData(indices, homography, mask, nonZeroCount, template)); } catch (CvException ex) { System.Windows.Forms.MessageBox.Show(ex.ErrorMessage); return(null); } }
/// <summary> /// 使用BruteForce匹配(較精確但較慢) /// </summary> /// <param name="template">樣板的特徵點類別</param> /// <param name="observedScene">被觀察的場景匹配的特徵點</param> /// <returns>回傳匹配的資料類別</returns> public static SURFMatchedData MatchSURFFeatureByBruteForce(SURFFeatureData template, SURFFeatureData observedScene) { Matrix <byte> mask; int k = 2; double uniquenessThreshold = 0.5; //default:0.8 Matrix <int> indices; HomographyMatrix homography = null; Stopwatch watch; try { watch = Stopwatch.StartNew(); #region bruteForce match for CPU //match BruteForceMatcher <float> matcher = new BruteForceMatcher <float>(DistanceType.L2Sqr); //default:L2 matcher.Add(template.GetDescriptors()); indices = new Matrix <int>(observedScene.GetDescriptors().Rows, k); using (Matrix <float> dist = new Matrix <float>(observedScene.GetDescriptors().Rows, k)) { matcher.KnnMatch(observedScene.GetDescriptors(), indices, dist, k, null); mask = new Matrix <byte>(dist.Rows, 1); mask.SetValue(255); Features2DToolbox.VoteForUniqueness(dist, uniquenessThreshold, mask); } int nonZeroCount = CvInvoke.cvCountNonZero(mask); Console.WriteLine("-----------------\nVoteForUniqueness pairCount => " + nonZeroCount.ToString() + "\n-----------------"); if (nonZeroCount >= 4) { nonZeroCount = Features2DToolbox.VoteForSizeAndOrientation(template.GetKeyPoints(), observedScene.GetKeyPoints(), indices, mask, 1.5, 30); //default:1.5 , 10, scale increment:1.5 rotatebin:50 Console.WriteLine("VoteForSizeAndOrientation pairCount => " + nonZeroCount.ToString() + "\n-----------------"); if (nonZeroCount >= 25) //defalut :4 , modify: 15 { homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(template.GetKeyPoints(), observedScene.GetKeyPoints(), indices, mask, 5); } } #endregion watch.Stop(); Console.WriteLine("Cal SURF Match time => " + watch.ElapsedMilliseconds.ToString() + "\n-----------------"); return(new SURFMatchedData(indices, homography, mask, nonZeroCount, template)); } catch (CvException ex) { System.Windows.Forms.MessageBox.Show(ex.ErrorMessage); return(null); } }
/// <summary> /// 取得對應出物體的ROI座標點 /// </summary> /// <param name="homography">保存了相關匹配後的資訊(用來投影至商品上的匹配位置)</param> /// <param name="template">樣板特徵類別</param> /// <returns>回傳座標點</returns> public static PointF[] GetMatchBoundingBox(HomographyMatrix homography, SURFFeatureData template) { if (homography != null) //Get RoI box { //draw a rectangle along the projected model PointF[] pts = new PointF[] { new PointF(template.GetImg().ROI.Left, template.GetImg().ROI.Bottom), new PointF(template.GetImg().ROI.Right, template.GetImg().ROI.Bottom), new PointF(template.GetImg().ROI.Right, template.GetImg().ROI.Top), new PointF(template.GetImg().ROI.Left, template.GetImg().ROI.Top) }; homography.ProjectPoints(pts); //project points return(pts); } else { return(null); } }