ios身份证识别opencv+TesseractOCR

第一次写简书,多见谅。
本文运用opencv+TesseractOCR来实现身份证识别姓名和身份证号
查阅并引用了很多文章
opencv安装及入门
OpenCV在iOS上的应用尝试
在身份证识别上,由于相机拍摄的亮度及其他问题难点在于图片的阈值二值化的判断,用过固定阈值二值化、局部阈值二值化、平均阈值二值化都不理想。
基于opencv的一种局部自适应快速二值化方法(积分法)文章中方法解决了光照不均匀的图像中进行二值化。


//扫描身份证图片,并进行预处理,定位号码区域图片并返回

- (NSArray*)opencvScanCard:(UIImage*)image {

//将UIImage转换成Mat

cv::MatresultImage;

UIImageToMat(image, resultImage);

//先用使用3x3内核来降噪

blur( resultImage, resultImage,cv::Size(3,3),cv::Point(-1,-1));

//UIImage *Image2 = MatToUIImage(resultImage);

////固定阈值二值化

//cv::threshold(resultImage, resultImage, 100, 255, CV_THRESH_BINARY);

////局部阈值二值化

//cv::adaptiveThreshold(resultImage, resultImage, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 3, 5);

////平均阈值二值化

//IplImage imgTopDown = resultImage;

//CvScalar mean ,std_dev;//平均值、标准差

//double u_threshold,d_threshold;

//cvAvgSdv(&imgTopDown,&mean,&std_dev,NULL);

//u_threshold = mean.val[0] +1.5* std_dev.val[0];//上阀值

//d_threshold = mean.val[0] -1.5* std_dev.val[0];//下阀值

//u_threshold = mean.val[0];

//d_threshold = mean.val[0];

////u_threshold = mean + 2.5 * std_dev; //错误

////d_threshold = mean - 2.5 * std_dev;

//std::cout<<"The TopThreshold of this Image in TopDown is:"<

//std::cout<<"The DownThreshold of this Image in TopDown is:"<

//cv::threshold(resultImage,resultImage,d_threshold,u_threshold,CV_THRESH_BINARY);//上下阀值

//积分阈值二值化

resultImage =AdaptiveThereshold(resultImage, resultImage);

//腐蚀,填充(腐蚀是让黑色点变大)

cv::MaterodeElement =getStructuringElement(cv::MORPH_RECT,cv::Size(22,22));

cv::erode(resultImage, resultImage, erodeElement);

//轮廊检测

std::vector> contours;//定义一个容器来存储所有检测到的轮廊

cv::findContours(resultImage, contours,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0));

//cv::drawContours(resultImage, contours, -1, cv::Scalar(255),4);

//取出身份证号码区域

std::vector rects;

cv::RectNameNumberRect =cv::Rect(0,0,0,0);

cv::RectCardNumberRect =cv::Rect(0,0,0,0);

std::vector>::const_iteratoritContours = contours.begin();

for( ; itContours != contours.end(); ++itContours) {

cv::Rectrect =cv::boundingRect(*itContours);

rects.push_back(rect);

//算法原理

if(rect.width> CardNumberRect.width&& rect.width> rect.height*6) {

CardNumberRect = rect;

}

if(rect.x>60&& rect.y<120&& rect.height*2< rect.width) {

NameNumberRect = rect;

}

}

//定位成功成功,去原图截取身份证号码区域,并转换成灰度图、进行二值化处理

//去原图截取身份证姓名区域,并转换成灰度图、进行二值化处理

cv::MatmatImage;

UIImageToMat(image, matImage);

cv::MatNameImageMat;

NameImageMat = matImage(NameNumberRect);

IplImagegrey = NameImageMat;

unsignedchar* dataImage = (unsignedchar*)grey.imageData;

intthreshold =Otsu(dataImage, grey.width, grey.height);

printf("阈值:%d\n",threshold);

NameImageMat =AdaptiveThereshold(NameImageMat, NameImageMat);

UIImage*NameImage =MatToUIImage(NameImageMat);

cv::MatCardImageMat;

CardImageMat = matImage(CardNumberRect);

CardImageMat =AdaptiveThereshold(CardImageMat, CardImageMat);

UIImage*CardImage =MatToUIImage(CardImageMat);

//身份证号码定位失败

if([publicClassobjectIsEmpty:CardImage]||[publicClassobjectIsEmpty:NameImage]) {

returnnil;

}

NSArray* arr =@[NameImage,CardImage];

returnarr;

}

局部自适应快速积分二值化方法

cv::Mat AdaptiveThereshold(cv::Mat src,cv::Mat dst)
{
    cvtColor(src,dst,CV_BGR2GRAY);
    int x1, y1, x2, y2;
    int count=0;
    long long sum=0;
    int S=src.rows>>3;  //划分区域的大小S*S
    int T=15;         /*百分比,用来最后与阈值的比较。原文:If the value of the current pixel is t percent less than this average
                       then it is set to black, otherwise it is set to white.*/
    int W=dst.cols;
    int H=dst.rows;
    long long **Argv;
    Argv=new long long*[dst.rows];
    for(int ii=0;ii<dst.rows;ii++)
    {
        Argv[ii]=new long long[dst.cols];
    }
    
    for(int i=0;i<W;i++)
    {
        sum=0;
        for(int j=0;j<H;j++)
        {
            sum+=dst.at<uchar>(j,i);
            if(i==0)
                Argv[j][i]=sum;
            else
                Argv[j][i]=Argv[j][i-1]+sum;
        }
    }
    
    for(int i=0;i<W;i++)
    {
        for(int j=0;j<H;j++)
        {
            x1=i-S/2;
            x2=i+S/2;
            y1=j-S/2;
            y2=j+S/2;
            if(x1<0)
                x1=0;
            if(x2>=W)
                x2=W-1;
            if(y1<0)
                y1=0;
            if(y2>=H)
                y2=H-1;
            count=(x2-x1)*(y2-y1);
            sum=Argv[y2][x2]-Argv[y1][x2]-Argv[y2][x1]+Argv[y1][x1];
            
            
            if((long long)(dst.at<uchar>(j,i)*count)<(long long)sum*(100-T)/100)
                dst.at<uchar>(j,i)=0;
            else
                dst.at<uchar>(j,i)=255;
        }
    }
    for (int i = 0 ; i < dst.rows; ++i)
    {
        delete [] Argv[i];
    }
    delete [] Argv;
    return dst;
}

TesseractOCR识别文字

//利用TesseractOCR识别文字
- (void)tesseractRecognizeImageArr:(NSArray *)arr compleate:(CompleateBlock)compleate {
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        NSMutableArray* marr = [NSMutableArray array];
        for (int i = 0; i<arr.count; i++) {
            G8Tesseract *tesseract;
            if(i==0){
                tesseract = [[G8Tesseract alloc] initWithLanguage:@"chi_sim"];
            }else{
                tesseract = [[G8Tesseract alloc] initWithLanguage:@"eng"];
            }
            tesseract.image = [arr[i] g8_blackAndWhite];
            tesseract.image = arr[i];
            // Start the recognition
            [tesseract recognize];
            //执行回调
            [marr addObject:tesseract.recognizedText];
        }
        compleate(marr[0],marr[1]);
        
    });
}

参考文章:
iOS身份证号码识别
demo下载:
由于包含字体库,demo比较大,还有下载完后请自行pod install。
idCardOpencv

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容