1

This is my first question on Stackoverflow.

I'm a software engineer in profession(Java, C#) and I have 0 knowledge on image processing and Android related technologies. I'm writing an android application for my masters thesis to support visually impaired people in my country to read a document from their Android smartphones, in our native language.

I have selected the sample size of the document as A4, and the app should eventually automatically focus on the document once the whole A4 doc is in camera's view (audible notification should be given to user), and it should then capture that image. Then I plan to run the document through tesseract engine to convert it into OCR. (Some other guy is doing the text-to-speech part of this application)

I googled thorough couple of applications and came up with the documentation of OpenCV. The http://docs.opencv.org/opencv_tutorials.pdf explains something about "Creating Bounding boxes and circles for contours" and looks like its gonna be my life saver.

My MSC project is a 300 hour part time project so I fear that I will get ended up with nothing after spending time to convert C++/ Python examples to Java by myself to learn OpenCV. I went through the JavaCV as well, but looks like its still in a growing stage, so most probably I will have to convert the examples by myself.

What I wanted to ask from experts is that whether the OpenCV can really do a thing like this? Thanks in advance!

Edit. I had a look at the link on the comment and trying to port the C++ example to Java. Here is what I got so far. Still there are couple of things to do though...

int thresh = 50, N = 11;

// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
static double angle(Point pt1, Point pt2, Point pt0)
{
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;

    return (dx1*dx2 + dy1*dy2)/Math.sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

public void find_squares(Mat image, Vector<Vector<Point> > squares)
{
    Imgproc img = new Imgproc();

    // blur will enhance edge detection
    org.opencv.core.Mat blurred = new org.opencv.core.Mat();
    Imgproc.medianBlur(image, blurred, 9);

    Mat gray0 = new Mat(blurred.size(), CvType.CV_8U);
    Mat gray = new Mat();
//        Vector<Vector<Point> > contours;
    List<MatOfPoint> contours = new ArrayList<MatOfPoint>();

    // find squares in every color plane of the image
    for (int c = 0; c < 3; c++)
    {
        int ch[] = {c, 0};
//            Core.mixChannels(blurred, 1, gray0, 1, ch, 1);
        List<Mat> src = new ArrayList<Mat>();
        src.add(blurred);
        List<Mat> dest = new ArrayList<Mat>();
        dest.add(gray0);

        MatOfInt a = new MatOfInt(ch);
        Core.mixChannels(src, dest, a);

        // try several threshold levels
        final int threshold_level = 2;
        for (int l = 0; l < threshold_level; l++)
        {
            // Use Canny instead of zero threshold level!
            // Canny helps to catch squares with gradient shading
            if (l == 0)
            {
                Imgproc.Canny(gray0, gray, 10, 20, 3, false);

                // Dilate helps to remove potential holes between edge segments
                Point point =  new Point(-1, -1);
                Imgproc.dilate(gray, gray, new Mat(), point, 1);
            }
            else
            {
                // TODO
                // gray = gray0 >= (l+1) * 255 / threshold_level;

            }

            // Find contours and store them in a list. //TODO
            Imgproc.findContours(gray, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

            // Test contours
            MatOfPoint2f approx = new MatOfPoint2f();
            for (int i = 0; i < contours.size(); i++)
            {
                // approximate contour with accuracy proportional
                // to the contour perimeter
                double epilson = Imgproc.arcLength(new MatOfPoint2f(contours.get(i)), true);
                epilson *= 0.02;
                Imgproc.approxPolyDP(new MatOfPoint2f(contours.get(i)), approx, epilson, true);

                // Note: absolute value of an area is used because
                // area may be positive or negative - in accordance with the
                // contour orientation
//                    Mat mmm = new Mat();
//                    MatOfPoint ppp = new MatOfPoint();

                if (/*TODO*/approx.size().area() == 4 &&
                        Math.abs(Imgproc.contourArea(approx)) > 1000 &&
                        Imgproc.isContourConvex(/*TODO*/approx))
                {
                    double maxCosine = 0;

                    for (int j = 2; j < 5; j++)
                    {
                        double cosine = Math.abs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
                        maxCosine = /*TODO*/MAX(maxCosine, cosine);
                    }

                    if (maxCosine < 0.3)
                        squares./*TODO*/push_back(approx);
                }
            }
        }
    }

}
}
dimuthu
  • 683
  • 8
  • 14
  • 1
    Regarding selecting A4 paper, it is possible with OpenCV. (http://stackoverflow.com/questions/8667818/opencv-c-obj-c-detecting-a-sheet-of-paper-square-detection/8863060#8863060)Regarding autofocussing, I don't know much about mobile version. – Abid Rahman K May 25 '13 at 07:30
  • Thanks for the link @AbidRahmanK. I'll vote you up once I get my reputation points. I started porting the program to Java, but still got couple of compile issues to solve. At the moment downloading the OpenCV-2.4.5-android-sdk to play around. Do you (Or anybody)know whether I can use native Python scripts in Android? (With the help of opencv) – dimuthu May 25 '13 at 15:59
  • Sorry, the above question should be "Do you (Or anybody) know whether I can use native Python or C++ scripts in Android? (With the help of opencv)" – dimuthu May 25 '13 at 16:26
  • i think c++ is possible. Not sure about that. Just search it. Something like 'android ndk' or whatever – Abid Rahman K May 25 '13 at 16:32

1 Answers1

0

Just to answer the question, Yes, this can be done in OpenCv (among many other things) and I have completed the project that I explained in the question. Also voted up Abid's answer for the link he provided:)

dimuthu
  • 683
  • 8
  • 14