OpenCV Java:从图像中提取卡片

我正在尝试使用OpenCV和Java实现一些图像处理,以从图像中提取出一张图像。

以下是我的方法:

  • 转换为BGR图像
  • 转换成灰色图像
  • 应用GaussianBlur
  • 应用Canny边缘检测
  • 膨胀
  • 找到轮廓
  • 找到最大的轮廓
  • 使用approxPolyDP查找最大轮廓的角点
  • 沿着最大轮廓获取裁剪图像的自顶向下视图
  • 在步骤8,我面临一些问题,因为我没有得到适当的角落/顶点。 以下示例图像显示了该场景:

    原始图像 在这里输入图像描述

    边缘检测和扩张后。 (要做什么才能获得合适的边缘?在这里,我已经断了边缘,无法让Hough变换工作) 在这里输入图像描述

    找到顶点后。 (以绿色显示)

    在这里输入图像描述

    以下是代码:

    System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
    
             //load Image
             File input = new File("card4.png");
             BufferedImage image = ImageIO.read(input); 
             byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
    
             //put read image to Mat
             mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3); //original Mat
             mat.put(0, 0, data);
             mat_f = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3); //for storing manipulated Mat
    
             //conversion to grayscale, blurring and edge detection
             Imgproc.cvtColor(mat, mat_f, Imgproc.COLOR_RGB2BGR);
             Imgproc.cvtColor(mat_f, mat_f, Imgproc.COLOR_RGB2GRAY);
             Imgproc.GaussianBlur(mat_f, mat_f, new Size(13,13), 0);             
             Imgproc.Canny(mat_f, mat_f, 300, 600, 5, true);
             Imgproc.dilate(mat_f, mat_f, new Mat(), new Point(-1, -1), 2);
             Imgcodecs.imwrite("D:JAVAImage_ProcCVTest1.jpg",mat_f);
    
             //finding contours
             List<MatOfPoint> contours = new ArrayList<MatOfPoint>();    
             Mat hierarchy = new Mat();
             Imgproc.findContours(mat_f, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
             double maxArea=0;
             int maxAreaIdx=0;
    
             //finding largest contour
             for (int idx = 0; idx != contours.size(); ++idx)
             {
                   Mat contour = contours.get(idx);
                   double contourarea = Imgproc.contourArea(contour);
                   if (contourarea > maxArea)
                   {
                       maxArea = contourarea;
                       maxAreaIdx = idx;
                   }
    
              }
    
                //Rect rect = Imgproc.boundingRect(contours.get(maxAreaIdx));
                //Imgproc.rectangle(mat, new Point(rect.x,rect.y), new Point(rect.x+rect.width,rect.y+rect.height),new Scalar(0,0,255),7);
               // mat = mat.submat(rect.y, rect.y + rect.height, rect.x, rect.x + rect.width);
    
    
              //Polygon approximation
              MatOfPoint2f approxCurve = new MatOfPoint2f();
              MatOfPoint2f oriCurve = new MatOfPoint2f(contours.get(maxAreaIdx).toArray());
              Imgproc.approxPolyDP(oriCurve, approxCurve, 6.0, true);
    
              //drawing red markers at vertices
              Point [] array = approxCurve.toArray();
              for(int i=0; i < array.length;i++) {
                 Imgproc.circle(mat, array[i], 2, new Scalar(0, 255, 0), 5);
              }
              Imgcodecs.imwrite("D:JAVAImage_ProcCVTest.jpg",mat);
    

    寻求帮助获得适当的角落顶点......在此先感谢..


    为了使用你的方法归档好结果,你的卡片必须包含4个角落。 但我更喜欢使用HoughLine方法来完成这项任务。

    第1步:调整图像以获得更高性能


    步骤2:边缘检测

  • 将图像转换为灰度
  • 模糊图像清除噪音
  • 使用Canny滤波器进行边缘检测
  • 您可以使用扩大使下一步的白色变大

    第3步:找到卡的角落

  • 找到图像轮廓
  • 从轮廓列表中获取最大轮廓
  • 获取它的凸面
  • 使用approxPolyDP来简化凸包(这应该给四边形)
  • 从现在开始,您可以在恢复缩放后绘制轮廓以获取矩形
  • 从四边形你可以得到4个角落。
  • 找到Homography
  • 使用计算的单应性矩阵来变换输入图像
  • 这里是Java中的示例代码

        // STEP 1: Resize input image to img_proc to reduce computation
        double ratio = DOWNSCALE_IMAGE_SIZE / Math.max(frame.width(), frame.height());
        Size downscaledSize = new Size(frame.width() * ratio, frame.height() * ratio);
        Mat dst = new Mat(downscaledSize, frame.type());
        Imgproc.resize(frame, dst, downscaledSize);
        Mat grayImage = new Mat();
        Mat detectedEdges = new Mat();
        // STEP 2: convert to grayscale
        Imgproc.cvtColor(dst, grayImage, Imgproc.COLOR_BGR2GRAY);
        // STEP 3: try to filter text inside document
        Imgproc.medianBlur(grayImage, detectedEdges, 9);
        // STEP 4: Edge detection
        Mat edges = new Mat();
        // Imgproc.erode(edges, edges, new Mat());
        // Imgproc.dilate(edges, edges, new Mat(), new Point(-1, -1), 1); // 1
        // canny detector, with ratio of lower:upper threshold of 3:1
        Imgproc.Canny(detectedEdges, edges, this.threshold.getValue(), this.threshold.getValue() * 3, 3, true);
        // STEP 5: makes the object in white bigger to join nearby lines
        Imgproc.dilate(edges, edges, new Mat(), new Point(-1, -1), 1); // 1
        Image imageToShow = Utils.mat2Image(edges);
        updateImageView(cannyFrame, imageToShow);
        // STEP 6: Compute the contours
        List<MatOfPoint> contours = new ArrayList<>();
        Imgproc.findContours(edges, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
        // STEP 7: Sort the contours by length and only keep the largest one
        MatOfPoint largestContour = getMaxContour(contours);
        // STEP 8: Generate the convex hull of this contour
        Mat convexHullMask = Mat.zeros(frame.rows(), frame.cols(), frame.type());
        MatOfInt hullInt = new MatOfInt();
        Imgproc.convexHull(largestContour, hullInt);
        MatOfPoint hullPoint = OpenCVUtil.getNewContourFromIndices(largestContour, hullInt);
        // STEP 9: Use approxPolyDP to simplify the convex hull (this should give a quadrilateral)
        MatOfPoint2f polygon = new MatOfPoint2f();
        Imgproc.approxPolyDP(OpenCVUtil.convert(hullPoint), polygon, 20, true);
        List<MatOfPoint> tmp = new ArrayList<>();
        tmp.add(OpenCVUtil.convert(polygon));
        restoreScaleMatOfPoint(tmp, ratio);
        Imgproc.drawContours(convexHullMask, tmp, 0, new Scalar(25, 25, 255), 2);
        // Image extractImageToShow = Utils.mat2Image(convexHullMask);
        // updateImageView(extractFrame, extractImageToShow);
        MatOfPoint2f finalCorners = new MatOfPoint2f();
        Point[] tmpPoints = polygon.toArray();
        for (Point point : tmpPoints) {
            point.x = point.x / ratio;
            point.y = point.y / ratio;
        }
        finalCorners.fromArray(tmpPoints);
        boolean clockwise = true;
        double currentThreshold = this.threshold.getValue();
        if (finalCorners.toArray().length == 4) {
            Size size = getRectangleSize(finalCorners);
            Mat result = Mat.zeros(size, frame.type());
            // STEP 10: Homography: Use findHomography to find the affine transformation of your paper sheet
            Mat homography = new Mat();
            MatOfPoint2f dstPoints = new MatOfPoint2f();
            Point[] arrDstPoints = { new Point(result.cols(), result.rows()), new Point(0, result.rows()), new Point(0, 0), new Point(result.cols(), 0) };
            dstPoints.fromArray(arrDstPoints);
            homography = Calib3d.findHomography(finalCorners, dstPoints);
    
            // STEP 11: Warp the input image using the computed homography matrix
            Imgproc.warpPerspective(frame, result, homography, size);
        }
    
    链接地址: http://www.djcxy.com/p/79603.html

    上一篇: OpenCV Java : Card Extraction from Image

    下一篇: Horizon Line Detection via Canny and Hough