1

I am working on a document scanner for Android similar to this.

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.

sample image

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.

Getting this result image.

result image

Please help me to resolve this issue.

1 Answer 1

0

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.