【问题标题】:Java OpenCV + Tesseract OCR "code" regocnitionJava OpenCV + Tesseract OCR“代码”识别
【发布时间】:2013-08-03 22:25:28
【问题描述】:

我正在尝试使有人手动将代码转换为数字代码的过程自动化。

然后我开始阅读有关 OCR 的内容。所以我安装了 tesseract OCR 并在一些图像上进行了尝试。它甚至没有检测到接近代码的东西。

在阅读了有关 stackoverflow 的一些问题后,我发现图像需要进行一些预处理,例如将图像倾斜到水平图像,例如可以通过 openCV 完成。

现在我的问题是:

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

希望有人能帮帮我!

【问题讨论】:

    标签: java opencv ocr tesseract


    【解决方案1】:

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

    我也学到了很多东西。特别是关于速度。此功能在高分辨率图像上速度较慢。尺寸为 3264 x 1836 时最多需要 10 秒。

    为了加快速度,我将输入矩阵的大小调整为1 / 4 的系数。这使它4^2 快​​了几倍,并且给了我最小的精度损失。下一步是将我们找到的四边形缩放回正常大小。这样我们就可以使用原始源将四边形转换为普通透视图。

    我为检测最大区域创建的代码很大程度上基于我在 stackoverflow 上找到的代码。不幸的是,它们并没有像我预期的那样工作,所以我结合了更多的代码 sn-ps 并进行了很多修改。 这是我得到的:

        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 forum上发布了您对相关问题的回答
    • 感谢@Tim,这段代码对我很有帮助但我必须对您的代码进行一些更改,因为我不知道如何使用“MatOfPoint”在图像周围绘制矩形。现在它对我有用,但我仍然面临一个问题。有时这会在 Image 上只得到一个半矩形,有时它会绘制多个矩形。你能建议我如何解决这个问题吗?
    猜你喜欢
    • 2014-06-04
    • 1970-01-01
    • 2021-03-11
    • 1970-01-01
    • 2017-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多