Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Where I start to develop Android OMR app?

image description

A just wanna to detect answer mark thought opencv. Looked at many samples. But most of them about hought circle, face detection etc. I look at this question But its not about android.

How to detect this answer sheet perfectly? Referance marks needed?

Where I begin to detect these black circles?

Here my code to detect circles. But I think I need another method to detect my black marks. If I can get the that coordinates than I can get next step.

public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    mRgba = inputFrame.rgba();
    mGray = inputFrame.gray();



        MatOfRect circles = new MatOfRect();

        Imgproc.HoughCircles(mGray, circles, Imgproc.CV_HOUGH_GRADIENT, 1, 50);

        // returns number of circular objects found
        Log.e("circle check", "circles.cols() " +  circles.cols());




    return mRgba;
}

Where I start How to develop Android OMR app?detect black dots inside largest Rectangle Contour?

image description

A just wanna to I can detect answer mark thought opencv. Looked at many samples. But most of them about hought circle, face detection etc. I look at this question But its not about android.

How to detect this largest contour the answer sheet perfectly? Referance marks needed?(20 questions, each have 4 alternative)

Where After the draw largest contour, what shall I begin do? Divide matris the rectangle by 20x4 cell? Or find countour again but this time inside the rectangle? I dont know what I need. Just I want to detect these black circles?

Here my code to detect circles. But I think I need another method to detect my black marks. If I can get the that coordinates than I can get next step.which is marked.

 public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    mRgba = inputFrame.rgba();
    mGray = inputFrame.gray();



        MatOfRect circles 
        return findLargestRectangle(inputFrame.rgba());
    }


    private Mat findLargestRectangle(Mat original_image) {
        Mat imgSource = original_image;
        hierarchy = new MatOfRect();

        Imgproc.HoughCircles(mGray, circles, Imgproc.CV_HOUGH_GRADIENT, 1, Mat();

        //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);

        // returns number //apply gaussian blur to smoothen lines of circular objects dots
        Imgproc.GaussianBlur(imgSource, imgSource, new Size(5, 5), 5);

        //find the contours
        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
        Imgproc.findContours(imgSource, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

        hierarchy.release();

        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
        Log.e("circle check", "circles.cols() "     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, contours, maxAreaIdx, new Scalar(0, 255, 0), 1);
        Log.d(TAG, "Largers Contour:" +  circles.cols());




contours.get(maxAreaIdx).toString());


        return mRgba;
imgSource;
    }

How to detect marked black dots regions inside largest Rectangle Contour?

image description

I can detect largest contour the answer sheet (20 questions, each have 4 alternative)

After the draw largest contour, what shall I do? Divide matris the rectangle by 20x4 cell? Or find countour again but this time inside the rectangle? I dont know what I need. Just I want to get which is marked.

 public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {

        return findLargestRectangle(inputFrame.rgba());
    }


    private Mat findLargestRectangle(Mat original_image) {
        Mat imgSource = original_image;
        hierarchy = new Mat();

        //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, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

        hierarchy.release();

        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, contours, maxAreaIdx, new Scalar(0, 255, 0), 1);
        Log.d(TAG, "Largers Contour:" + contours.get(maxAreaIdx).toString());


        return imgSource;
    }

UPDATE 1: I want to thank you @sturkmen for the his answer. I can read and find black regions now. Here the Android codes:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View _view = inflater.inflate(R.layout.fragment_main, container, false);
    // Inflate the layout for this fragment


    Button btnTest = (Button) _view.findViewById(R.id.btnTest);
    btnTest.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Mat img = Imgcodecs.imread(mediaStorageDir().getPath() + "/" + "test2.jpg");
            if (img.empty()) {
                Log.d("Fragment", "IMG EMPTY");
            }


            Mat gray = new Mat();
            Mat thresh = new Mat();

            //convert the image to black and white
            Imgproc.cvtColor(img, gray, Imgproc.COLOR_BGR2GRAY);

            //convert the image to black and white does (8 bit)
            Imgproc.threshold(gray, thresh, 0, 255, Imgproc.THRESH_BINARY_INV + Imgproc.THRESH_OTSU);
            Mat temp = thresh.clone();
            //find the contours
            Mat hierarchy = new Mat();

            Mat corners = new Mat(4,1, CvType.CV_32FC2);
            List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
            Imgproc.findContours(temp, contours,hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
            hierarchy.release();

            for (int idx = 0; idx < contours.size(); idx++)
            {
                MatOfPoint contour = contours.get(idx);
                MatOfPoint2f contour_points = new MatOfPoint2f(contour.toArray());
                RotatedRect minRect = Imgproc.minAreaRect( contour_points );
                Point[] rect_points = new Point[4];
                minRect.points( rect_points );
                if(minRect.size.height > img.width() / 2)
                {
                    List<Point> srcPoints = new ArrayList<Point>(4);
                    srcPoints.add(rect_points[2]);
                    srcPoints.add(rect_points[3]);
                    srcPoints.add(rect_points[0]);
                    srcPoints.add(rect_points[1]);

                    corners = Converters.vector_Point_to_Mat(
                            srcPoints, CvType.CV_32F);
                }

            }
            Imgproc.erode(thresh, thresh, new Mat(), new Point(-1,-1), 10);
            Imgproc.dilate(thresh, thresh, new Mat(), new Point(-1,-1), 5);
            Mat results = new Mat(1000,250,CvType.CV_8UC3);
            Mat quad = new Mat(1000,250,CvType.CV_8UC1);

            List<Point> dstPoints = new ArrayList<Point>(4);
            dstPoints.add(new Point(0, 0));
            dstPoints.add(new Point(1000, 0));
            dstPoints.add(new Point(1000, 250));
            dstPoints.add(new Point(0, 250));
            Mat quad_pts = Converters.vector_Point_to_Mat(
                    dstPoints, CvType.CV_32F);

            Mat transmtx = Imgproc.getPerspectiveTransform(corners, quad_pts);
            Imgproc.warpPerspective( img, results, transmtx, new Size(1000,250));
            Imgproc.warpPerspective( thresh, quad, transmtx, new Size(1000,250));

            Imgproc.resize(quad,quad,new Size(20,5));

            Imgcodecs.imwrite("results.png",quad);

            //show image
            showImage(quad);

            //store image
            storeImage(quad);

        }

    });

    return _view;
}

public void showImage (Mat img) {
    ImageView imgView = (ImageView) getActivity().findViewById(R.id.sampleImageView);
    //Mat mRgba = new Mat();

    //mRgba = Utils.loadResource(MainAct.this, R.drawable.your_image,Highgui.CV_LOAD_IMAGE_COLOR);
    Bitmap img2 = Bitmap.createBitmap(img.cols(), img.rows(),Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(img, img2);
    imgView.setImageBitmap(img2);
}

public File mediaStorageDir () {
    File _mediaStorageDir = new File(Environment.getExternalStorageDirectory()
            + "/Android/data/"
            + getActivity().getApplicationContext().getPackageName());

    return _mediaStorageDir;
}

public void storeImage(Mat matImg) {

    Bitmap bitmapImg = Bitmap.createBitmap(matImg.cols(), matImg.rows(),Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(matImg, bitmapImg);
    String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(new Date());
    File mediaFile;
    String mImageName="IMG_"+ timeStamp +".jpg";
    mediaFile = new File(mediaStorageDir().getPath() + File.separator + mImageName);

    File pictureFile = mediaFile;

    try {
        FileOutputStream fos = new FileOutputStream(pictureFile);
        bitmapImg.compress(Bitmap.CompressFormat.PNG, 90, fos);
        fos.close();
    } catch (FileNotFoundException e) {
        Log.d("FragmentMain", "File not found: " + e.getMessage());
    } catch (IOException e) {
        Log.d("FragmentMain", "Error accessing file: " + e.getMessage());
    }
}