• OpenCV自带dnn的Example研究(6)— text_detection


    这个博客系列,简单来说,今天我们就是要研究
    6个文件,看看在最新的OpenCV中,它们是如何发挥作用的。
    在配置使用的过程中,需要注意使用较高版本的VS避免编译器兼容问题;由于DNN程序的运行依赖于训练成功的模型,因此需要预先下载准备;此外如果出现各种报错,需要对症下药。
    此外,由于需要使用common.hpp文件,所以需要引入dnn目录到include中
    用到的数据集都放在:
    链接:https://pan.baidu.com/s/1WPoXU3VodErPHZo6Yc21xA 
    提取码:01no 
    如果你没找到,那一定是我忘了。
    =====================================================================================友善的分割线============================
    对于这个例子,之前我结合tesseract做过一个更好的,这里就不重复了。将其转过来:

    EAST+Tesseract识别自然场景下发票序号
    目前的代码基本可用,但是需要进行进一步的重构。

    获得所有的rect
    经过筛检后去掉很多
    里面就有我需要的。

    那么这里的识别还是有一定问题的,主要是east有漏的情况出现。适当进行修正。

    那么识别的结果主要是两个entire,一个是前后有多余字符;二个是可能存在错误。




    我认为在现有的识别结果上,应该可以得到进一步的增强。但是需要建立一个“识别和调整”的循环机制,并且对特别是tesseract的参数调节有进一步的认识。


    重新编译了OpenCV4,并且对代码重构,看上去效果非常不错:
    // EAST+Tesseract实现自然场景下发票编码识别
    // by jsxyhelu.cnblogs.com
    #include "pch.h"
    #include <iostream>
    #include <opencv2/core.hpp>
    #include <opencv2/highgui.hpp>
    #include <opencv2/imgproc.hpp>
    #include <opencv2/imgproc/imgproc_c.h>
    #include <opencv2/dnn.hpp>
    #include <allheaders.h> // leptonica main header for image io
    #include <baseapi.h> // tesseract main header
    using namespace std;
    using namespace cv;
    using namespace cv::dnn;
    using namespace std;
    //对east的结果进行解码
    void decode(const Matscoresconst Matgeometryfloat scoreThresh,
        std::vector<RotatedRect>& detectionsstd::vector<float>& confidences)
    {
        detections.clear();
        CV_Assert(scores.dims == 4); CV_Assert(geometry.dims == 4); CV_Assert(scores.size[0] == 1);
        CV_Assert(geometry.size[0] == 1); CV_Assert(scores.size[1] == 1); CV_Assert(geometry.size[1] == 5);
        CV_Assert(scores.size[2] == geometry.size[2]); CV_Assert(scores.size[3] == geometry.size[3]);
        const int height = scores.size[2];
        const int width = scores.size[3];
        for (int y = 0; y < height; ++y)
        {
            const floatscoresData = scores.ptr<float>(0, 0, y);
            const floatx0_data = geometry.ptr<float>(0, 0, y);
            const floatx1_data = geometry.ptr<float>(0, 1, y);
            const floatx2_data = geometry.ptr<float>(0, 2, y);
            const floatx3_data = geometry.ptr<float>(0, 3, y);
            const floatanglesData = geometry.ptr<float>(0, 4, y);
            for (int x = 0; x < width; ++x)
            {
                float score = scoresData[x];
                if (score < scoreThresh)
                    continue;
                // Decode a prediction.
                // Multiple by 4 because feature maps are 4 time less than input image.
                float offsetX = x * 4.0f, offsetY = y * 4.0f;
                float angle = anglesData[x];
                float cosA = std::cos(angle);
                float sinA = std::sin(angle);
                float h = x0_data[x] + x2_data[x];
                float w = x1_data[x] + x3_data[x];
                Point2f offset(offsetX + cosA * x1_data[x] + sinA * x2_data[x],
                    offsetY - sinA * x1_data[x] + cosA * x2_data[x]);
                Point2f p1 = Point2f(-sinA * h, -cosA * h+ offset;
                Point2f p3 = Point2f(-cosA * wsinA * w+ offset;
                RotatedRect r(0.5f * (p1 + p3), Size2f(wh), -angle * 180.0f / (float)CV_PI);
                detections.push_back(r);
                confidences.push_back(score);
            }
        }
    }
    int main()
    {
        //参数和常量准备
        String model = "./frozen_east_text_detection.pb";
        std::vector<Matouts;
        std::vector<StringoutNames(2);
        outNames[0] = "feature_fusion/Conv_7/Sigmoid";
        outNames[1] = "feature_fusion/concat_3";
        Mat  blob;
        std::vector<RotatedRectboxes;
        std::vector<floatconfidences;
        std::vector<intindices;
        char cbuf[255];
        // 引入EAST model
        Net net = readNet(model);
        //对tesseract进行初始化操作
        tesseract::TessBaseAPI tess;
        if (tess.Init("E:\sandbox\新建文件夹\tessdata""eng"))
        {
            std::cout << "OCRTesseract: Could not initialize tesseract." << std::endl;
            return 1;
        }
        Mat src = imread("E:\未来项目\(15)微模式ocr\发票图片\2.png");
        Mat board = src.clone();//用于显示图片
        blobFromImage(srcblob, 1.0, Size(320, 320), Scalar(), truefalse);//Scalar采用默认是设置
        net.setInput(blob);
        net.forward(outsoutNames);
        Mat scores = outs[0];
        Mat geometry = outs[1];
        decode(scoresgeometry, 0.5, boxesconfidences);//注意0.5是超参数
        NMSBoxes(boxesconfidences, 0.5, 0.4, indices);
        Point2f ratio((float)src.cols / 320, (float)src.rows / 320);//缩放比例
        //获得最终框选结果
        for (size_t i = 0; i < indices.size(); ++i)
        {
            RotatedRectbox = boxes[indices[i]];    
            Point2f vertices[4];
            box.points(vertices);
            for (int j = 0; j < 4; ++j)
            {
                vertices[j].x *= ratio.x;
                vertices[j].y *= ratio.y;
            }
            Point2flastItemPointer = (vertices + sizeof vertices / sizeof vertices[0]);
            vector<Point2fcontour(verticeslastItemPointer);
            //筛选出所有矩形中中心点y值小于整个图像1/6的举行,绘制最小外接矩形
            Rect boundRect = boundingRect(Mat(contour));
            //对rect适当进行扩充
            boundRect = cv::Rect(boundRect.tl().x - 5, boundRect.tl().yboundRect.width + 10, boundRect.height);
            if (boundRect.y < src.rows / 6)
            {
                Mat roi = src(boundRect);
                //绘制外接边线
                for (int j = 0; j < 4; ++j)
                    line(boardvertices[j], vertices[(j + 1) % 4], Scalar(0, 255, 0), 1);
                rectangle(boardboundRectScalar(0, 0, 255));//绘制外接最小矩形
                //打印数据
                sprintf_s(cbuf"E:\未来项目\(15)微模式ocr\发票图片\roi\%d.jpg"i);//打印出来
                imwrite(cbufroi);
                //将切割出来的图片输入tesseract中
                auto pixs = pixRead(cbuf);
                if (!pixs)
                {
                    std::cout << "Cannot open input file: " << std::endl;
                    return 1;
                }
                // recognize
                tess.SetImage(pixs);
                tess.Recognize(0);
                // get result and delete[] returned char* string
                std::cout << std::unique_ptr<char[]>(tess.GetUTF8Text()).get() << std::endl;
                putText(boardstd::unique_ptr<char[]>(tess.GetUTF8Text()).get(), boundRect.tl(), 1, 1.0f, Scalar(0, 255, 0));
                // cleanup
                tess.Clear();
                pixDestroy(&pixs);
            }
        }
        imshow("board"board);
        cv::waitKey();
        getchar();
        return 0;
    }





  • 相关阅读:
    C#Note13:如何在C#中调用python
    C# Note12:WPF只允许数字的限制性TextBox
    C# Note11:如何优雅地退出WPF应用程序
    C#读书笔记:线程,任务和同步
    Programming好文解读系列(—)——代码整洁之道
    java算法面试题:从类似如下的文本文件中读取出所有的姓名,并打印出重复的姓名和重复的次数,并按重复次数排序 ;读取docx 读取doc 使用poi 相关jar包提集提供下载
    java面试题:如果一串字符如"aaaabbc中国1512"要分别统计英文字符的数量,中文字符的数量,和数字字符的数量,假设字符中没有中文字符、英文字符、数字字符之外的其他特殊字符。
    java算法面试题:有一个字符串,其中包含中文字符、英文字符和数字字符,请统计和打印出各个字符的个数 按值的降序排序,如果值相同则按键值的字母顺序
    java算法面试题:编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串,但要保证汉字不被截取半个, 如“我ABC”,4,应该截取“我AB”,输入“我ABC汉DEF”,6,应该输出“我ABC”,而不是“我ABC+汉的半个”。
    Java算法面试题:编写一个程序,将e: eck目录下的所有.java文件复制到e:jpg目录下,并将原来文件的扩展名从.java改为.jpg
  • 原文地址:https://www.cnblogs.com/jsxyhelu/p/10796079.html
Copyright © 2020-2023  润新知