24

我想制作一个像凸轮扫描仪这样的应用程序来裁剪文档。

但我需要像我的两个图像一样的功能..

第一张图片显示相机拍摄的图像..

在此处输入图像描述

第二张图像识别像这样捕获的图像部分..

在此处输入图像描述

我研究得越来越多,但没有得到任何结果,所以我在这里问是否,有人这样做告诉我..

谢谢

4

3 回答 3

14

我假设您的问题是检测要扫描的对象。

像模式匹配或特征检测这样的对象检测机制不会为您带来您正在寻找的结果,因为您不知道您正在扫描的对象到底是什么。

基本上你在图片中搜索一个矩形对象。

对此的基本方法如下:

  • 在图像上运行一个精明的边缘检测器。在执行此操作之前,它可能有助于稍微模糊图像。物体的边缘应清晰可见。

  • 现在你想做一个霍夫变换来找到图片中的线条。

  • 搜索彼此成约 90 度角的线。问题是找到合适的。也许使用最接近图片框架的线条与它们相当平行就足够了。

  • 找到相交点以定义对象的边缘。

至少这应该给你一个提示,在哪里进一步研究。

作为此类应用程序中的进一步步骤,您将必须计算点的投影并对对象进行仿射变换。

我希望这有帮助。

写完这一切后,我发现了这篇文章。它应该对你有很大帮助。

由于我的回答针对 OpenCV,您必须使用 OpenCV 库。为此,您需要安装Android Native Development Kit (NDK)在OpenCV for Android页面上有一些关于如何在 Android 上使用 OpenCV 的很好的教程。

要记住的一件事是,Java 包装器的几乎每个函数都调用一个本地方法。那要花很多时间。因此,在将结果返回到 Java 部分之前,您希望在本机代码中做尽可能多的事情。

于 2013-10-30T13:52:43.820 回答
5

I know I am too late to answer but it might be helpful to someone.

Try the following code.

@Override
protected void onDraw(Canvas canvas) {

  super.onDraw(canvas);
  path = new Path();

  path.moveTo(x1, y1);        // this should set the start point right

  //path.lineTo(x1, y1);    <-- this line should be drawn at the end of     course,sorry
  path.lineTo(x2, y2);
  path.lineTo(x3, y3);
  path.lineTo(x4, y4);
  path.lineTo(x1, y1); 
  canvas.drawPath(path, currentPaint);

}
于 2015-03-24T13:59:38.287 回答
0

以这种方法传递您的图像垫:

       void findSquares(Mat image, List<MatOfPoint> squares) {
    int N = 10;

    squares.clear();

    Mat smallerImg = new Mat(new Size(image.width() / 2, image.height() / 2), image.type());

    Mat gray = new Mat(image.size(), image.type());

    Mat gray0 = new Mat(image.size(), CvType.CV_8U);

    // down-scale and upscale the image to filter out the noise
    Imgproc.pyrDown(image, smallerImg, smallerImg.size());
    Imgproc.pyrUp(smallerImg, image, image.size());
    // find squares in every color plane of the image
    Outer:
    for (int c = 0; c < 3; c++) {

        extractChannel(image, gray, c);

        // try several threshold levels
        Inner:
        for (int l = 1; l < N; l++) {

            Imgproc.threshold(gray, gray0, (l + 1) * 255 / N, 255, Imgproc.THRESH_BINARY);


            List<MatOfPoint> contours = new ArrayList<MatOfPoint>();

            // find contours and store them all as a list
            Imgproc.findContours(gray0, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

            MatOfPoint approx = new MatOfPoint();

            // test each contour
            for (int i = 0; i < contours.size(); i++) {

                approx = approxPolyDP(contours.get(i), Imgproc.arcLength(new MatOfPoint2f(contours.get(i).toArray()), true) * 0.02, true);

                // square contours should have 4 vertices after approximation
                // relatively large area (to filter out noisy contours)
                // and be convex.
                // Note: absolute value of an area is used because
                // area may be positive or negative - in accordance with the
                // contour orientation
                double area = Imgproc.contourArea(approx);

                if (area > 5000) {

                    if (approx.toArray().length == 4 &&
                            Math.abs(Imgproc.contourArea(approx)) > 1000 &&
                            Imgproc.isContourConvex(approx)) {

                        double maxCosine = 0;
                        Rect bitmap_rect = null;
                        for (int j = 2; j < 5; j++) {
                            // find the maximum cosine of the angle between joint edges
                            double cosine = Math.abs(angle(approx.toArray()[j % 4], approx.toArray()[j - 2], approx.toArray()[j - 1]));
                            maxCosine = Math.max(maxCosine, cosine);
                            bitmap_rect = new Rect(approx.toArray()[j % 4], approx.toArray()[j - 2]);

                        }

                        // if cosines of all angles are small
                        // (all angles are ~90 degree) then write quandrange
                        // vertices to resultant sequence
                        if (maxCosine < 0.3)
                            squares.add(approx);

                    }
                }
            }
        }
    }
}

在这种方法中,您可以获得四个文件点,然后您可以使用以下方法剪切此图像:

      public Bitmap warpDisplayImage(Mat inputMat) {
    List<Point> newClockVisePoints = new ArrayList<>();

    int resultWidth = inputMat.width();
    int resultHeight = inputMat.height();

    Mat startM = Converters.vector_Point2f_to_Mat(orderRectCorners(Previes method four poit list(like : List<Point> points)));

    Point ocvPOut4 = new Point(0, 0);
    Point ocvPOut1 = new Point(0, resultHeight);
    Point ocvPOut2 = new Point(resultWidth, resultHeight);
    Point ocvPOut3 = new Point(resultWidth, 0);



        ocvPOut3 = new Point(0, 0);
        ocvPOut4 = new Point(0, resultHeight);
        ocvPOut1 = new Point(resultWidth, resultHeight);
        ocvPOut2 = new Point(resultWidth, 0);
    }

    Mat outputMat = new Mat(resultWidth, resultHeight, CvType.CV_8UC4);

    List<Point> dest = new ArrayList<Point>();
    dest.add(ocvPOut3);
    dest.add(ocvPOut2);
    dest.add(ocvPOut1);
    dest.add(ocvPOut4);


    Mat endM = Converters.vector_Point2f_to_Mat(dest);

    Mat perspectiveTransform = Imgproc.getPerspectiveTransform(startM, endM);

    Imgproc.warpPerspective(inputMat, outputMat, perspectiveTransform, new Size(resultWidth, resultHeight), Imgproc.INTER_CUBIC);


    Bitmap descBitmap = Bitmap.createBitmap(outputMat.cols(), outputMat.rows(), Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(outputMat, descBitmap);



    return descBitmap;
}
于 2017-04-26T10:11:58.137 回答