首页 文章

Android OpenCV纸张检测

提问于
浏览
1

我想之前问过这个问题,但我找不到问题的样本或解决方案 . 我是opencv的新手,我想使用OpenCV CameraPreview进行纸张检测 . 在我的示例应用程序中,我使用opencv 3.0.0进行静态初始化 . 我知道对象识别可以通过以下步骤完成:

  • 制作输入图像Canny

  • 模糊Canny图像

  • 在模糊的Canny图像上查找轮廓

  • 搜索矩形等

  • 绘制线条或用半透明颜色填充矩形

我现在的问题是,我可以精确地模糊图像,但我不知道如何找到轮廓和矩形,并用半透明的颜色填充它们 .

这是我目前的onCameraFrame功能:

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    Mat input = inputFrame.rgba();
    Mat output = input.clone();
    Imgproc.Canny(input, output, 50, 50);
    Imgproc.blur(output, output,new Size(5,5));
    //Find Contours
    //Search for biggest Contour/Rectangle
    //Fill Rectangle with half transparent Color
    return output;
}

任何人都可以帮我解决纸张检测问题,并为android / java提供代码示例吗?谢谢

1 回答

  • 3

    以下代码来自我正在开发的Open Note Scanner应用程序,您可以使用它来查找更多信息 .

    函数findDocument将返回一个Quadrilateral对象,该对象封装了一个带有轮廓的MatOfPoint和一个带有各个点的Point [] . 您可以调用它并使用返回的对象调用Imgproc.drawContours()来完成您的图像 .

    所有代码都是以this excellent tutorial from pyimagesearch为基础编写的

    注意:这是从我的代码快速移植方法,它没有语法错误但我没有测试它 .

    package com.todobom.opennotescanner.views;
    
    import org.opencv.core.CvType;
    import org.opencv.core.Mat;
    import org.opencv.core.MatOfPoint;
    import org.opencv.core.MatOfPoint2f;
    import org.opencv.core.Point;
    import org.opencv.core.Size;
    import org.opencv.imgproc.Imgproc;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.Comparator;
    
    public class detectDocument {
    
        /**
         *  Object that encapsulates the contour and 4 points that makes the larger
         *  rectangle on the image
         */
        public static class Quadrilateral {
            public MatOfPoint contour;
            public Point[] points;
    
            public Quadrilateral(MatOfPoint contour, Point[] points) {
                this.contour = contour;
                this.points = points;
            }
        }
    
        public static Quadrilateral findDocument( Mat inputRgba ) {
            ArrayList<MatOfPoint> contours = findContours(inputRgba);
            Quadrilateral quad = getQuadrilateral(contours);
            return quad;
        }
    
        private static ArrayList<MatOfPoint> findContours(Mat src) {
    
            double ratio = src.size().height / 500;
            int height = Double.valueOf(src.size().height / ratio).intValue();
            int width = Double.valueOf(src.size().width / ratio).intValue();
            Size size = new Size(width,height);
    
            Mat resizedImage = new Mat(size, CvType.CV_8UC4);
            Mat grayImage = new Mat(size, CvType.CV_8UC4);
            Mat cannedImage = new Mat(size, CvType.CV_8UC1);
    
            Imgproc.resize(src,resizedImage,size);
            Imgproc.cvtColor(resizedImage, grayImage, Imgproc.COLOR_RGBA2GRAY, 4);
            Imgproc.GaussianBlur(grayImage, grayImage, new Size(5, 5), 0);
            Imgproc.Canny(grayImage, cannedImage, 75, 200);
    
            ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
            Mat hierarchy = new Mat();
    
            Imgproc.findContours(cannedImage, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
    
            hierarchy.release();
    
            Collections.sort(contours, new Comparator<MatOfPoint>() {
    
                @Override
                public int compare(MatOfPoint lhs, MatOfPoint rhs) {
                    return Double.valueOf(Imgproc.contourArea(rhs)).compareTo(Imgproc.contourArea(lhs));
                }
            });
    
            resizedImage.release();
            grayImage.release();
            cannedImage.release();
    
            return contours;
        }
    
        private static Quadrilateral getQuadrilateral(ArrayList<MatOfPoint> contours) {
    
            for ( MatOfPoint c: contours ) {
                MatOfPoint2f c2f = new MatOfPoint2f(c.toArray());
                double peri = Imgproc.arcLength(c2f, true);
                MatOfPoint2f approx = new MatOfPoint2f();
                Imgproc.approxPolyDP(c2f, approx, 0.02 * peri, true);
    
                Point[] points = approx.toArray();
    
                // select biggest 4 angles polygon
                if (points.length == 4) {
                    Point[] foundPoints = sortPoints(points);
    
                    return new Quadrilateral(c, foundPoints);
                }
            }
    
            return null;
        }
    
        private static Point[] sortPoints(Point[] src) {
    
            ArrayList<Point> srcPoints = new ArrayList<>(Arrays.asList(src));
    
            Point[] result = { null , null , null , null };
    
            Comparator<Point> sumComparator = new Comparator<Point>() {
                @Override
                public int compare(Point lhs, Point rhs) {
                    return Double.valueOf(lhs.y + lhs.x).compareTo(rhs.y + rhs.x);
                }
            };
    
            Comparator<Point> diffComparator = new Comparator<Point>() {
    
                @Override
                public int compare(Point lhs, Point rhs) {
                    return Double.valueOf(lhs.y - lhs.x).compareTo(rhs.y - rhs.x);
                }
            };
    
            // top-left corner = minimal sum
            result[0] = Collections.min(srcPoints, sumComparator);
    
            // bottom-right corner = maximal sum
            result[2] = Collections.max(srcPoints, sumComparator);
    
            // top-right corner = minimal diference
            result[1] = Collections.min(srcPoints, diffComparator);
    
            // bottom-left corner = maximal diference
            result[3] = Collections.max(srcPoints, diffComparator);
    
            return result;
        }
    
    }
    

相关问题