【问题标题】:Perspective Transform OpenCV透视变换 OpenCV
【发布时间】:2018-03-16 08:59:06
【问题描述】:

我是 Android 上的 OpenCV 新手,尝试进行透视变换,但我不知道如何使用 getperspectivetransform() 和 warpperspective() 函数。我可以从图像中检测矩形,但不知道如何翘曲。

这里是检测矩形功能:

 Mat tempMat = new Mat();
        Mat src = new Mat();
        Utils.bitmapToMat(image, tempMat);

        Imgproc.cvtColor(tempMat, src, Imgproc.COLOR_BGR2RGB);

        Mat blurred = src.clone();
        Imgproc.medianBlur(src, blurred, 9);

        Mat gray0 = new Mat(blurred.size(), CvType.CV_8U), gray = new Mat();

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

        List<Mat> blurredChannel = new ArrayList<Mat>();
        blurredChannel.add(blurred);
        List<Mat> gray0Channel = new ArrayList<Mat>();
        gray0Channel.add(gray0);

        MatOfPoint2f approxCurve = new MatOfPoint2f();

        double maxArea = 0;
        int maxId = -1;

        for (int c = 0; c < 3; c++) {
            int ch[] = { c, 0 };
            Core.mixChannels(blurredChannel, gray0Channel, new MatOfInt(ch));

            int thresholdLevel = 1;
            for (int t = 0; t < thresholdLevel; t++) {
                if (t == 0) {
                    Imgproc.Canny(gray0, gray, 50, 50, 3, true); // true ?
                    Imgproc.dilate(gray, gray, new Mat(), new Point(-1, -1), 1); // 1
                    // ?
                } else {
                    Imgproc.adaptiveThreshold(gray0, gray, thresholdLevel,
                            Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,
                            Imgproc.THRESH_BINARY,
                            (src.width() + src.height()) / 200, t);
                }

                Imgproc.findContours(gray, contours, new Mat(),
                        Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

                for (MatOfPoint contour : contours) {
                    MatOfPoint2f temp = new MatOfPoint2f(contour.toArray());

                    double area = Imgproc.contourArea(contour);
                    approxCurve = new MatOfPoint2f();
                    Imgproc.approxPolyDP(temp, approxCurve,
                            Imgproc.arcLength(temp, true) * 0.02, true);

                    if (approxCurve.total() == 4 && area >= maxArea) {
                        double maxCosine = 0;

                        List<Point> curves = approxCurve.toList();
                        for (int j = 2; j < 5; j++) {

                            double cosine = Math.abs(angle(curves.get(j % 4),
                                    curves.get(j - 2), curves.get(j - 1)));
                            maxCosine = Math.max(maxCosine, cosine);
                        }

                        if (maxCosine < 0.45) {
                            maxArea = area;
                            maxId = contours.indexOf(contour);
                        }
                    }
                }
            }
        }

我用这个语句绘制矩形。

if (maxId >= 0) {
            Rect rect = Imgproc.boundingRect(contours.get(maxId));

            Imgproc.rectangle(src, rect.tl(), rect.br(), new Scalar(255, 0, 0,
                    .8), 4);

        }

之后,我将 mat 转换为位图并显示在 imageview 上。

Here is the screenshot

所以我的问题是翘曲,我怎样才能翘曲矩形并旋转它?

如果可能的话,我该如何改进检测矩形?有什么提示吗?

(OpenCV Android SDK 版本:3.41,Android Studio 版本:3.01)

【问题讨论】:

    标签: android opencv image-processing


    【解决方案1】:

    如果您希望将检测到的轮廓变形为矩形,

    1. 获取矩形的轮廓
    2. 找到轮廓的凸包
    3. 使用 approxPolyDP 将凸包点减少为 4 个点
    4. 将直线拟合到连续点(例如,如果 pts 是数组,则直线拟合如下 l1 = line Between(pts[0], pts[1]), l2 = line Between(pts[1], pts[ 2]), l3 = 线Between(pts[2], pts[3]), l4 = lineBetween(pts[3], pts[0])
    5. 找到这些线之间的交点,你会得到四个点
    6. 按顺时针顺序排列点(inputCorners = TopLeft、TopRight、BottomRight、BottomLeft)
    7. 创建具有所需分辨率的输出图像,并以相同的顺时针顺序 ((0,0), (0, cols), (rows, cols), (rows, 0)) 制作角点
    8. 使用函数查找单应性

      Mat homography = Calib3d.findHomography(inputCorners, imageCorners, Calib3d.RANSAC, 10);
      
    9. 使用输出单应矩阵,使用函数扭曲输入图像

      Imgproc.warpPerspective(image, outputMat, homography, new Size(image.cols(), image.rows()));
      

    可以参考以下link

    【讨论】:

      【解决方案2】:

      这是我的 kotlin extensin 版本,你可以在你的项目中使用它。

      fun Bitmap.perspectiveTransform(srcPoints: List<org.opencv.core.Point>) : 
          Bitmap{
           val dstWidth = max(
              srcPoints[0].distanceFrom(srcPoints[1]),
              srcPoints[2].distanceFrom(srcPoints[3])
           )
           val dstHeight = max(
               srcPoints[0].distanceFrom(srcPoints[2]),
               srcPoints[1].distanceFrom(srcPoints[3])
            )
      
          val dstPoints: List<org.opencv.core.Point> = listOf(
             org.opencv.core.Point(0.0, 0.0),
             org.opencv.core.Point(dstWidth, 0.0),
             org.opencv.core.Point(0.0, dstHeight),
             org.opencv.core.Point(dstWidth, dstHeight)
          )
          return try {
               val srcMat = Converters.vector_Point2d_to_Mat(srcPoints)
               val dstMat = Converters.vector_Point2d_to_Mat(dstPoints)
               val perspectiveTransformation = 
          Imgproc.getPerspectiveTransform(srcMat, dstMat)
          val inputMat = Mat(this.height, this.width, CvType.CV_8UC1)
          Utils.bitmapToMat(this, inputMat)
          val outPutMat = Mat(dstHeight.toInt(), dstWidth.toInt(), CvType.CV_8UC1)
          Imgproc.warpPerspective(
              inputMat,
              outPutMat,
              perspectiveTransformation,
              Size(dstWidth, dstHeight)
          )
          val outPut = Bitmap.createBitmap(
              dstWidth.toInt(),
              dstHeight.toInt(), Bitmap.Config.RGB_565
          )
          //Imgproc.cvtColor(outPutMat , outPutMat , Imgproc.COLOR_GRAY2BGR)
          Utils.matToBitmap(outPutMat , outPut)
          outPut
        }
        catch ( e : Exception){
          e.printStackTrace()
          this
        }
      }
      

      为了使用距离我写了另一个扩展函数

      fun org.opencv.core.Point.distanceFrom(srcPoint: org.opencv.core.Point): 
           Double {
           val w1 = this.x - srcPoint.x
           val h1 = this.y - srcPoint.y
           val distance = w1.pow(2) + h1.pow(2)
           return sqrt(distance)
         }
      

      在这个答案中,正确的 src Points 索引是:
      0 : 左上角

      1 : 右上

      2 : 左下

      3 : 右下角

      祝你好运

      【讨论】:

        猜你喜欢
        • 2011-08-26
        • 1970-01-01
        • 2021-01-05
        • 2018-04-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-20
        • 2015-01-04
        相关资源
        最近更新 更多