/// <summary> /// 获取优秀的匹配点 /// <para> /// 使用 "比较最近邻距离与次近邻距离的SIFT匹配方式" 和 "随机抽样一致(RANSAC)算法" 来进一步获取优秀匹配点 /// </para> /// </summary> /// <param name="matches"></param> /// <param name="argument"></param> /// <param name="sourceKeyPoints"></param> /// <param name="searchKeyPoints"></param> /// <returns></returns> private IList <DMatch> SelectGoodMatches(IEnumerable <DMatch[]> matches, FeatureMatchArgument argument, IList <KeyPoint> sourceKeyPoints, IList <KeyPoint> searchKeyPoints) { var sourcePoints = new List <Point2d>(); var searchPoints = new List <Point2d>(); var goodMatches = new List <DMatch>(); //比较最近邻距离与次近邻距离的SIFT匹配方式 foreach (var items in matches) { if (items.Length == 0) { continue; } if (argument.MatchPoints > 1 && (items.Length < 2 || items[0].Distance > argument.Ratio * items[1].Distance)) { continue; } //此处直接选择欧氏距离小的匹配关键点 var goodMatch = items[0]; goodMatches.Add(goodMatch); sourcePoints.Add(Point2FToPoint2D(sourceKeyPoints[goodMatch.QueryIdx].Pt)); searchPoints.Add(Point2FToPoint2D(searchKeyPoints[goodMatch.TrainIdx].Pt)); } argument.OutputDebugMessage($"[FeatureMatch] [SIFT] The number of good matching points is ({goodMatches.Count})."); //随机抽样一致(RANSAC)算法 (如果原始的匹配结果为空, 则跳过过滤步骤) if (sourcePoints.Count >= MinCorrespondingPointCount && searchPoints.Count >= MinCorrespondingPointCount) { var inliersMask = new Mat(); Cv2.FindHomography(sourcePoints, searchPoints, HomographyMethods.Ransac, argument.RansacThreshold, inliersMask); // 如果通过RANSAC处理后的匹配点大于10个,才应用过滤. 否则使用原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果). if (inliersMask.Rows > 10) { inliersMask.GetArray(out byte[] maskBytes); var inliers = new List <DMatch>(); for (var i = 0; i < maskBytes.Length; i++) { if (maskBytes[i] != 0) { inliers.Add(goodMatches[i]); } } argument.OutputDebugMessage($"[FeatureMatch] [SIFT] The number of good matching RANSAC points is ({inliers.Count})."); return(inliers); } } return(goodMatches); }
public override FeatureMatchResult Match(Mat sourceMat, Mat searchMat, FeatureMatchArgument argument) { //创建SIFT using var sift = SIFT.Create(); //创建特征点描述对象,为下边的特征点匹配做准备 using var sourceDescriptors = new Mat(); using var searchDescriptors = new Mat(); //提取特征点,并进行特征点描述 sift.DetectAndCompute(sourceMat, null, out var sourceKeyPoints, sourceDescriptors); sift.DetectAndCompute(searchMat, null, out var searchKeyPoints, searchDescriptors); //创建Brute-force descriptor matcher using var bfMatcher = new BFMatcher(); //对原图特征点描述加入训练 bfMatcher.Add(new List <Mat>() { sourceDescriptors }); bfMatcher.Train(); //获得匹配特征点,并提取最优配对 var matches = bfMatcher.KnnMatch(sourceDescriptors, searchDescriptors, (int)argument.MatchPoints); argument.OutputDebugMessage($"[FeatureMatch] [SIFT] The number of matching points is ({matches.Length})."); //即使使用SIFT算法,但此时没有经过点筛选的匹配效果同样糟糕,所进一步获取优秀匹配点 var goodMatches = SelectGoodMatches(matches, argument, sourceKeyPoints, searchKeyPoints); //获取匹配结果 var matchResult = GetMatchResult(goodMatches, sourceKeyPoints, searchKeyPoints); argument.OutputDebugMessage($"[FeatureMatch] [SIFT] The result of the match is ({matchResult.Success}) ({matchResult.MatchItems.Count})."); if (matchResult.Success) { var bestMatch = matchResult.MatchItems[0]; argument.OutputDebugMessage($"[FeatureMatch] [SIFT] The center point of the best match is ({bestMatch.Point}), and the rect is {bestMatch.Rectangle}."); } argument.PreviewDebugFeatureMatchResult(matchResult, sourceMat, searchMat, sourceKeyPoints, searchKeyPoints, goodMatches); return(matchResult); }