Ask Your Question
0

Crop rectangle and apply transformation from image?

asked 2016-07-07 02:42:25 -0600

Hardik Patel gravatar image

Hello all,

i want to detect paper sheet from image.i applied medianBlur, Canny ,dilate,threshold,Etc. algorithms to find.i am able to find sheet but dont know how to crop rectangle and apply transformation

image description

this is my code:-

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

    // Set up images to use.
    Mat gray0 = new Mat(blurred.size(), CvType.CV_8U);
    Mat gray = new Mat();

    // For Core.mixChannels.
    List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
    List<MatOfPoint2f> rectangles = new ArrayList<MatOfPoint2f>();

    List<Mat> sources = new ArrayList<Mat>();
    sources.add(blurred);
    List<Mat> destinations = new ArrayList<Mat>();
    destinations.add(gray0);

    // To filter rectangles by their areas.
    int srcArea = src.rows() * src.cols();

    // Find squares in every color plane of the image.
    for (int c = 0; c < 3; c++) {
        int[] ch = {c, 0};
        MatOfInt fromTo = new MatOfInt(ch);

        Core.mixChannels(sources, destinations, fromTo);

        // Try several threshold levels.
        for (int l = 0; l < N; l++) {
            if (l == 0) {
                // HACK: Use Canny instead of zero threshold level.
                // Canny helps to catch squares with gradient shading.
                // NOTE: No kernel size parameters on Java API.
                Imgproc.Canny(gray0, gray, 0, CANNY_THRESHOLD);

                // Dilate Canny output to remove potential holes between edge segments.
                Imgproc.dilate(gray, gray, Mat.ones(new Size(3, 3), 0));
            } else {
                int threshold = (l + 1) * 255 / N;
                Imgproc.threshold(gray0, gray, threshold, 255, Imgproc.THRESH_BINARY);
            }

            // Find contours and store them all as a list.
            Imgproc.findContours(gray, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
            int i=0;
            for (MatOfPoint contour : contours) {
                MatOfPoint2f contourFloat = GeomUtils.toMatOfPointFloat(contour);
                double arcLen = Imgproc.arcLength(contourFloat, true) * 0.02;

                // Approximate polygonal curves.
                MatOfPoint2f approx = new MatOfPoint2f();
                Imgproc.approxPolyDP(contourFloat, approx, arcLen, true);

                if (isRectangle(approx, srcArea)) {
                    Imgproc.drawContours(src, contours, i, new Scalar(255, 0, 0), 3);
                    //rectangles.add(approx);
                    /*Rect rect = Imgproc.boundingRect(contour);
                    Log.e("Rectangle Finder:-" + i, "Height:-" + rect.height + ", Width:-" + rect.width + " and Area:-" + rect.area() + "\nX:-" + rect.x + ",Y:-" + rect.y);*/
                }
                i++;
            }
        }

i want to select only white papersheet.please help me

Thanks in advance

edit retag flag offensive close merge delete

Comments

1

You already calculated the contours of your image. The paper sheet should be the biggest contour. So find the biggest contour in your image and you get your paper sheet. With minAreaRect() you can calculate a rotated rectangle around that contour.

Missing gravatar imageMissing ( 2016-07-07 03:41:25 -0600 )edit
sturkmen gravatar imagesturkmen ( 2016-07-07 03:55:00 -0600 )edit

Yes @Missing i calculated contours but i want find largest contour and crop into new mat.please help me.thanks

Hardik Patel gravatar imageHardik Patel ( 2016-07-07 09:03:27 -0600 )edit

Simply iterate over your contours and retrieve the contour area by calling contourAea(contour) and store the biggest one. With minAreaRect()you get the rotated rectangle for that contour. If you want to extract that rectangle take a look at that question here: http://answers.opencv.org/question/49...

Missing gravatar imageMissing ( 2016-07-08 03:56:27 -0600 )edit

Hello @Missing,i have tried with following code:

     Imgproc.findContours(gray, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
            int i=0;
            MatOfPoint largestContour=contours.get(0);
            double largestares=Imgproc.contourArea(largestContour);
            for (MatOfPoint contour : contours)            {
              MatOfPoint temp_contour = contours.get(i);
                double temparea = Imgproc.contourArea(temp_contour);
              if (temparea > largestares) {
                        largestares=temparea;
                        largestContour=temp_contour;
                        largestRectNo=i;
                        Log.e("Contour Size",largestares+"");}}
Hardik Patel gravatar imageHardik Patel ( 2016-07-08 07:18:37 -0600 )edit

when i draw largest contour its return this :- http://i.stack.imgur.com/BhNhI.jpg

Hardik Patel gravatar imageHardik Patel ( 2016-07-08 07:23:30 -0600 )edit

Hello @Missing.please help me

Hardik Patel gravatar imageHardik Patel ( 2016-07-11 00:46:19 -0600 )edit

Could you post your image that you use findContours() on? Your contour follows along the border of the image and not the paper sheet. Seems yout threshold is not good enough.

Missing gravatar imageMissing ( 2016-07-11 01:02:03 -0600 )edit

Means original image? this is original image http://i.stack.imgur.com/ojhGb.jpg. and my code is mentioned in my question

Hardik Patel gravatar imageHardik Patel ( 2016-07-11 02:58:41 -0600 )edit

No your image named "gray"...This is the black and white image you use to calculate the contours. This image should just contain the white paper sheet.

Missing gravatar imageMissing ( 2016-07-11 03:00:29 -0600 )edit

2 answers

Sort by ยป oldest newest most voted
1

answered 2016-07-11 06:39:41 -0600

Missing gravatar image

So i wrote some Python code to get the contour of the paper sheet.

import numpy as np
import cv2

# Original image
image = cv2.imread('images/sheet.jpg')
# Resize
image = cv2.resize(image, (500,500))
draw = np.zeros_like(image)
# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Get black and white image
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))

# Some erosions and dilations to remove noise.
thresh = cv2.erode(thresh, kernel, iterations=4)
thresh = cv2.dilate(thresh, kernel, iterations=4)

# Get Contours of binary image
im, cnts, hier = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Find the biggest contour
max_area = -1
max_c = 0
for i in range(len(cnts)):
    contour = cnts[i]
    area = cv2.contourArea(contour)
    if (area > max_area):
        max_area = area
        max_c = i
contour = cnts[max_c]

# Get minAreaRect
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
box = np.int0(box)


# Draw contour and minAreaRect
cv2.drawContours(image, [box],-1, (0, 255, 0), 2)
cv2.drawContours(image, [contour], -1, (255,0,0), 2)
cv2.imshow('Sheet', image)

cv2.waitKey(0)
cv2.destroyAllWindows()

After that the image looks like this (blue is the contour and green is the rectangle around the contour:

image description

edit flag offensive delete link more

Comments

Thanks @Missing for help. but i need code in java.and just tell me one thing that how to check biggest contour is rectangle? as you know in my code,largest contour is like Sample image so if i able to check this contour is rectangle or not then i filter the result.. thanks

Hardik Patel gravatar imageHardik Patel ( 2016-07-12 00:15:28 -0600 )edit

You can check the shape by using approxPolyDP(). This functions approximates a polygonal curve of the contour. This meens you get four points if the contour is a rectangle, three points if it is a triangle and so on. But this will not work for your image, because your contour does not fit the paper sheet correctly. You need to get the contour right like in my example above.

Missing gravatar imageMissing ( 2016-07-12 01:54:10 -0600 )edit
0

answered 2016-07-12 02:14:57 -0600

Hardik Patel gravatar image

updated 2016-07-12 02:17:29 -0600

Yes @Missing i already use approxPolyDP() in my code

  Imgproc.findContours(gray, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
        int i=0;
        for (MatOfPoint contour : contours) {
            MatOfPoint2f contourFloat = GeomUtils.toMatOfPointFloat(contour);
            double arcLen = Imgproc.arcLength(contourFloat, true) * 0.02;

            // Approximate polygonal curves.
            MatOfPoint2f approx = new MatOfPoint2f();
            Imgproc.approxPolyDP(contourFloat, approx, arcLen, true);

            if (isRectangle(approx, srcArea)) {
                Imgproc.drawContours(src, contours, i, new Scalar(255, 0, 0), 3);
            }
        }

  private boolean isRectangle(MatOfPoint2f polygon, int srcArea) {
    MatOfPoint polygonInt = GeomUtils.toMatOfPointInt(polygon);

    if (polygon.rows() != 4) {
        return false;
    }

    double area = Math.abs(Imgproc.contourArea(polygon));
    if (area < srcArea * areaLowerThresholdRatio || area > srcArea * areaUpperThresholdRatio) {
        return false;
    }

    if (!Imgproc.isContourConvex(polygonInt)) {
        return false;
    }

    // Check if the all angles are more than 72.54 degrees (cos 0.3).
    double maxCosine = 0;
    Point[] approxPoints = polygon.toArray();

    for (int i = 2; i < 5; i++) {
        double cosine = Math.abs(GeomUtils.angle(approxPoints[i % 4], approxPoints[i - 2], approxPoints[i - 1]));
        maxCosine = Math.max(cosine, maxCosine);
    }

    if (maxCosine >= 0.3) {
        return false;
    }
    return true;
}

Do you have any other working code then please tell me

Thanks

edit flag offensive delete link more

Comments

I don't know how to check if your contour is a rectangle since the contour is not good. What are these noisy lines at the top left corner? You have to get a clean contour of the paper sheet to determine the shape of it.

Missing gravatar imageMissing ( 2016-07-12 02:22:10 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2016-07-07 02:42:25 -0600

Seen: 7,974 times

Last updated: Jul 12 '16