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

2017-08-11  本文已影响0人  一蓑烟雨满眼风波

声明:思路来源于 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;
}

腐蚀&膨胀

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 );
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));

根据轮廓选取目标区域

(未完)

上一篇下一篇

猜你喜欢

热点阅读