Reputation: 1646
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:
But now, when I try to crop it, it looks like this:
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?
Upvotes: 3
Views: 2529
Reputation: 1646
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.
Upvotes: 3
Reputation: 501
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.
Upvotes: 5