【问题标题】:How to draw a boundingRect with the right rotation angle by using OpenCV?如何使用 OpenCV 绘制具有正确旋转角度的 boundingRect?
【发布时间】:2019-07-23 06:43:37
【问题描述】:

我正在使用 Android 和 Opencv 在图像上执行 Canny 边缘检测器以检测最大轮廓,使用 warpPerspective 方法提取它,然后找到该轮廓内的所有对象。一切都按预期工作,但仅适用于未旋转的图像。 我正在使用 boundingRect 来获取轮廓并使用它的坐标来提取它。

这是我的代码:

   private Mat  detectLargestContour(Mat origMat) {

   // long e1 = Core.getTickCount();

    Mat mGray = new Mat();

    MatOfDouble mu = new MatOfDouble();

    MatOfDouble stddev = new MatOfDouble();

    Imgproc.cvtColor(origMat, mGray, Imgproc.COLOR_BGR2GRAY);

    Core.meanStdDev(mGray, mu, stddev);

    Imgproc.GaussianBlur(mGray, mGray, new Size(5, 5), 5);

    //Imgproc.Canny(mGray, mGray, 30, 80, 3, false);   //FOR HIGH BRIGHTNESS
    //Imgproc.Canny(mGray, mGray, 50, 130, 3, false);    // FOR LOW BRIGHTNESS

    Imgproc.Canny(mGray, mGray, mu.get(0, 0)[0], stddev.get(0, 0)[0], 3, false);

    Mat kernell = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(9,9));

    Imgproc.morphologyEx(mGray, mGray, Imgproc.MORPH_CLOSE, kernell);

    Imgproc.dilate(mGray, mGray, Imgproc.getStructuringElement(Imgproc.MORPH_CROSS, new Size(3, 3)));


    List<MatOfPoint> contours = new ArrayList<MatOfPoint>();

    Mat hierarchy = new Mat();

    Imgproc.findContours(mGray, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

   //MatOfPoint2f approxCurve = new MatOfPoint2f();

    double largest_area=0;

    Rect rect = new Rect();

    for (int idx = 0; idx < contours.size() ; idx++) {

        double a = Imgproc.contourArea(contours.get(idx));  //Find the area of contour

        if (a > largest_area) {
            largest_area = a;
            rect = Imgproc.boundingRect(contours.get(idx));
        }
    }

    if (rect.area() > 100000) {
        Imgproc.rectangle(origMat, rect.tl(), rect.br(), new Scalar(0, 255, 0));
        p1 = new Point(rect.tl().x, rect.tl().y);
        p2 = new Point(rect.tl().x + rect.width, rect.tl().y);
        p3 = new Point(rect.tl().x, rect.tl().y + rect.height);
        p4 = new Point(rect.tl().x + rect.width, rect.tl().y + rect.height);

        card_corners = new ArrayList<>();
        card_corners.add(p1);
        card_corners.add(p3);
        card_corners.add(p4);
        card_corners.add(p2);

        warpedCard =  new Mat(origMat.rows(), origMat.cols(), CvType.CV_8UC3);
        final Point p1 = new Point(warpedCard.cols() + marge, warpedCard.rows() + marge);
        final Point p2 = new Point(0 - marge, warpedCard.rows() + marge);
        final Point p3 = new Point(0 - marge, 0 - marge);
        final Point p4 = new Point(warpedCard.cols() + marge, 0 - marge);

        LinkedList<Point> sceneList = new LinkedList<Point>();
        sceneList.addLast(p4);
        sceneList.addLast(p3);
        sceneList.addLast(p2);
        sceneList.addLast(p1);

        MatOfPoint2f scene = new MatOfPoint2f();
        scene.fromList(sceneList);

        MatOfPoint2f obj = new MatOfPoint2f();
        obj.fromList(card_corners);

        Mat homography = Calib3d.findHomography(obj, scene);
        Imgproc.warpPerspective(origMat, warpedCard, homography, new Size(warpedCard.cols(), warpedCard.rows()));

        return warpedCard;
    }

    return origMat;
}

这很奇怪,但只有 boundingRect 给了我一个稳定且高性能的结果,但绘制的矩形不会随着找到的轮廓旋转。

我该如何解决这个问题?有什么想法吗?

编辑: 我用 minAreaRect 改变了 boundingRect。

这里是代码

  int largest_idx = 0;

    for (int idx = 0; idx < contours.size() ; idx++) {

        double a = Imgproc.contourArea(contours.get(idx));  //Find the area of contour

        if (a > largest_area) {

            largest_area = a;

            // rect = Imgproc.boundingRect(contours.get(idx));

            largest_idx = idx;
        }
    }

    MatOfPoint2f new_mat = new MatOfPoint2f( contours.get(largest_idx).toArray() );

    RotatedRect rbox = Imgproc.minAreaRect(new_mat);

    Log.d("rotatedrect_angle", "" + rbox.angle);

    Point points[] = new Point[4];

    rbox.points(points);

    for(int i=0; i<4; ++i){
        Imgproc.line(origMat, points[i], points[(i+1)%4], new Scalar(255,255,255));
    }

这就是我所拥有的:

如您所见,检测不如我使用 boundingRect 时准确。

【问题讨论】:

标签: java android opencv image-processing opencv4android


【解决方案1】:

查找和绘制旋转矩形的 Python 演示:

# 2019/03/01
# https://stackoverflow.com/a/54942835/3547485

import numpy as np
import cv2

gray = cv2.imread("tmp.png", cv2.IMREAD_GRAYSCALE)
th, threshed = cv2.threshold(gray, 220, 255, cv2.THRESH_BINARY_INV)
cnts = cv2.findContours(threshed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2]
cnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
rbox = cv2.minAreaRect(cnt)
pts = cv2.boxPoints(rbox).astype(np.int32)
cv2.drawContours(img, [pts], -1, (0, 255, 0), 1, cv2.LINE_AA)

cv2.imwrite("dst.png", img)

有用的 OpenCV 函数(在 Python 中):cv2.minAreaRect、cv2.boxPoints、cv.2drawContours。你可以在Java中找到相应的函数。

【讨论】:

  • 谢谢你,先生,我会试试这个例子并给你更新。
  • @Amine 关于minAreaRect的java问题,也许有用:stackoverflow.com/questions/23327502/…
  • 感谢您的建议,但线路尚不可用。
  • Imgproc.boxPoints 需要两个参数,rotatedrect 和 Mat of points,我有 rotaterect,你能告诉我在点 mat 中放什么吗?
猜你喜欢
  • 1970-01-01
  • 2019-09-27
  • 1970-01-01
  • 1970-01-01
  • 2017-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多