C++ ---- 基于OpenCV的OCR字符识别

OpenCV 简介:
OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

OpenCV用C++语言编写,它的主要接口也是C++语言,但是依然保留了大量的C语言接口。该库也有大量的Python、Java and MATLAB/OCTAVE(版本2.5)的接口。这些语言的API接口函数可以通过在线文档获得。如今也提供对于C#、Ch、Ruby,GO的支持。

OCR 简介:
 OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程;即,针对印刷体字符,采用光学的方式将纸质文档中的文字转换成为黑白点阵的图像文件,并通过识别软件将图像中的文字转换成文本格式,供文字处理软件进一步编辑加工的技术。如何除错或利用辅助信息提高识别正确率,是OCR最重要的课题,ICR(Intelligent Character Recognition)的名词也因此而产生。衡量一个OCR系统性能好坏的主要指标有:拒识率、误识率、识别速度、用户界面的友好性,产品的稳定性,易用性及可行性等。

OCR实例:
做字符识别除了对软体有要求之外,外界环境一样很重要,比如摄像头,光源等。我们一般在做摄像头选取时在不考虑费用的情况下当然是像素越高越好,光源建议选用无阴影环形光。我采用的是800万CCD+800万定焦相机镜头+无阴影环形光源,为保证识别率高,外部设置先保证无误。

Step1: 调用摄像头进行拍照,代码如下:

        INT    mydevice;
    CHAR    *mydevicename;
    BOOL    findDevice = false;
    INT        DviceNo;//设备号  
    videoInput::listDevices();
    videoInput *VI = new videoInput();
    mydevice = VI->listDevices();
    VideoCapture capture(0);
    LOG_FOR_RD("Total Device found:%d", mydevice);
 
    for (int i = 0; i < mydevice; i++)
    {
        mydevicename = VI->getDeviceName(i);
        LOG_FOR_RD("Find device name:%s", mydevicename);
        if (strcmp(mydevicename, szCameraName) == 0)
        {
            DviceNo = i;
            findDevice = true;
            //break;
        }
    }
 
    if (findDevice == true)
    {
        //VI->setPhyCon(0,VI_COMPOSITE);
        VI->setupDevice(DviceNo);//打开设备  
        VI->setFormat(DviceNo, VI_PAL_B);//我用的摄像头是PAL_B格式的,所以设置成这个格式的,其实可以不要。  
        //VI->showSettingsWindow(DviceNo);//使用widows的对话框来设置摄像头的格式等。可以替代掉上面的那句话。、、打开qq的画质调节,发现你的对话框和qq的竟然一样?????  
        //原来qq也是用videoInput来实现的。 
        int height = VI->getHeight(DviceNo);
        int width = VI->getWidth(DviceNo);
        LOG_FOR_RD("Height:%d", height);
        LOG_FOR_RD("Width:%d", width);
 
        Sleep(1000);
 
        IplImage *img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); //3通道图像(RGB图像),1通道是灰度圖像
        LOG_FOR_RD("Start The device:%d", VI->isDeviceSetup(DviceNo));//查看设备是否启动  
        LOG_FOR_RD("The new frame status:%d", VI->isFrameNew(DviceNo));
        LOG_FOR_RD("Device name:%s", VI->getDeviceName(DviceNo));//得到设备名称。 
        Sleep(2000);
        while (NowTime < EndTime)
        {
 
            NowTime = ::GetTickCount();
            if (VI->isFrameNew(DviceNo))
            {
 
                VI->getPixels(DviceNo, (unsigned char*)img->imageData, false, true);//IplImage 格式  
                //cvFlip(img,NULL,1);//加上这句就水平翻转画面
                cvSaveImage(szTakePhotoName, img);
                bTakePhoto = TRUE;
                break;
            }
        }
 
        VI->stopDevice(DviceNo);//释放设备。 
        LOG_FOR_RD("release device");
    }
    else
    {
        MessageBox(NULL, "Not find ang device", NULL, NULL);
        iStatus = TEST_FAIL;
    }
Step2:  每次拍完照片进行图片保存(代码比较简单自己写)

Step3:为了提高识别率在拍到照片后对识别区域做图片截取,代码如下:

                //Step#3.截取圖片部分,提高識別率get ROI and save as szDealPic
        if (pic1rect.x >= 0 && pic1rect.y >= 0 && pic1rect.width > 0 && pic1rect.height > 0)
        {
            IplImage *img1 = NULL;
 
            img1 = cvLoadImage(szTakePhotoName);    //load original image
            if (img1 == NULL)
            {
                LOG_FOR_RD("Load test image fail!please check picture!");
                MessageBox(NULL, "Load test image fail!please check picture!", NULL, NULL);
                return TEST_FAIL;
            }
            cvSetImageROI(img1, pic1rect);// intercept img1 size of pic1rect   圖像截取Set Image ROI
            if (iPicColorRangeL[0] > 0 || iPicColorRangeL[1] > 0 || iPicColorRangeL[2] > 0 || iPicColorRangeH[0] < 255 || iPicColorRangeH[1] < 255 || iPicColorRangeH[2] < 255)
            {
                IplImage *img2 = NULL, *img3 = NULL, *img4 = NULL;
                img2 = cvCreateImage(cvGetSize(img1), IPL_DEPTH_8U, 1);  //創建灰度图像,大小和img1一樣
                img3 = cvCreateImage(cvGetSize(img1), IPL_DEPTH_8U, 1);
                img4 = cvCreateImage(cvGetSize(img1), IPL_DEPTH_8U, 1);
                //检查图像中的像素灰度是否属于某一指定范围
                cvInRangeS(img1, cvScalar(iPicColorRangeL[2], iPicColorRangeL[1], iPicColorRangeL[0]), cvScalar(255, 255, 255), img2);
                cvInRangeS(img1, cvScalar(iPicColorRangeH[2], iPicColorRangeH[1], iPicColorRangeH[0]), cvScalar(255, 255, 255), img3);
                cvAnd(img2, img3, img4);//計算两个数组的按位与的结果
 
                cvSaveImage(szDealPic, img4);//保存文件
            }
            else
                cvSaveImage(szDealPic, img1);
        }
        else
            ::CopyFile(szTakePhotoName, szDealPic, TRUE);
以上进行完成之后目前图片是只含有目标字符部分,OK 继续--->

Step4:对截取后的图片进行处理,做灰度化,二值化等:

                Step#4. process picture;
                Mat image, imageGrag, imageGuussian, imageSobelx, imageSobely, imageSobelOut;
        image = imread(szDealPic);
        //轉化為灰度圖
        cvtColor(image, imageGrag, CV_RGB2GRAY);
        //imwrite(szDealPic, imageGrag);
        //高斯平滑濾波
        GaussianBlur(imageGrag, imageGuussian, Size(3, 3), 0);
        imwrite(szDealPic, imageGuussian);
        blur(imageGuussian, imageSobelOut, Size(3, 3));
 
        //二值化
        Mat imageSobelOutThreshold;
        threshold(imageSobelOut, imageSobelOutThreshold, (float)PiexThresh, 255, CV_THRESH_BINARY);///* value = value > threshold ? max_value : 0       */
 
        //保存圖片
        imwrite(szDealPic, imageSobelOutThreshold);
 Step5:最后综合OpenCV进行字符识别

        设置自动进行版面分析 SetPageSegMode(PSM)
        api.SetPageSegMode(static_cast<tesseract::PageSegMode>(tesseract::PageSegMode::PSM_SINGLE_BLOCK));
 
        //結合opencv進行識別
        PIX   *pixs = pixRead(szDealPic);
        api.SetImage(pixs);
        char* out = api.GetUTF8Text();    //get context from picture
        api.Clear();
        api.End();
以上是整个流程,如果识别率并不是很好的情况下,我们还可以做手动training,采用jTessBoxEditor工具进行Tesseract3.02.02样本训练,从而提高识别率。

方法参考:http://www.mamicode.com/info-detail-1453474.html


————————————————
版权声明:本文为CSDN博主「Yu小余」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38862704/article/details/83381626

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值