// Draw matches between two images public static Mat getMatchesImage(Mat query, Mat pattern, MatOfKeyPoint queryKp, MatOfKeyPoint trainKp, MatOfDMatch matches, int maxMatchesDrawn) { Mat outImg = new Mat(); List <DMatch> matchesList = matches.toList(); if (matchesList.Count > maxMatchesDrawn) { matchesList.RemoveRange(maxMatchesDrawn, matchesList.Count - maxMatchesDrawn); } MatOfDMatch tmpMatches = new MatOfDMatch(); tmpMatches.fromList(matchesList); Features2d.drawMatches ( query, queryKp, pattern, trainKp, tmpMatches, outImg, new Scalar(0, 200, 0, 255), Scalar.all(-1), new MatOfByte() ); return(outImg); }
/// <summary> /// Crosses the matcher. /// </summary> /// <returns>The matcher.</returns> /// <param name="queryDescriptors">Query descriptors.</param> /// <param name="trainDescriptors">Train descriptors.</param> public static IList <DMatch> CrossMatcher(MatOfFloat queryDescriptors, MatOfFloat trainDescriptors) { MatOfDMatch matchQT = new MatOfDMatch(), matchTQ = new MatOfDMatch(); List <DMatch> bmatch = new List <DMatch>(); DMatch[] dmatch; if (trainDescriptors.cols() <= 0) { throw new ApplicationException("CrossMatcherの引数trainDescriptorsがありません。"); } matcher.match(queryDescriptors, trainDescriptors, matchQT); if (queryDescriptors.cols() <= 0) { throw new ApplicationException("CrossMatcherの引数queryDescriptorsがありません。"); } matcher.match(trainDescriptors, queryDescriptors, matchTQ); for (int i = 0; i < matchQT.rows(); i++) { DMatch forward = matchQT.toList()[i]; DMatch backward = matchTQ.toList()[forward.trainIdx]; if (backward.trainIdx == forward.queryIdx) { bmatch.Add(forward); } } dmatch = bmatch.ToArray(); bmatch.Clear(); return(dmatch); }
/// <summary> /// Refines the matches with homography. /// </summary> /// <returns><c>true</c>, if matches with homography was refined, <c>false</c> otherwise.</returns> /// <param name="queryKeypoints">Query keypoints.</param> /// <param name="trainKeypoints">Train keypoints.</param> /// <param name="reprojectionThreshold">Reprojection threshold.</param> /// <param name="matches">Matches.</param> /// <param name="homography">Homography.</param> static bool refineMatchesWithHomography ( MatOfKeyPoint queryKeypoints, MatOfKeyPoint trainKeypoints, float reprojectionThreshold, MatOfDMatch matches, Mat homography ) { //Debug.Log ("matches " + matches.ToString ()); int minNumberMatchesAllowed = 8; List <KeyPoint> queryKeypointsList = queryKeypoints.toList(); List <KeyPoint> trainKeypointsList = trainKeypoints.toList(); List <DMatch> matchesList = matches.toList(); if (matchesList.Count < minNumberMatchesAllowed) { return(false); } // Prepare data for cv::findHomography List <Point> srcPointsList = new List <Point>(matchesList.Count); List <Point> dstPointsList = new List <Point>(matchesList.Count); for (int i = 0; i < matchesList.Count; i++) { srcPointsList.Add(trainKeypointsList[matchesList[i].trainIdx].pt); dstPointsList.Add(queryKeypointsList[matchesList[i].queryIdx].pt); } // Find homography matrix and get inliers mask using (MatOfPoint2f srcPoints = new MatOfPoint2f()) using (MatOfPoint2f dstPoints = new MatOfPoint2f()) using (MatOfByte inliersMask = new MatOfByte(new byte[srcPointsList.Count])) { srcPoints.fromList(srcPointsList); dstPoints.fromList(dstPointsList); //Debug.Log ("srcPoints " + srcPoints.ToString ()); //Debug.Log ("dstPoints " + dstPoints.ToString ()); Calib3d.findHomography(srcPoints, dstPoints, Calib3d.FM_RANSAC, reprojectionThreshold, inliersMask, 2000, 0.955).copyTo(homography); if (homography.rows() != 3 || homography.cols() != 3) { return(false); } //Debug.Log ("homography " + homography.ToString ()); //Debug.Log ("inliersMask " + inliersMask.dump ()); List <byte> inliersMaskList = inliersMask.toList(); List <DMatch> inliers = new List <DMatch>(); for (int i = 0; i < inliersMaskList.Count; i++) { if (inliersMaskList[i] == 1) { inliers.Add(matchesList[i]); } } matches.fromList(inliers); //Debug.Log ("matches " + matches.ToString ()); } return(matchesList.Count > minNumberMatchesAllowed); }
void Orb() { p1Mat = Imgcodecs.imread(Application.dataPath + "/Textures/1.jpg", 1); p2Mat = Imgcodecs.imread(Application.dataPath + "/Textures/3.jpg", 1); Imgproc.cvtColor(p1Mat, p1Mat, Imgproc.COLOR_BGR2RGB); Imgproc.cvtColor(p2Mat, p2Mat, Imgproc.COLOR_BGR2RGB); Imgproc.resize(p2Mat, p2Mat, new Size(p1Mat.width(), p1Mat.height())); Debug.Log(p2Mat); /* * //仿射变换(矩阵旋转) * float angle = UnityEngine.Random.Range(0, 360), scale = 1.0f; * Point center = new Point(img2Mat.cols() * 0.5f, img2Mat.rows() * 0.5f); * * Mat affine_matrix = Imgproc.getRotationMatrix2D(center, angle, scale); * Imgproc.warpAffine(img1Mat, img2Mat, affine_matrix, img2Mat.size()); * * Texture2D texture = new Texture2D(img2Mat.cols(), img2Mat.rows()); * Utils.matToTexture2D(img2Mat, texture); * outputRawImage.texture = texture; */ ORB detector = ORB.create(); ORB extractor = ORB.create(); //提取图一特征点 MatOfKeyPoint keypoints1 = new MatOfKeyPoint(); Mat descriptors1 = new Mat(); detector.detect(p1Mat, keypoints1); extractor.compute(p1Mat, keypoints1, descriptors1); //提取图二特征点 MatOfKeyPoint keypoints2 = new MatOfKeyPoint(); Mat descriptors2 = new Mat(); detector.detect(p2Mat, keypoints2); extractor.compute(p2Mat, keypoints2, descriptors2); //第一次匹配结果(密密麻麻) DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMINGLUT); MatOfDMatch matches = new MatOfDMatch(); matcher.match(descriptors1, descriptors2, matches); //筛选(非官方) //计算向量距离的最大值/最小值 double max_dist = 0; double min_dist = 15; //通过距离控制需要的特征。 //(设到10,最终只有2个耳朵匹配。。。) //(设到15,尾巴也开始匹配。。。。。。) //新建两个容器存放筛选样本 List <DMatch> matchesArray = matches.toList(); //用Unity版API多转一步 //Debug.Log(matchesArray.Count); //500 List <DMatch> goodmatchesArray = new List <DMatch>(); //Debug.Log(img1Mat.rows()); //512 for (int i = 0; i < matchesArray.Count; i++) { Debug.Log("[" + i + "]" + matchesArray[i].distance); if (matchesArray[i].distance > max_dist) { //max_dist = matchesArray[i].distance; } if (matchesArray[i].distance < min_dist) { min_dist = matchesArray[i].distance; } } //Debug.Log("The max distance is: " + max_dist); Debug.Log("The min distance is: " + min_dist); for (int i = 0; i < matchesArray.Count; i++) { if (matchesArray[i].distance < 2 * min_dist) // { goodmatchesArray.Add(matchesArray[i]); } } MatOfDMatch newMatches = new MatOfDMatch(); newMatches.fromList(goodmatchesArray); Debug.Log(newMatches.toList().Count); //第二次筛选后符合的 //绘制第二次筛选结果 dstMat = new Mat(); Features2d.drawMatches(p1Mat, keypoints1, p2Mat, keypoints2, newMatches, dstMat); Texture2D t2d = new Texture2D(dstMat.width(), dstMat.height()); Utils.matToTexture2D(dstMat, t2d); Sprite sp = Sprite.Create(t2d, new UnityEngine.Rect(0, 0, t2d.width, t2d.height), Vector2.zero); m_dstImage.sprite = sp; m_dstImage.preserveAspect = true; }