使用OpenCV扫描文档 [英] Scanning a document by using OpenCV

查看:111
本文介绍了使用OpenCV扫描文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用类似于这个.

我对此进行了搜索,发现可以通过OpenCV来实现,因此从OpenCV开始.

I searched about this and found that this can be achieved with OpenCV so started with OpenCV.

我尝试了许多示例来从图像中检测文档,但是无法检测图像背景是否浅.检查样本图像以进行测试.

I tried lots of examples to detect document from image but could not able to detect if image has light background. Check sample image for test.

我正在使用OpenCV Android SDK并使用Java代码进行图像处理. 这是代码:

I am using OpenCV Android SDK and using java code for image processing. Here is code:

public void scanDocument(Bitmap mBitmap)
{
    Mat mOriginalMat = convertToMat(mBitmap);
    int mRatio = getRadio(mOriginalMat);
    Size mSize = getImageFitSize(mOriginalMat, mRatio);

    Mat resizedMat = resizeMat(mOriginalMat, mSize);
    Mat colorMat = grayMat(resizedMat, mSize);
    Mat blurMat = medianBlurMat(colorMat, mSize);
    Mat thresholdMat = cannyEdgeMat(blurMat, mSize);

    ArrayList<MatOfPoint> contourList = findContours(thresholdMat, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
    double maxArea = 0.0;
    int maxAreaIdx = -1;
    Collections.sort(contourList, new Comparator<MatOfPoint>() {
        @Override
        public int compare(MatOfPoint lhs, MatOfPoint rhs)
        {
        return Double.valueOf(Imgproc.contourArea(rhs)).compareTo(Imgproc.contourArea(lhs));
        }
    });

    ArrayList<MatOfPoint> contourListMax = new ArrayList<>();
    for (int idx = 0; idx < contourList.size(); idx++)
    {
        MatOfPoint contour = contourList.get(idx);

        MatOfPoint2f c2f = new MatOfPoint2f(contour.toArray());
        MatOfPoint2f approx = new MatOfPoint2f();
        double epsilon = Imgproc.arcLength(c2f, true);
        Imgproc.approxPolyDP(c2f, approx, epsilon * 0.02, true);

        Point[] points = approx.toArray();
        MatOfPoint approxTemp = new MatOfPoint(approx.toArray());

        if (points.length == 4 && Imgproc.isContourConvex(approxTemp) && maxArea < Imgproc.contourArea(approxTemp))
        {
            maxArea = Imgproc.contourArea(approxTemp);
            maxAreaIdx = idx;
            Point[] foundPoints = sortPoints(points);

            contourListMax.add(approxTemp);

            mPointFMap = new HashMap<>();
            mPointFMap.put(0, new PointF((float) foundPoints[0].x + xGap, (float) foundPoints[0].y + yGap));
            mPointFMap.put(1, new PointF((float) foundPoints[1].x + xGap, (float) foundPoints[1].y + yGap));
            mPointFMap.put(2, new PointF((float) foundPoints[3].x + xGap, (float) foundPoints[3].y + yGap));
            mPointFMap.put(3, new PointF((float) foundPoints[2].x + xGap, (float) foundPoints[2].y + yGap));
            break;
        }
    }

    Imgproc.drawContours(resizedMat, contourListMax, -1, new Scalar(255, 165, 0), 2);
    showMatToImageView(resizedMat);
}

private Mat convertToMat(Bitmap bitmap)
{
    Mat mat = Imgcodecs.imread(mFilePath);// new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC1);
    Imgproc.cvtColor(mat, mat, Imgproc.COLOR_BGR2RGB);
    return mat;
}

private double getRadio(Mat mat)
{
    double ratio;
    if (mat.size().width > mat.size().height)
        ratio = mat.size().height / mMainLayout.getHeight();
    else
        ratio = mat.size().width / mMainLayout.getWidth();
    return ratio;
}

private Size getImageFitSize(Mat mat, double ratio)
{
    int height = Double.valueOf(mat.size().height / ratio).intValue();
    int width = Double.valueOf(mat.size().width / ratio).intValue();
    return new Size(width, height);
}

private void showMatToImageView(Mat mat)
{
    final Bitmap bitmap = Bitmap.createBitmap(mat.width(), mat.height(), Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(mat, bitmap);
    runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {
            mSourceImageView.setImageBitmap(bitmap);
            mProgressBar.setVisibility(View.GONE);
        }
    });
}

private Mat resizeMat(Mat mat, Size size)
{
    Mat resizedMat = new Mat(size, CvType.CV_8UC4);
    Imgproc.resize(mat, resizedMat, size);
    return resizedMat;
}

private Mat grayMat(Mat mat, Size size)
{
    Mat grayMat = new Mat(size, CvType.CV_8UC4);
    Imgproc.cvtColor(mat, grayMat, Imgproc.COLOR_RGB2GRAY, 4);
    return grayMat;
}

private Mat medianBlurMat(Mat mat, Size size)
{
    Mat blurMat = new Mat(size, CvType.CV_8UC4);
    Imgproc.medianBlur(mat, blurMat, 3);
    return blurMat;
}

private Mat cannyEdgeMat(Mat mat, Size size)
{
    if (thresholdVal <= 0)
        thresholdVal = 200;
    Mat cannyEdgeMat = new Mat(size, CvType.CV_8UC1);
    Imgproc.Canny(mat, cannyEdgeMat, thresholdVal * 0.5, thresholdVal, 3, true);
    return cannyEdgeMat;
}

private ArrayList<MatOfPoint> findContours(Mat mat, int retrievalMode, int approximationMode)
{
    ArrayList<MatOfPoint> contourList = new ArrayList<>();
    Mat hierarchy = new Mat();
    Imgproc.findContours(mat, contourList, hierarchy, retrievalMode, approximationMode);
    hierarchy.release();

    return contourList;
}

我想在透视变换的帮助下检测文档点,将文档变换为直线并进行其他图像过滤.

I want to detect points of document after with the help of perspective transform I will transform document to straight and do other image filtration.

获取此结果图像.

请帮助我解决此问题.

推荐答案

您的问题是在资源非常有限的字段上.我实际上已经复制了上面粘贴的代码,因为我什至不知道从哪里开始.但是,您还没有包括该行Point[] foundPoints = sortPoints(points);中使用的 sortPoints()函数, thresholdVal xGap & yGap 整数.他们是如何初始化的?通过共享其余代码,您将为我带来极大的帮助.谢谢.

Your question is on a field with very limited resources. I fact I have literally copy pasted your code above because I don't even know where to begin. You however didn't include the sortPoints() function used in this line Point[] foundPoints = sortPoints(points); also, the thresholdVal, xGap & yGap integers. How were they initialized? You'd do me a huge favor by sharing the rest of the code. Thankyou.

这篇关于使用OpenCV扫描文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆