Java OpenCV + Tesseract OCR的“code”识别

3

我正在尝试自动化一个流程,其中有人手动将代码转换为数字形式。

模拟代码

然后我开始阅读OCR技术。所以我安装了tesseract OCR并在一些图像上尝试了一下。它甚至不能检测到类似于代码的东西。

通过阅读stackoverflow上的一些问题,我发现这些图像需要进行一些预处理,例如将图像倾斜成水平的形式,这可以使用openCV完成。

现在我的问题是:

  • 在像以上图像这样的情况下,应该使用什么类型的预处理或其他方法?
  • 其次,我能否依靠输出结果? 在像以上图像这样的情况下,它是否总是有效的?

希望有人能够帮助我!

1个回答

7

我决定捕获整张卡片而不仅仅是代码。通过捕获整张卡片,可以将其转换为普通透视图,然后我可以轻松获取“代码”区域。

此外我学到了很多东西,特别是关于速度方面的问题。在高分辨率图像上,这个函数速度会很慢。对于3264 x 1836大小的图片,可能需要长达10秒的时间。

为了加快速度,我重新调整了输入矩阵的大小,缩小了4倍。这使得它的处理速度快了4^2倍,并且仅有微小的精度损失。下一步是将我们找到的四边形缩放回正常大小。这样我们就可以使用原始源将四边形转换为普通透视图。

我创建用于检测最大区域的代码非常依赖我在stackoverflow上找到的代码。不幸的是,它们对我来说并没有像预期的那样工作,所以我组合了更多的代码片段并进行了大量修改。这就是我得到的结果:

    private static double angle(Point p1, Point p2, Point p0 ) {
        double dx1 = p1.x - p0.x;
        double dy1 = p1.y - p0.y;
        double dx2 = p2.x - p0.x;
        double dy2 = p2.y - p0.y;
        return (dx1 * dx2 + dy1 * dy2) / Math.sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2) + 1e-10);
    }



    private static MatOfPoint find(Mat src) throws Exception {
        Mat blurred = src.clone();
        Imgproc.medianBlur(src, blurred, 9);

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

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

        List<Mat> blurredChannel = new ArrayList<>();
        blurredChannel.add(blurred);
        List<Mat> gray0Channel = new ArrayList<>();
        gray0Channel.add(gray0);

        MatOfPoint2f approxCurve;

        double maxArea = 0;
        int maxId = -1;

        for (int c = 0; c < 3; c++) {
            int ch[] = {c, 0};
            Core.mixChannels(blurredChannel, gray0Channel, new MatOfInt(ch));

            int thresholdLevel = 1;
            for (int t = 0; t < thresholdLevel; t++) {
                if (t == 0) {
                    Imgproc.Canny(gray0, gray, 10, 20, 3, true); // true ?
                    Imgproc.dilate(gray, gray, new Mat(), new Point(-1, -1), 1); // 1 ?
                } else {
                    Imgproc.adaptiveThreshold(gray0, gray, thresholdLevel, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY, (src.width() + src.height()) / 200, t);
                }

                Imgproc.findContours(gray, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

                for (MatOfPoint contour : contours) {
                    MatOfPoint2f temp = new MatOfPoint2f(contour.toArray());

                    double area = Imgproc.contourArea(contour);
                    approxCurve = new MatOfPoint2f();
                    Imgproc.approxPolyDP(temp, approxCurve, Imgproc.arcLength(temp, true) * 0.02, true);

                    if (approxCurve.total() == 4 && area >= maxArea) {
                        double maxCosine = 0;

                        List<Point> curves = approxCurve.toList();
                        for (int j = 2; j < 5; j++)
                        {

                            double cosine = Math.abs(angle(curves.get(j % 4), curves.get(j - 2), curves.get(j - 1)));
                            maxCosine = Math.max(maxCosine, cosine);
                        }

                        if (maxCosine < 0.3) {
                            maxArea = area;
                            maxId = contours.indexOf(contour);
                            //contours.set(maxId, getHull(contour));
                        }
                    }
                }
            }
        }

        if (maxId >= 0) {
            return contours.get(maxId);
            //Imgproc.drawContours(src, contours, maxId, new Scalar(255, 0, 0, .8), 8);
        }
        return null;
    }

你可以这样调用它:
MathOfPoint contour = find(src);

查看此答案以了解从轮廓检测到将其转换为平面透视图的四边形检测: Java OpenCV deskewing a contour


我在opencv论坛上回答了你发布的相关问题。 - tleyden
感谢@Tim,这段代码对我非常有帮助。但是我必须对你的代码进行一些更改,因为我不知道如何使用'MatOfPoint'来在图像周围绘制一个矩形。现在它对我有用了,但我仍然面临一个问题。有时候只会在图像的一半绘制矩形,有时则会绘制多个矩形。你能否给我一些建议如何解决这个问题? - UltimateDevil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接