2015-05-16 4 views
0

Итак, я пытаюсь нарисовать прямоугольник вокруг изображения. Я нахожу суб изображение большего изображения, используя Open CV. Как я рассчитывал, он должен был преобразовать изображение шаблона (цель) и целевое изображение (сцену) в HSV и получить обратную проекцию объекта и сравнить его с насыщенным изображением сцены. Работает немного. (Был бы рад за любые улучшения). В принципе, я хочу нарисовать прямоугольник вокруг изображения и извлечь найденный прямоугольник из сцены в Mat. Я пробовал сделать это несколькими способами, но, похоже, не работает. Вот мой код. Мой вопрос в том, как получить суб изображение из целевого изображения?Обнаружение изображения Открыто CV

public List<DMatch> subListGoodMatches(List<DMatch> good_matches) { 
     Collections.sort(good_matches, (DMatch o1, DMatch o2) -> { 
      if (o1.distance < o2.distance) { 
       return -1; 
      } 
      if (o1.distance > o2.distance) { 
       return 1; 
      } 
      return 0; 
     }); 

     if (good_matches.size() > 10) { 
      good_matches = good_matches.subList(0, 10); 
     } 

     return good_matches; 
    } 

    public List<Mat> calculateHistograms(Mat image) { 
     Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2HSV); 

     List<Mat> hsv_planes = new ArrayList<Mat>(); 
     Core.split(image, hsv_planes); 

     MatOfInt histSize = new MatOfInt(256); 
     final MatOfFloat histRange = new MatOfFloat(0f, 256f); 
     boolean accumulate = true; 

     Mat h_hist = new Mat(); 
     Mat s_hist = new Mat(); 
     Mat v_hist = new Mat(); 

     //Break channels 
     List<Mat> h_plane = new ArrayList<Mat>(); 
     List<Mat> s_plane = new ArrayList<Mat>(); 
     List<Mat> v_plane = new ArrayList<Mat>(); 

     h_plane.add(hsv_planes.get(0)); 
     s_plane.add(hsv_planes.get(1)); 
     v_plane.add(hsv_planes.get(2)); 

     Imgproc.calcHist(h_plane, new MatOfInt(0), new Mat(), h_hist, histSize, histRange, accumulate); 
     Imgproc.calcHist(s_plane, new MatOfInt(0), new Mat(), s_hist, histSize, histRange, accumulate); 
     Imgproc.calcHist(v_plane, new MatOfInt(0), new Mat(), v_hist, histSize, histRange, accumulate); 

     //Draw combined histograms 
     int hist_w = 512; 
     int hist_h = 600; 
     long bin_w = Math.round((double) hist_w/256); 

     Mat histImage = new Mat(hist_h, hist_w, CvType.CV_8UC3, new Scalar(0, 0, 0)); 
     Core.normalize(h_hist, h_hist, 3, histImage.rows(), Core.NORM_MINMAX, -1, new Mat()); 
     Core.normalize(s_hist, s_hist, 3, histImage.rows(), Core.NORM_MINMAX, -1, new Mat()); 
     Core.normalize(v_hist, v_hist, 3, histImage.rows(), Core.NORM_MINMAX, -1, new Mat()); 

     for (int i = 1; i < 256; i++) { 
      Point p1 = new Point(bin_w * (i - 1), hist_h - Math.round(h_hist.get(i - 1, 0)[0])); 
      Point p2 = new Point(bin_w * (i), hist_h - Math.round(h_hist.get(i, 0)[0])); 
      Core.line(histImage, p1, p2, RED, 2, 8, 0); 

      Point p3 = new Point(bin_w * (i - 1), hist_h - Math.round(s_hist.get(i - 1, 0)[0])); 
      Point p4 = new Point(bin_w * (i), hist_h - Math.round(s_hist.get(i, 0)[0])); 
      Core.line(histImage, p3, p4, GREEN, 2, 8, 0); 

      Point p5 = new Point(bin_w * (i - 1), hist_h - Math.round(v_hist.get(i - 1, 0)[0])); 
      Point p6 = new Point(bin_w * (i), hist_h - Math.round(v_hist.get(i, 0)[0])); 
      Core.line(histImage, p5, p6, BLUE, 2, 8, 0); 

     } 

     Highgui.imwrite("img-histogram.jpg", histImage); 
     System.out.println("Hist size is: " + hsv_planes.size()); 

     List<Mat> histograms = new ArrayList<Mat>(); 
     histograms.add(h_hist); 
     histograms.add(s_hist); 
     histograms.add(v_hist); 

     return histograms; 
    } 

    public Mat identifyLowSat(Mat image) { 

     Mat hsvTargetImage = new Mat(); 
     Imgproc.cvtColor(image, hsvTargetImage, Imgproc.COLOR_BGR2HSV); 
     List<Mat> hsv_planes = new ArrayList<Mat>(); 
     Core.split(hsvTargetImage, hsv_planes); 

     //Get saturation channel 
     Mat s_hist = hsv_planes.get(1); 

     Imgproc.threshold(s_hist, s_hist, 65, 255, Imgproc.THRESH_BINARY); 

     Highgui.imwrite("img-saturation.png", s_hist); 

     return s_hist; 
    } 

    public Mat getBackProjOfHueTemplate(Mat image, Mat hue_histogram) { 

     Mat hsvTargetImage = new Mat(); 
     Imgproc.cvtColor(image, hsvTargetImage, Imgproc.COLOR_BGR2HSV); 
     List<Mat> hsv_planes = new ArrayList<Mat>(); 
     Core.split(hsvTargetImage, hsv_planes); 

     Mat backProj = new Mat(); 
     final MatOfFloat range = new MatOfFloat(0f, 256f); 

     Imgproc.calcBackProject(hsv_planes, new MatOfInt(0), hue_histogram, backProj, range, 4); 

     Highgui.imwrite("img-backProj.png", backProj); 

     return backProj; 
    } 

    public Mat meanShift(Mat image) { 
     Mat map = new Mat(); 
     Rect rect = new Rect(); 
     TermCriteria term = new TermCriteria(); 

     term.maxCount = 100; 
     term.type = TermCriteria.EPS; 
     term.epsilon = 0.1; 

     Imgproc.pyrMeanShiftFiltering(image, map, 0.5, 0.5, 5, term); 

     Highgui.imwrite("img-meanshift.png", map); 
     return map; 
    } 

    public MatOfDMatch filterMatches(Mat img1, Mat img2) { 

     FeatureDetector detector = FeatureDetector.create(FeatureDetector.SIFT); 
     DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.BRISK); 
     DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING); 

     // First photo 
     //Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGB2GRAY); 
     Mat descriptors1 = new Mat(); 
     MatOfKeyPoint keypoints1 = new MatOfKeyPoint(); 

     detector.detect(img1, keypoints1); 
     descriptor.compute(img1, keypoints1, descriptors1); 

     // Second photo 
     //Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGB2GRAY); 
     Mat descriptors2 = new Mat(); 
     MatOfKeyPoint keypoints2 = new MatOfKeyPoint(); 

     detector.detect(img2, keypoints2); 
     descriptor.compute(img2, keypoints2, descriptors2); 

     // Matching 
     MatOfDMatch matches = new MatOfDMatch(); 
     MatOfDMatch filteredMatches = new MatOfDMatch(); 
     matcher.match(descriptors1, descriptors2, matches); 

     List<DMatch> matchesList = matches.toList(); 
     Double max_dist = Double.MIN_VALUE; 
     Double min_dist = Double.POSITIVE_INFINITY; 

     for (DMatch matchesList1 : matchesList) { 
      Double dist = (double) matchesList1.distance; 
      if (dist < min_dist) { 
       min_dist = dist; 
      } 
      if (dist > max_dist) { 
       max_dist = dist; 
      } 
     } 

     LinkedList<DMatch> good_matches = new LinkedList<DMatch>(); 
     for (DMatch matchesList1 : matchesList) { 
      if (matchesList1.distance <= (1.5 * min_dist)) { 
       good_matches.addLast(matchesList1); 
      } 
     } 

     MatOfDMatch goodMatches = new MatOfDMatch(); 
     //goodMatches.fromList(good_matches); 
     List<DMatch> newGood_Matches = subListGoodMatches(good_matches); 
     goodMatches.fromList(newGood_Matches); 

     //put keypoints mats into lists 
     List<KeyPoint> keypoints1_List = keypoints1.toList(); 
     List<KeyPoint> keypoints2_List = keypoints2.toList(); 

     //put keypoints into point2f mats so calib3d can use them to find homography 
     LinkedList<Point> objList = new LinkedList<Point>(); 
     LinkedList<Point> sceneList = new LinkedList<Point>(); 
     for (int i = 0; i < newGood_Matches.size(); i++) { 
      objList.addLast(keypoints2_List.get(newGood_Matches.get(i).trainIdx).pt); 
      sceneList.addLast(keypoints1_List.get(newGood_Matches.get(i).queryIdx).pt); 
     } 
     MatOfPoint2f obj = new MatOfPoint2f(); 
     MatOfPoint2f scene = new MatOfPoint2f(); 
     obj.fromList(objList); 
     scene.fromList(sceneList); 

     System.out.println(matches.size() + " " + goodMatches.size()); 

     //output image 
     Mat outputImg = new Mat(); 
     MatOfByte drawnMatches = new MatOfByte(); 
     Features2d.drawMatches(img1, keypoints1, img2, keypoints2, goodMatches, outputImg, Scalar.all(-1), Scalar.all(-1), drawnMatches, Features2d.NOT_DRAW_SINGLE_POINTS); 

     Highgui.imwrite("img-matches.png", outputImg); 
     drawWithRect(img1, img2, obj, scene, outputImg); 

     keypointers1 = keypoints1; 
     keypointers2 = keypoints2; 

     return goodMatches; 
    } 

    public MatOfDMatch filterMatchesByHomography(MatOfDMatch matches) { 
     MatOfKeyPoint keypoints1 = keypointers1; 
     MatOfKeyPoint keypoints2 = keypointers2; 

     List<Point> lp1 = new ArrayList<Point>(); 
     List<Point> lp2 = new ArrayList<Point>(); 

     KeyPoint[] k1 = keypoints1.toArray(); 
     KeyPoint[] k2 = keypoints2.toArray(); 

     List<DMatch> matches_original = matches.toList(); 

     if (matches_original.size() < 4) { 
      MatOfDMatch mat = new MatOfDMatch(); 
      return mat; 
     } 

     // Add matches keypoints to new list to apply homography 
     for (DMatch match : matches_original) { 
      Point kk1 = k1[match.queryIdx].pt; 
      Point kk2 = k2[match.trainIdx].pt; 
      lp1.add(kk1); 
      lp2.add(kk2); 
     } 

     //srcPoints = new MatOfPoint2f(lp1.toArray(new Point[0])); 
     //dstPoints = new MatOfPoint2f(lp2.toArray(new Point[0])); 

     Mat mask = new Mat(); 
     //Mat homography = Calib3d.findHomography(srcPoints, dstPoints, Calib3d.LMEDS, 0.2, mask); 
     List<DMatch> matches_homo = new ArrayList<DMatch>(); 
     int size = (int) mask.size().height; 
     for (int i = 0; i < size; i++) { 
      if (mask.get(i, 0)[0] == 1) { 
       DMatch d = matches_original.get(i); 
       matches_homo.add(d); 
      } 
     } 

     MatOfDMatch mat = new MatOfDMatch(); 
     mat.fromList(matches_homo); 

     //Highgui.imwrite("img-matchesWithRect.png", mat); 
     return mat; 
    } 

    public void drawMatches(Mat img1, Mat img2, MatOfDMatch matches, boolean imageOnly) { 
     Mat out = new Mat(); 

     MatOfKeyPoint key2 = keypointers2; 
     MatOfKeyPoint key1 = keypointers1; 

     //Imgproc.cvtColor(img1, im1, Imgproc.COLOR_BGR2RGB); 
     //Imgproc.cvtColor(img2, im2, Imgproc.COLOR_BGR2RGB); 
     if (imageOnly) { 
      MatOfDMatch emptyMatch = new MatOfDMatch(); 
      MatOfKeyPoint emptyKey1 = new MatOfKeyPoint(); 
      MatOfKeyPoint emptyKey2 = new MatOfKeyPoint(); 
      Features2d.drawMatches(img1, emptyKey1, img2, emptyKey2, emptyMatch, out); 
     } else { 
      Features2d.drawMatches(img1, key1, img2, key2, matches, out); 
     } 

     //Imgproc.cvtColor(out, out, Imgproc.COLOR_BGR2RGB); 
     Core.putText(out, "FRAME", new Point(img1.width()/2, 30), Core.FONT_HERSHEY_PLAIN, 2, new Scalar(0, 255, 255), 3); 
     Core.putText(out, "MATCHED", new Point(img1.width() + img2.width()/2, 30), Core.FONT_HERSHEY_PLAIN, 2, new Scalar(255, 0, 0), 3); 

     Highgui.imwrite("img-drawnMatches.png", out); 
    } 

    public void drawWithRect(Mat img1, Mat img2, MatOfPoint2f obj, MatOfPoint2f scene, Mat outputImg){ 
     //run homography on object and scene points 
     Mat H = Calib3d.findHomography(obj, scene, Calib3d.RANSAC, 5); 
     Mat tmp_corners = new Mat(4, 1, CvType.CV_32FC2); 
     Mat scene_corners = new Mat(4, 1, CvType.CV_32FC2); 

     //get corners from object 
     tmp_corners.put(0, 0, new double[]{0, 0}); 
     tmp_corners.put(1, 0, new double[]{img2.cols(), 0}); 
     tmp_corners.put(2, 0, new double[]{img2.cols(), img2.rows()}); 
     tmp_corners.put(3, 0, new double[]{0, img2.rows()}); 

     Core.perspectiveTransform(tmp_corners, scene_corners, H); 

     Core.line(outputImg, new Point(scene_corners.get(0, 0)), new Point(scene_corners.get(1, 0)), new Scalar(0, 255, 0), 4); 
     Core.line(outputImg, new Point(scene_corners.get(1, 0)), new Point(scene_corners.get(2, 0)), new Scalar(0, 255, 0), 4); 
     Core.line(outputImg, new Point(scene_corners.get(2, 0)), new Point(scene_corners.get(3, 0)), new Scalar(0, 255, 0), 4); 
     Core.line(outputImg, new Point(scene_corners.get(3, 0)), new Point(scene_corners.get(0, 0)), new Scalar(0, 255, 0), 4); 

     Highgui.imwrite("img-matchesWithRect.png", outputImg); 
    } 

Основной метод:

public static void main(String args[]) { 
     System.load(new File("/usr/local/Cellar/opencv/2.4.9/share/OpenCV/java/libopencv_java249.dylib").getAbsolutePath()); 

     Mat img1 = Highgui.imread(scenesD); 
     Mat img2 = Highgui.imread(objectD); 

     MeanShift Tester = new MeanShift(); 
     List<Mat> histogramsList; 
     Mat hue_histogram; 
     Mat saturationChannel; 
     Mat getBackProjOfHueTemp; 

     //Calulate Histogram of Object 
     histogramsList = Tester.calculateHistograms(img2); 

     //Get saturation channel of scene 
     saturationChannel = Tester.identifyLowSat(img1); 

     //Get hue of calculated object histogram 
     hue_histogram = histogramsList.get(0); 

     //Get back projection of object from calculated hue histogram template 
     getBackProjOfHueTemp = Tester.getBackProjOfHueTemplate(img2, hue_histogram); 

     //Filtering matches 
     MatOfDMatch matches = Tester.filterMatches(saturationChannel, getBackProjOfHueTemp); 
     MatOfDMatch homo_matches = Tester.filterMatchesByHomography(matches); 

     //Draw img unto screen; 
     Tester.drawMatches(saturationChannel, getBackProjOfHueTemp, homo_matches, false); 
    } 

И до сих пор вот финальное изображение я получить (IMG-matches.png) enter image description here

И пытается получить прямоугольник из изображение дает мне это (img-matchesWithRect.png) enter image description here

+0

@mprat Я сделал это, реализовав его в методе drawMatches() и сделал гомографию в drawMacthesWithRect() – Daniel

+1

Ваш вопрос непонятен - в чем же проблема? Сообщения об ошибках? Случаи, где это не работает? Вы пробовали это на небольшом примере? – mprat

+0

Согласитесь с этим в моем сообщении «Мой вопрос: как получить суб изображение с целевого изображения?» – Daniel

ответ

-1

Итак, у вас есть Point s в ваше исходное изображение, которое вы нашли, имеет совпадения в вашем целевом изображении. Все эти точки имеют x и y координаты - для поиска «субимага» (или прямоугольника на изображении) все, что вам нужно сделать, это взять минимум всех x, чтобы получить верхний левый x координаты, минимум y s, чтобы получить верхний левый y координаты, максимум x s, чтобы получить нижнее правое x координаты, а максимальное значение y s, чтобы получить нижнее правое y координаты.

Затем с этим вы можете создать Rect (http://docs.opencv.org/java/org/opencv/core/Rect.html) и использовать его для доступа к Растр: изображение (Rect) (если у вас есть предыдущая переменная image, которая является Mat):

Rect sub_rect = new Rect(min_x, min_y, max_x - min_x, max_y - min_y); 
Mat sub_region = image(sub_rect); 

Теперь sub_region будет иметь ваш субрегион в нем.

+0

Вы могли бы дать образец кода в java? Было бы полезно попытаться конвертировать из C++ в Java весь день из документов openCV. – Daniel

+0

Ваше решение не работает. – Daniel

+0

. Вы должны объяснить, как, или что такое сообщение об ошибке, или что вы сделали. Просто сказать, что это не работает, не помогает. – mprat

Смежные вопросы