美文网首页
OpenCV+TesseractOCRiOS实现身份证号/银行卡

OpenCV+TesseractOCRiOS实现身份证号/银行卡

作者: 一蓑烟雨满眼风波 | 来源:发表于2017-08-11 13:44 被阅读0次
    • iOS 文字识别准备
    • 图片灰度化
    • 图片二值化
    • 根据特征点提取某一区域

    声明:思路来源于 iOS身份证号码识别 ,在此我对作者表示感谢,一下内容,是我结合http://www.opencv.org.cn写的一个简单教程,对该工程所用到的方法进行解读,在本文的最后,会附上完整的代码.

    正文

    iOS 文字识别准备

    文字识别重要点在对图片的预处理,预处理做的比较好,识别率就会比较高,本次所介绍的身份证号识别是基于OpenCV、TesseractOCRiOS来实现的
    首先使用CocoaPods导入三方库

    pod 'OpenCV', '~> 3.0.0'
    pod 'TesseractOCRiOS', '~> 4.0.0'
    

    灰度化

    灰度化,在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。
    下面说一下如何使用OpenCV进行灰度化处理,使用的OpenCV是一个C++ 的代码,在使用的类中要将.m文件改为.mm

        //将UIImage转换成矩阵
        cv::Mat resultImage;//定义矩阵
        UIImageToMat(image, resultImage);
        //转为灰度图
        cvtColor(resultImage, resultImage, cv::COLOR_BGR2GRAY);
    
    原图.png 灰度化.png

    二值化

    图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。

    固定阈值门限分割
    • 方法
    double threshold( InputArray src, OutputArray dst,
                                   double thresh, double maxval, int type );
    
    • 参数说明
    src 输入矩阵
    dst 输出矩阵
    thresh 阀值
    maxval 最大值(这里通常设置为255)
    thresholdType 分割类型
    
    • 分割类型说明
    //value 矩阵中一个单位的颜色的值
    //threshold 阀值
    CV_THRESH_BINARY      =0,  /**value > threshold ? max_value : 0       */
        CV_THRESH_BINARY_INV  =1,  /**value > threshold ? 0 : max_value       */
        CV_THRESH_TRUNC       =2,  /** value > threshold ? threshold : value   */
        CV_THRESH_TOZERO      =3,  /**value > threshold ? value : 0           */
        CV_THRESH_TOZERO_INV  =4,  /** value > threshold ? 0 : value */
    
    • 使用
        cv::threshold(resultImage, resultImage, 100, 255, CV_THRESH_BINARY);
    
    阀值为100二值化.png

    这里又有一个很重要的点,阀值的确定,我是在某个博客找到个计算阀值的算法,不过不是很理想,现在也贴出来,但是不知道作者是谁了,很抱歉...

    int cvThresholdOtsu(IplImage* src)
    {
        int height=src->height;
        int width=src->width;
        
        //histogram
        float histogram[256]={0};
        for(int i=0;i<height;i++) {
            unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i;
            for(int j=0;j<width;j++) {
                histogram[*p++]++;
            }
        }
        //normalize histogram
        int size=height*width;
        for(int i=0;i<256;i++) {
            histogram[i]=histogram[i]/size;
        }
        
        //average pixel value
        float avgValue=0;
        for(int i=0;i<256;i++) {
            avgValue+=i*histogram[i];
        }
        
        int threshold = 0;
        float maxVariance=0;
        float w=0,u=0;
        for(int i=0;i<256;i++) {
            w+=histogram[i];
            u+=i*histogram[i];
            
            float t=avgValue*w-u;
            float variance=t*t/(w*(1-w));
            if(variance>maxVariance) {
                maxVariance=variance;
                threshold=i;
            }
        }
        
        return threshold;
    }
    
    • 截取卡号区域
      思路,现将黑色的点放大,这样点会连接到一起,变成一块儿黑色,然后我们通过图片的轮廓,宽高比例来寻找复合的一个区域,将其截取下来

    腐蚀&膨胀

    • 官方解释:
      腐蚀:进行腐蚀操作时,将内核B划过图像,将内核B覆盖区域的最小相素值提取,并代替锚点位置的相素。
      膨胀:进行膨胀操作时,将内核B划过图像,将内核B覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。对上图采用膨胀操作我们得到:
    • 个人理解:
      腐蚀:定义一个size,用这个size替换图片每个点(加粗)
      膨胀:与腐蚀相反(变细)
      个人的认识比较low,在这里呢使用腐蚀目的是将相近的黑色点连接到一块,已便后面获取所有数字连接到一块儿的轮廓,对比每个轮廓的宽高比,截取到卡号区域。
    cv::Mat erodeElement = getStructuringElement(cv::MORPH_RECT, cv::Size(25,1));
    cv::erode(resultImage, resultImage, erodeElement);
    
    腐蚀之后的照片

    在图像中寻找轮廓

    • 方法
    //获取图片轮廓
    findContours( InputOutputArray image, OutputArrayOfArrays contours,
                                  int mode, int method, Point offset = Point());
    //将存放Point的数组转为Rect
    Rect boundingRect( InputArray points );
    
    • findContours参数说明
    InputOutputArray:输入输出的图片
    OutputArrayOfArrays:输出的轮廓点,这是一个三维数
    std::vector<std::vector<cv::Point>> contours;
    
    mode:轮廓检索模式,具体参考cv::RetrievalModes
    CV_RETR_EXTERNAL:只检索最外面的轮廓;
    CV_RETR_LIST:检索所有的轮廓,并将其放入list中;
    CV_RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
    CV_RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次。
    
    method:轮廓近似法,具体参考cv::ContourApproximationModes
    CV_CHAIN_CODE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
    CV_CHAIN_APPROX_NONE:将所有的连码点,转换成点。
    CV_CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
    CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用the flavors of Teh-Chin chain近似算法
    的一种。
    CV_LINK_RUNS:通过连接水平段的1,使用完全不同的边缘提取算法。使用CV_RETR_LIST检索模式能使用此方法。
    offset:偏移量,用于移动所有轮廓点。
    
    • 使用
        cv::findContours(resultImage, contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
    

    根据轮廓选取目标区域

    (未完)

    相关文章

      网友评论

          本文标题:OpenCV+TesseractOCRiOS实现身份证号/银行卡

          本文链接:https://www.haomeiwen.com/subject/icpotxtx.html