建網(wǎng)站需要多錢網(wǎng)站建設使用的工具
鶴壁市浩天電氣有限公司
2026/01/24 10:39:42
建網(wǎng)站需要多錢,網(wǎng)站建設使用的工具,正邦品牌設計公司簡介,百度為什么不收錄我的網(wǎng)站概述前面已經(jīng)介紹過了OpenCV中的很多特征檢測算法#xff0c;但是好像還不太清楚具體是怎么使用的#xff0c;今天以一個完整的例子介紹具體如何使用這些特征檢測算法。效果#xff1a;實踐讀取兩張圖像#xff1a;// 讀取圖像using var img1 new Mat(FirstImagePath, Imr…概述前面已經(jīng)介紹過了OpenCV中的很多特征檢測算法但是好像還不太清楚具體是怎么使用的今天以一個完整的例子介紹具體如何使用這些特征檢測算法。效果實踐讀取兩張圖像// 讀取圖像 using var img1 new Mat(FirstImagePath, ImreadModes.Color); using var img2 new Mat(SecondImagePath, ImreadModes.Color);檢測關(guān)鍵點和計算描述符:using var descriptors1 new Mat(); usingvar descriptors2 new Mat(); usingvar matcher new BFMatcher(NormTypes.L2SQR); usingvar kaze KAZE.Create(); // 檢測關(guān)鍵點和計算描述符 kaze.DetectAndCompute(img1, null, outvar keypoints1, descriptors1); kaze.DetectAndCompute(img2, null, outvar keypoints2, descriptors2);使用KNN匹配:// 使用KNN匹配 DMatch[][] matches matcher.KnnMatch(descriptors1, descriptors2, 2);KNNK-近鄰匹配是一種基于特征點的圖像匹配算法它通過計算兩幅圖像中特征點之間的距離為每個特征點找到K個最相似的特征點作為候選匹配對然后使用比率測試或其他篩選方法來消除錯誤匹配最終實現(xiàn)圖像間的特征點對應關(guān)系建立廣泛應用于圖像拼接、目標識別和三維重建等計算機視覺任務中。前面我們創(chuàng)建了一個暴力匹配器(Brute-Force Matcher)的實例用于特征點匹配。NormTypes.L2SQR參數(shù)指定了距離計算方式為歐幾里得距離的平方(L2距離的平方)這種距離度量適用于SIFT、SURF等特征描述符。查看KnnMatch的函數(shù)簽名public DMatch[][] KnnMatch(Mat queryDescriptors, Mat trainDescriptors, int k, Mat? mask null, bool compactResult false)這個KnnMatch函數(shù)是OpenCV中用于執(zhí)行K近鄰特征匹配的核心方法它為查詢描述符集合中的每個描述符找到訓練描述符集合中距離最近的k個匹配項。函數(shù)返回一個二維數(shù)組DMatch[][]其中每個子數(shù)組包含對應查詢描述符的k個最佳匹配結(jié)果按距離從小到大排序。KnnMatch函數(shù)參數(shù)說明:參數(shù)名類型說明queryDescriptorsMat查詢圖像的特征描述符矩陣每一行代表一個特征點的描述符trainDescriptorsMat訓練圖像的特征描述符矩陣用于與查詢描述符進行匹配kint為每個查詢描述符要查找的最佳匹配數(shù)量maskMat?可選掩碼矩陣用于指定哪些描述符對參與匹配null表示全部參與compactResultbool決定是否壓縮結(jié)果false時結(jié)果數(shù)組大小與查詢描述符行數(shù)相同true時排除完全被掩碼的查詢描述符得到的結(jié)果如下所示進行投票唯一性// 投票唯一性 VoteForUniqueness(matches, mask); int nonZero Cv2.CountNonZero(mask); private static void VoteForUniqueness(DMatch[][] matches, Mat mask, float uniqnessThreshold 0.80f) { var maskData newbyte[matches.Length]; var maskHandle GCHandle.Alloc(maskData, GCHandleType.Pinned); using (var m Mat.FromPixelData(matches.Length, 1, MatType.CV_8U, maskHandle.AddrOfPinnedObject())) { mask.CopyTo(m); for (int i 0; i matches.Length; i) { // 這也被稱為NNDR最近鄰距離比率 if ((matches[i][0].Distance / matches[i][1].Distance) uniqnessThreshold) maskData[i] 255; else maskData[i] 0; } m.CopyTo(mask); } maskHandle.Free(); }這段代碼實現(xiàn)了特征匹配中的唯一性投票機制也稱為NNDR(最近鄰距離比率)測試用于篩選出可靠的匹配對。對每個查詢特征點的KNN匹配結(jié)果進行唯一性檢驗,通過比較最佳匹配與次佳匹配的距離比率來判斷匹配的可靠性,默認閾值為0.80f這是經(jīng)驗值可根據(jù)應用場景調(diào)整。進一步過濾KNN匹配結(jié)果// 投票大小和方向 nonZero VoteForSizeAndOrientation(keypoints2, keypoints1, matches, mask, 1.5f, 20); static int VoteForSizeAndOrientation(KeyPoint[] modelKeyPoints, KeyPoint[] observedKeyPoints, DMatch[][] matches, Mat mask, float scaleIncrement, int rotationBins) { int idx 0; int nonZeroCount 0; byte[] maskMat newbyte[mask.Rows]; GCHandle maskHandle GCHandle.Alloc(maskMat, GCHandleType.Pinned); using (Mat m Mat.FromPixelData(mask.Rows, 1, MatType.CV_8U, maskHandle.AddrOfPinnedObject())) { mask.CopyTo(m); Listfloat logScale new Listfloat(); Listfloat rotations new Listfloat(); double s, maxS, minS, r; maxS -1.0e-10f; minS 1.0e10f; // 如果在這里得到異常那是因為你傳入的模型和觀察關(guān)鍵點順序錯誤。只需切換順序。 for (int i 0; i maskMat.Length; i) { if (maskMat[i] 0) { KeyPoint observedKeyPoint observedKeyPoints[i]; KeyPoint modelKeyPoint modelKeyPoints[matches[i][0].TrainIdx]; s Math.Log10(observedKeyPoint.Size / modelKeyPoint.Size); logScale.Add((float)s); maxS s maxS ? s : maxS; minS s minS ? s : minS; r observedKeyPoint.Angle - modelKeyPoint.Angle; r r 0.0f ? r 360.0f : r; rotations.Add((float)r); } } int scaleBinSize (int)Math.Ceiling((maxS - minS) / Math.Log10(scaleIncrement)); if (scaleBinSize 2) scaleBinSize 2; float[] scaleRanges { (float)minS, (float)(minS scaleBinSize Math.Log10(scaleIncrement)) }; usingvar scalesMat Mat.FromArray(logScale.ToArray()); usingvar rotationsMat Mat.FromArray(rotations.ToArray()); usingvar flagsMat new Matfloat(logScale.Count, 1); using Mat hist new Mat(); flagsMat.SetTo(new Scalar(0.0f)); float[] flagsMatFloat1 flagsMat.ToArray(); int[] histSize { scaleBinSize, rotationBins }; float[] rotationRanges { 0.0f, 360.0f }; int[] channels { 0, 1 }; Rangef[] ranges { new Rangef(scaleRanges[0], scaleRanges[1]), new Rangef(rotations.Min(), rotations.Max()) }; Mat[] arrs { scalesMat, rotationsMat }; Cv2.CalcHist(arrs, channels, null, hist, 2, histSize, ranges); Cv2.MinMaxLoc(hist, outdouble minVal, outdouble maxVal); Cv2.Threshold(hist, hist, maxVal * 0.5, 0, ThresholdTypes.Tozero); Cv2.CalcBackProject(arrs, channels, hist, flagsMat, ranges); MatIndexerfloat flagsMatIndexer flagsMat.GetIndexer(); for (int i 0; i maskMat.Length; i) { if (maskMat[i] 0) { if (flagsMatIndexer[idx] ! 0.0f) { nonZeroCount; } else maskMat[i] 0; } } m.CopyTo(mask); } maskHandle.Free(); return nonZeroCount; }通過分析匹配對之間的尺度變化和旋轉(zhuǎn)角度一致性來評估匹配質(zhì)量。獲取匹配點// 收集好的匹配點 ListPoint2f obj new ListPoint2f(); ListPoint2f scene new ListPoint2f(); ListDMatch goodMatchesList new ListDMatch(); // 遍歷掩碼只提取非零項因為它們是匹配項 for (int i 0; i mask.Rows; i) { MatIndexerbyte maskIndexer mask.GetGenericIndexerbyte(); if (maskIndexer[i] 0) { obj.Add(keypoints1[matches[i][0].QueryIdx].Pt); scene.Add(keypoints2[matches[i][0].TrainIdx].Pt); goodMatchesList.Add(matches[i][0]); } } // 轉(zhuǎn)換點類型 ListPoint2d objPts obj.ConvertAll(Point2fToPoint2d); ListPoint2d scenePts scene.ConvertAll(Point2fToPoint2d); private static Point2d Point2fToPoint2d(Point2f pf) { returnnew Point2d(((int)pf.X), ((int)pf.Y)); }繪制結(jié)果圖像// 計算單應性矩陣 Mat homography Cv2.FindHomography(objPts, scenePts, HomographyMethods.Ransac, 1.5, mask); nonZero Cv2.CountNonZero(mask); if (homography ! null) { // 定義對象角點 Point2f[] objCorners { new Point2f(0, 0), new Point2f(img1.Cols, 0), new Point2f(img1.Cols, img1.Rows), new Point2f(0, img1.Rows) }; // 透視變換 Point2d[] sceneCorners MyPerspectiveTransform3(objCorners, homography); // 創(chuàng)建拼接圖像 using Mat img3 new Mat(Math.Max(img1.Height, img2.Height), img2.Width img1.Width, MatType.CV_8UC3); using Mat left new Mat(img3, new Rect(0, 0, img1.Width, img1.Height)); using Mat right new Mat(img3, new Rect(img1.Width, 0, img2.Width, img2.Height)); img1.CopyTo(left); img2.CopyTo(right); // 獲取掩碼數(shù)組 mask.GetArray(outbyte[] maskBytes); // 繪制匹配 Cv2.DrawMatches(img1, keypoints1, img2, keypoints2, goodMatchesList, img3, Scalar.All(-1), Scalar.All(-1), maskBytes, DrawMatchesFlags.NotDrawSinglePoints); // 繪制檢測到的對象邊界 ListListPoint listOfListOfPoint2D new ListListPoint(); ListPoint listOfPoint2D new ListPoint { new Point(sceneCorners[0].X img1.Cols, sceneCorners[0].Y), new Point(sceneCorners[1].X img1.Cols, sceneCorners[1].Y), new Point(sceneCorners[2].X img1.Cols, sceneCorners[2].Y), new Point(sceneCorners[3].X img1.Cols, sceneCorners[3].Y) }; listOfListOfPoint2D.Add(listOfPoint2D); img3.Polylines(listOfListOfPoint2D, true, Scalar.LimeGreen, 2);