3

So, I managed to detect document borders with opencv c++ code. Now, I need to crop that image and make it look decent.

Border detection looks good as you can see in this picture:

Before cropping

But now, when I try to crop it, it looks like this:

After cropping

Now, this is the code im using:

extern "C"
JNIEXPORT void JNICALL
Java_prisca_ctest_ScanActivity_doWithMat(JNIEnv *env, jobject instance, jlong matNumber) {
    //reference to the image from Java
    Mat &image = *(Mat *) matNumber;
    //resize image
    image = GetSquareImage(image);
    //add color effects for better detection
    Mat gray;
    cvtColor(image, gray, CV_BGR2GRAY);
    GaussianBlur(gray, gray, Size(5, 5), 0);
    Mat edged;
    Canny(gray, edged, 75, 200);
    //find contours and sort them from biggest to smallest
    vector<vector<Point> > contours;
    vector<Point> screenCnt;
    findContours(edged, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
    // sort contours
    sort(contours.begin(), contours.end(), compareContourAreas);

    Rect boundRect;

    //itterate over the contours and get the biggest contour for image
    for (int i = (int) (contours.size() - 1); i > 0; i--) {
        double peri = arcLength(Mat(contours[i]), true);
        vector<Point> approx;
        approxPolyDP(Mat(contours[i]), approx, 0.02 * peri, true);
        if (approx.size() == 4) {
            screenCnt = approx;
            boundRect = boundingRect(approx);
            break;
        }
    }
    Scalar color = Scalar(0, 255, 0);
    drawContours(image, Mat(screenCnt), -1, color, 5);
    //crop image with boundRect
    image = Mat(image, boundRect).clone();
}


Mat GetSquareImage(const cv::Mat &img, int target_width = 500) {
    int width = img.cols,
            height = img.rows;

    cv::Mat square = cv::Mat::zeros(target_width, target_width, img.type());

    int max_dim = (width >= height) ? width : height;
    float scale = ((float) target_width) / max_dim;
    cv::Rect roi;
    if (width >= height) {
        roi.width = target_width;
        roi.x = 0;
        roi.height = height * scale;
        roi.y = (target_width - roi.height) / 2;
    } else {
        roi.y = 0;
        roi.height = target_width;
        roi.width = width * scale;
        roi.x = (target_width - roi.width) / 2;
    }

    cv::resize(img, square(roi), roi.size());

    return square;
}


extern "C"
bool compareContourAreas(std::vector<cv::Point> contour1, std::vector<cv::Point> contour2) {
    double i = fabs(contourArea(cv::Mat(contour1)));
    double j = fabs(contourArea(cv::Mat(contour2)));
    return (i < j);
}

First of all, I followed tutorial from python code. He resizes picture to get desired result and when I do that, my text is not readable and my image isn't cropped like it is supposed to be(crop it so there is no surrounding background, only paper, etc..).

Does somebody has experience with this and if so, can somebody help me?

Miljan Vulovic
  • 1,322
  • 2
  • 12
  • 42
  • Have a look at [THIS POST](http://stackoverflow.com/questions/41428162/python-perspective-transform-for-opencv-from-a-rotation-angle/41555470#41555470) it is in python – Jeru Luke Mar 14 '17 at 09:43

2 Answers2

5

Looks like you'd need to get the rotatedRect instead of rectangle. Then perform a warpAffine (http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html?highlight=warpaffine)

Then use getRotationMatrix2D (http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html#getrotationmatrix2d) to get the angle of rotation, rotate the image as such, crop as usual and then rotate back to normal.

Jeru Luke
  • 13,413
  • 9
  • 57
  • 71
Luke Greenwood
  • 346
  • 2
  • 4
3

I have created a git repo with code for native support, that is cropping the image the right way, please find it on: link.

Feel free to edit code if you come up with a better solution.

Miljan Vulovic
  • 1,322
  • 2
  • 12
  • 42