1

これは Stackoverflow に関する私の最初の質問です。

私はプロのソフトウェア エンジニア (Java、C#) であり、画像処理と Android 関連のテクノロジに関する知識はありません。私は修士論文用の Android アプリケーションを作成しており、私の国の視覚障害者が Android スマートフォンから母国語でドキュメントを読むことをサポートしています。

ドキュメントのサンプル サイズとして A4 を選択しました。A4 ドキュメント全体がカメラの視野に入ると、アプリは最終的にドキュメントに自動的にフォーカスし (音声通知がユーザーに与えられる必要があります)、その画像をキャプチャする必要があります。次に、文書を tesseract エンジンで実行して OCR に変換する予定です。(他の人がこのアプリケーションのテキスト読み上げ部分を行っています)

いくつかのアプリケーションを徹底的にグーグル検索し、OpenCV のドキュメントを思いつきました。http://docs.opencv.org/opencv_tutorials.pdfは、「輪郭の境界ボックスと円の作成」について説明しており、私の命の恩人になるようです。

私の MSC プロジェクトは 300 時間のパートタイム プロジェクトなので、OpenCV を学ぶために自分で C++/Python の例を Java に変換するのに時間を費やした後、何も残らないのではないかと心配しています。私は JavaCV も試しましたが、まだ成長段階にあるように見えるので、おそらく自分でサンプルを変換する必要があります。

私が専門家に聞きたかったのは、OpenCV で本当にこのようなことができるのかということです。前もって感謝します!

編集。コメントのリンクを見て、C++ の例を Java に移植しようとしました。これが私がこれまでに得たものです。それでもやるべきことがいくつかありますが...

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

}
}
4

1 に答える 1

0

質問に答えるために、はい、これはOpenCvで(他の多くのことの中でも)行うことができ、質問で説明したプロジェクトを完了しました。また、彼が提供したリンクに対するAbidの回答に投票しました:)

于 2014-11-13T08:23:27.460 に答える