旅游網(wǎng)站的導(dǎo)航怎么做做網(wǎng)站需要每年都繳費(fèi)嗎
鶴壁市浩天電氣有限公司
2026/01/24 19:08:01
旅游網(wǎng)站的導(dǎo)航怎么做,做網(wǎng)站需要每年都繳費(fèi)嗎,網(wǎng)頁(yè)設(shè)計(jì)需要學(xué)什么東西,英德市網(wǎng)站建設(shè)概述前面已經(jīng)介紹過(guò)了OpenCV中的很多特征檢測(cè)算法#xff0c;但是好像還不太清楚具體是怎么使用的#xff0c;今天以一個(gè)完整的例子介紹具體如何使用這些特征檢測(cè)算法。效果#xff1a;實(shí)踐讀取兩張圖像#xff1a;// 讀取圖像using var img1 new Mat(FirstImagePath, Imr…概述前面已經(jīng)介紹過(guò)了OpenCV中的很多特征檢測(cè)算法但是好像還不太清楚具體是怎么使用的今天以一個(gè)完整的例子介紹具體如何使用這些特征檢測(cè)算法。效果實(shí)踐讀取兩張圖像// 讀取圖像 using var img1 new Mat(FirstImagePath, ImreadModes.Color); using var img2 new Mat(SecondImagePath, ImreadModes.Color);檢測(cè)關(guān)鍵點(diǎn)和計(jì)算描述符:using var descriptors1 new Mat(); usingvar descriptors2 new Mat(); usingvar matcher new BFMatcher(NormTypes.L2SQR); usingvar kaze KAZE.Create(); // 檢測(cè)關(guān)鍵點(diǎn)和計(jì)算描述符 kaze.DetectAndCompute(img1, null, outvar keypoints1, descriptors1); kaze.DetectAndCompute(img2, null, outvar keypoints2, descriptors2);使用KNN匹配:// 使用KNN匹配 DMatch[][] matches matcher.KnnMatch(descriptors1, descriptors2, 2);KNNK-近鄰匹配是一種基于特征點(diǎn)的圖像匹配算法它通過(guò)計(jì)算兩幅圖像中特征點(diǎn)之間的距離為每個(gè)特征點(diǎn)找到K個(gè)最相似的特征點(diǎn)作為候選匹配對(duì)然后使用比率測(cè)試或其他篩選方法來(lái)消除錯(cuò)誤匹配最終實(shí)現(xiàn)圖像間的特征點(diǎn)對(duì)應(yīng)關(guān)系建立廣泛應(yīng)用于圖像拼接、目標(biāo)識(shí)別和三維重建等計(jì)算機(jī)視覺(jué)任務(wù)中。前面我們創(chuàng)建了一個(gè)暴力匹配器(Brute-Force Matcher)的實(shí)例用于特征點(diǎn)匹配。NormTypes.L2SQR參數(shù)指定了距離計(jì)算方式為歐幾里得距離的平方(L2距離的平方)這種距離度量適用于SIFT、SURF等特征描述符。查看KnnMatch的函數(shù)簽名public DMatch[][] KnnMatch(Mat queryDescriptors, Mat trainDescriptors, int k, Mat? mask null, bool compactResult false)這個(gè)KnnMatch函數(shù)是OpenCV中用于執(zhí)行K近鄰特征匹配的核心方法它為查詢描述符集合中的每個(gè)描述符找到訓(xùn)練描述符集合中距離最近的k個(gè)匹配項(xiàng)。函數(shù)返回一個(gè)二維數(shù)組DMatch[][]其中每個(gè)子數(shù)組包含對(duì)應(yīng)查詢描述符的k個(gè)最佳匹配結(jié)果按距離從小到大排序。KnnMatch函數(shù)參數(shù)說(shuō)明:參數(shù)名類型說(shuō)明queryDescriptorsMat查詢圖像的特征描述符矩陣每一行代表一個(gè)特征點(diǎn)的描述符trainDescriptorsMat訓(xùn)練圖像的特征描述符矩陣用于與查詢描述符進(jìn)行匹配kint為每個(gè)查詢描述符要查找的最佳匹配數(shù)量maskMat?可選掩碼矩陣用于指定哪些描述符對(duì)參與匹配null表示全部參與compactResultbool決定是否壓縮結(jié)果false時(shí)結(jié)果數(shù)組大小與查詢描述符行數(shù)相同true時(shí)排除完全被掩碼的查詢描述符得到的結(jié)果如下所示進(jìn)行投票唯一性// 投票唯一性 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(); }這段代碼實(shí)現(xiàn)了特征匹配中的唯一性投票機(jī)制也稱為NNDR(最近鄰距離比率)測(cè)試用于篩選出可靠的匹配對(duì)。對(duì)每個(gè)查詢特征點(diǎn)的KNN匹配結(jié)果進(jìn)行唯一性檢驗(yàn),通過(guò)比較最佳匹配與次佳匹配的距離比率來(lái)判斷匹配的可靠性,默認(rèn)閾值為0.80f這是經(jīng)驗(yàn)值可根據(jù)應(yīng)用場(chǎng)景調(diào)整。進(jìn)一步過(guò)濾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; // 如果在這里得到異常那是因?yàn)槟銈魅氲哪P秃陀^察關(guān)鍵點(diǎn)順序錯(cuò)誤。只需切換順序。 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; }通過(guò)分析匹配對(duì)之間的尺度變化和旋轉(zhuǎn)角度一致性來(lái)評(píng)估匹配質(zhì)量。獲取匹配點(diǎn)// 收集好的匹配點(diǎn) ListPoint2f obj new ListPoint2f(); ListPoint2f scene new ListPoint2f(); ListDMatch goodMatchesList new ListDMatch(); // 遍歷掩碼只提取非零項(xiàng)因?yàn)樗鼈兪瞧ヅ漤?xiàng) 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)換點(diǎ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é)果圖像// 計(jì)算單應(yīng)性矩陣 Mat homography Cv2.FindHomography(objPts, scenePts, HomographyMethods.Ransac, 1.5, mask); nonZero Cv2.CountNonZero(mask); if (homography ! null) { // 定義對(duì)象角點(diǎn) 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); // 繪制檢測(cè)到的對(duì)象邊界 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);