I am able to detect the largest square/rectangle (in green) in an image. However, I want to convert the largest square/rectangle detected in the image into a new image (to be stored in a new Mat).
Here's the return image of this function that has the largest rectangle/square on it: http://img153.imageshack.us/img153/9308/nn4w.png
Here is my code so far:
private Mat findLargestRectangle(Mat original_image) {
Mat imgSource = original_image;
//convert the image to black and white
Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BGR2GRAY);
//convert the image to black and white does (8 bit)
Imgproc.Canny(imgSource, imgSource, 50, 50);
//apply gaussian blur to smoothen lines of dots
Imgproc.GaussianBlur(imgSource, imgSource, new Size(5, 5), 5);
//find the contours
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(imgSource, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
double maxArea = -1;
int maxAreaIdx = -1;
MatOfPoint temp_contour = contours.get(0); //the largest is at the index 0 for starting point
MatOfPoint2f approxCurve = new MatOfPoint2f();
Mat largest_contour = contours.get(0);
List<MatOfPoint> largest_contours = new ArrayList<MatOfPoint>();
for (int idx = 0; idx < contours.size(); idx++) {
temp_contour = contours.get(idx);
double contourarea = Imgproc.contourArea(temp_contour);
//compare this contour to the previous largest contour found
if (contourarea > maxArea) {
//check if this contour is a square
MatOfPoint2f new_mat = new MatOfPoint2f( temp_contour.toArray() );
int contourSize = (int)temp_contour.total();
Imgproc.approxPolyDP(new_mat, approxCurve, contourSize*0.05, true);
if (approxCurve.total() == 4) {
maxArea = contourarea;
maxAreaIdx = idx;
largest_contours.add(temp_contour);
largest_contour = temp_contour;
}
}
}
MatOfPoint temp_largest = largest_contours.get(largest_contours.size()-1);
largest_contours = new ArrayList<MatOfPoint>();
largest_contours.add(temp_largest);
Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BayerBG2RGB);
Imgproc.drawContours(imgSource, largest_contours, -1, new Scalar(0, 255, 0), 1);
//create the new image here using the largest detected square
Toast.makeText(getApplicationContext(), "Largest Contour: ", Toast.LENGTH_LONG).show();
return imgSource;
}
The variable largest_contours is a list of MatOfPoint but only contains the largest contour, also stored in largest_contour variable. How can I possible make a new image from the largest contour?
I am using OpenCV in Android and there are few tutorials for detecting images but not exactly on how to use Imgproc.warpPerspective()
Thanks!
All you need is to find the corners of this contour. You can use extreme points approach.
You should simply find out the point having minimum x and minimum y (this is your topleft), minimum x maximum y (this is your bottom left), and so on.
In C++, there is a library named algoritm which has min/max methods. For instance min_element will help you to find the point having minimum x or y. Don't forget to include header.
After having your 4 points, you can use perspective transform.
First input your points to this method. The destination should be
Point2f dest[4] = {(0,0),(image.width,0),(0,image.height),(image.height,image.width)}
for your case. The matrix (M) you obtain from this method will transform your points to destination using another method.
Good luck.
Edit: On the second thought; since your contour is not a parallelogram, you have your extreme points as min x = bottomleft, min y = topleft, and so on. Then it is easier to find the minimum element.