Find a contour checked in java with OpenCV

3.2k views Asked by At

I want my program to input an image (attachment)

input

and output a string like :

  • Question 1: box 2 checked
  • Question 2: box 1 checked
  • Question 3: box 3 checked
  • Question 4: box 2 checked

Etc ... (as many question as I have per image)

I can simply locate empty boxes with this program:

import java.util.ArrayList;
import java.util.List;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class test {
    public static void main(String[] args) {
        // Load the library of openCv
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        // Consider the image for processing
        Mat image = Imgcodecs.imread("C:/attachement.jpg", Imgproc.COLOR_BGR2GRAY);
        Mat imageHSV = new Mat(image.size(), CvType.CV_8UC4);
        Mat imageBlurr = new Mat(image.size(),CvType.CV_8UC4);
        Mat imageA = new Mat(image.size(), CvType.CV_32F);
        Imgproc.cvtColor(image, imageHSV, Imgproc.COLOR_BGR2GRAY);
        Imgproc.GaussianBlur(imageHSV, imageBlurr, new Size(5,5), 0);
        Imgproc.adaptiveThreshold(imageBlurr, imageA, 255,Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY,7, 5);
        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();    
        Imgproc.findContours(imageA, contours, new Mat(), Imgproc.RETR_LIST,Imgproc.CHAIN_APPROX_SIMPLE);
        for(int i=0; i< contours.size();i++)
        {
            if (Imgproc.contourArea(contours.get(i)) > 50 )
            {
                Rect rect = Imgproc.boundingRect(contours.get(i));
                if ((rect.height > 35 && rect.height < 60) && (rect.width > 35 && rect.width < 60))
                {
                    Imgproc.rectangle(image, new Point(rect.x,rect.y), new Point(rect.x+rect.width,rect.y+rect.height),new Scalar(0,0,255));
                }
            }
        }
        Imgcodecs.imwrite("C:/Users/Benreghai/Downloads/tof/output.png",image);
    }
}

Here is the output of my program: (image attached) output

Thank you for your help !

1

There are 1 answers

1
Rick M. On

Following the comments, I'm adding the piece of code required.

Vector<Mat> rectangles = new Vector<Mat>();
for(int i=0; i< contours.size();i++)
    {
        if (Imgproc.contourArea(contours.get(i)) > 50 )
        {
            Rect rect = Imgproc.boundingRect(contours.get(i));
            if ((rect.height > 35 && rect.height < 60) && (rect.width > 35 && rect.width < 60))
            {
                 //Instead of drawing the rectangle, extract it using the Rect data type
                Rect rec = new Rect(rect.x, rect.y, rect.width, rect.height);
                rectangles.add(new Mat(image, rec));  
                // Imgproc.rectangle(image, new Point(rect.x,rect.y), new Point(rect.x+rect.width,rect.y+rect.height),new Scalar(0,0,255));
            }
        }
    }
     // Once you have all the rectangles, loop over them to find intersecting lines
     // Initialize a vector of points to save the start and end of each line segment found
     Vector<Point> start = new Vector<Point>();
     Vector<Point> end = new Vector<Point>();
     for (Mat rectangle : rectangles){
     // Perform edge detection for using Canny, apply threshold suitably
     int canny_lower = 100, canny_upper = 200;
     Mat canny_img = new Mat(rectangle.size, CvType.8UC1);
     Imgproc.Canny(rectangle, canny_img, canny_lower, canny_upper);
     // Probably a Morphological Operation here, if required
     Mat hough_lines = new Mat();
     // Adjust the parameters from (here)[http://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html]
     Imgproc.HoughLinesP(canny_img, hough_lines, 1, Math.PI / 720, 80, img.width() * 0.5, 50);
     // hough_lines contains all the line segments detected by HoughLinesP
     // Find coordinates of the line segment found using the previous step
     for(int j = 0; j < hough_lines.cols(); j++){
     double[] vec = hough_lines.get(0, j);
     double x1 = vec[0], y1 = vec[1], x2 = vec[2], y2 = vec[3];
     start.add(new Point(x1, y1));
     end.add(new Point(x2, y2));
} 
 // Now that you have all lines the rectangle, find angle between them to
 check if they are intersecting
 for (int i = 0; i < start.size(); i++){
  // Find the slope between segment i and i+1
  // Multiple approaches here
  char intersect_flag = get_line_intersection();
  if (intersect_flag == 1)
      System.out.print("\n Intersecting");
  else 
      System.out.print("\n Not intersecting");

}

}
// Returns 1 if the lines intersect, otherwise 0. In addition, if the lines intersect the intersection point may be stored in the floats i_x and i_y.
// Pass x and y coordinates of each line segment for p0 to p4.i_x and i_y will have the coordinate of intersection, not required here. 
char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, 
float p2_x, float p2_y, float p3_x, float p3_y, float i_x, float i_y)
{
float s1_x, s1_y, s2_x, s2_y;
s1_x = p1_x - p0_x;     s1_y = p1_y - p0_y;
s2_x = p3_x - p2_x;     s2_y = p3_y - p2_y;

float s, t;
s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
{
    // Collision detected
    if (i_x != NULL)
        *i_x = p0_x + (t * s1_x);
    if (i_y != NULL)
        *i_y = p0_y + (t * s1_y);
    return 1;
}

return 0; // No collision
}

Hope it helps! Follow How do you detect where two line segments intersect? for the intersection of two lines.