Java OpenCV-使用knnMatch和findHomography显示重复项

Java OpenCV-使用knnMatch和findHomography显示重复项,java,opencv,image-processing,opencv4android,Java,Opencv,Image Processing,Opencv4android,我是OpenCV java新手,我有一个android应用程序,它将使用ORB FeatureDetector和DescriptorExtractor匹配两幅图像。我使用描述符BRUTEFORCE_HAMMING。matcher一直在工作,但有时会显示关键点的副本。当场景中的图像太亮或太暗时,它会显示重复的关键点,这不是我想要的 精确匹配的图像: 不正确的图像匹配: 试试看{ bmpobjtorecognition=bmpobjtorecognition.copy(Bitmap.Config

我是OpenCV java新手,我有一个android应用程序,它将使用ORB FeatureDetector和DescriptorExtractor匹配两幅图像。我使用描述符BRUTEFORCE_HAMMING。matcher一直在工作,但有时会显示关键点的副本。当场景中的图像太亮或太暗时,它会显示重复的关键点,这不是我想要的

精确匹配的图像:

不正确的图像匹配:

试试看{
bmpobjtorecognition=bmpobjtorecognition.copy(Bitmap.Config.ARGB_8888,true);
bmpScene=bmpScene.copy(Bitmap.Config.ARGB_8888,true);
img1=新垫();
img2=新材料();
比特映射器(bmpobjtorecognition,img1);
比特映射器(bmpScene,img2);
Imgproc.cvt颜色(img1,img1,Imgproc.COLOR_RGBA2GRAY);
Imgproc.cvt颜色(img2,img2,Imgproc.COLOR_RGBA2GRAY);
Imgproc.equalizeHist(img1,img1);
Imgproc.equalizeHist(img2,img2);
detector=FeatureDetector.create(FeatureDetector.ORB);
descExtractor=DescriptorExtractor.create(DescriptorExtractor.ORB);
matcher=DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
keypoints1=新的MatOfKeyPoint();
keypoints2=新的MatOfKeyPoint();
描述符=新材料();
dupDescriptors=新Mat();
检测器。检测(img1,关键点1);
Log.d(“Log!”,“查询关键点的数量=“+keypoints1.size());
检测器。检测(img2,关键点2);
Log.d(“Log!”,“dup关键点的数量=“+keypoints2.size());
//描述关键点1
descExtractor.compute(img1,keypoints1,描述符);
descExtractor.compute(img2、keypoints2、DupDescriptor);
//匹配描述符
List knnMatches=new ArrayList();
matcher.knnMatch(描述符,DupDescriptor,knnMatches,DescriptorMatcher.BRUTEFORCE);
goodMatches=newarraylist();
knnMatchesValue=knnMatches.size();
Log.i(“xxx”、“xxx匹配计数knnMatches=“+knnMatches.size());
对于(int i=0;i1){
DMatch[]matches=knnMatches.get(i).toArray();
如果(匹配[0]。距离<0.89f*匹配[1]。距离){
添加(匹配项[0]);
}
}
}
//获取好匹配的关键点坐标,以查找单应性并使用ransac删除异常值
List pts1=new ArrayList();
List pts2=new ArrayList();
对于(int i=0;i

我是否缺少代码的一部分?

TL;DR显式使用类
BFMatcher
及其方法,然后您可以将
交叉检查
标志设置为true。这将启用您想要的“反之亦然检查”

引用
knnMatch
的OpenCV文档及其标题:

从查询集中为每个描述符查找k个最佳匹配项

因此,这意味着可能有多个“查询描述符”与“训练集”中的同一描述符匹配。它只提供了k个最佳值,如果查询描述符多于训练描述符,那么不可避免地会得到重复的查询描述符。特别是,当训练图像/集合中几乎没有特征和描述符时(由于缺少任何纹理,例如黑色输入),情况将是这样

如果要清除重复项,请将
BFMatcher
的“交叉检查”标志设置为true。否则(即其他匹配者),您需要通过各自的训练描述符对比赛进行“分组”,并删除除距离最小的比赛之外的所有比赛

try {
 bmpObjToRecognize = bmpObjToRecognize.copy(Bitmap.Config.ARGB_8888, true);
 bmpScene = bmpScene.copy(Bitmap.Config.ARGB_8888, true);

 img1 = new Mat();
 img2 = new Mat();
 Utils.bitmapToMat(bmpObjToRecognize, img1);
 Utils.bitmapToMat(bmpScene, img2);
 Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGBA2GRAY);
 Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGBA2GRAY);
 Imgproc.equalizeHist(img1, img1);
 Imgproc.equalizeHist(img2, img2);
 detector = FeatureDetector.create(FeatureDetector.ORB);
 descExtractor = DescriptorExtractor.create(DescriptorExtractor.ORB);
 matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);

 keypoints1 = new MatOfKeyPoint();
 keypoints2 = new MatOfKeyPoint();
 descriptors = new Mat();
 dupDescriptors = new Mat();

 detector.detect(img1, keypoints1);
 Log.d("LOG!", "number of query Keypoints= " + keypoints1.size());
 detector.detect(img2, keypoints2);
 Log.d("LOG!", "number of dup Keypoints= " + keypoints2.size());
  // Descript keypoints1
  descExtractor.compute(img1, keypoints1, descriptors);
  descExtractor.compute(img2, keypoints2, dupDescriptors);
  // matching descriptors
  List<MatOfDMatch> knnMatches = new ArrayList<>();
  matcher.knnMatch(descriptors, dupDescriptors, knnMatches, DescriptorMatcher.BRUTEFORCE);
  goodMatches = new ArrayList<>();
  knnMatchesValue = knnMatches.size();
  Log.i("xxx", "xxx match count knnMatches = " + knnMatches.size());
  for (int i = 0; i < knnMatches.size(); i++) {
   if (knnMatches.get(i).rows() > 1) {
    DMatch[] matches = knnMatches.get(i).toArray();
    if (matches[0].distance < 0.89f * matches[1].distance) {
     goodMatches.add(matches[0]);
    }
   }
  }

  // get keypoint coordinates of good matches to find homography and remove outliers using ransac
  List<Point> pts1 = new ArrayList<>();
  List<Point> pts2 = new ArrayList<>();
  for (int i = 0; i < goodMatches.size(); i++) {
   Point destinationPoint = keypoints2.toList().get(goodMatches.get(i).trainIdx).pt;
   pts1.add(keypoints1.toList().get(goodMatches.get(i).queryIdx).pt);
   pts2.add(destinationPoint);
  }

  // convertion of data types - there is maybe a more beautiful way
  Mat outputMask = new Mat();
  MatOfPoint2f pts1Mat = new MatOfPoint2f();
  pts1Mat.fromList(pts1);
  MatOfPoint2f pts2Mat = new MatOfPoint2f();
  pts2Mat.fromList(pts2);

  // Find homography - here just used to perform match filtering with RANSAC, but could be used to e.g. stitch images
  // the smaller the allowed reprojection error (here 15), the more matches are filtered
  Mat Homog = Calib3d.findHomography(pts1Mat, pts2Mat, Calib3d.RANSAC, 15, outputMask, 2000, 0.995);

  // outputMask contains zeros and ones indicating which matches are filtered
  better_matches = new LinkedList<>();
  for (int i = 0; i < goodMatches.size(); i++) {
   if (outputMask.get(i, 0)[0] != 0.0) {
    better_matches.add(goodMatches.get(i));
   }
  }

  matches_final_mat = new MatOfDMatch();
  matches_final_mat.fromList(better_matches);

  imgOutputMat = new Mat();
  MatOfByte drawnMatches = new MatOfByte();
  Features2d.drawMatches(img1, keypoints1, img2, keypoints2, matches_final_mat, 
   imgOutputMat, GREEN, RED, drawnMatches, Features2d.NOT_DRAW_SINGLE_POINTS);
  bmp = Bitmap.createBitmap(imgOutputMat.cols(), imgOutputMat.rows(), Bitmap.Config.ARGB_8888);
  Imgproc.cvtColor(imgOutputMat, imgOutputMat, Imgproc.COLOR_BGR2RGB);
  Utils.matToBitmap(imgOutputMat, bmp);
  List<DMatch> betterMatchesList = matches_final_mat.toList();
  final int matchesFound = betterMatchesList.size();


} catch (Exception e) {
 e.printStackTrace();
}
knnMatch(InputArray queryDescriptors, InputArray trainDescriptors, ...)