曾静的博客

但行好事,莫问前程.

嗨,我是曾静 (@devzeng),目前暂居深圳。


这是我用来记录平日学习笔记的地方,欢迎您的访问.

iOS中使用Tesseract提取身份证号码

OCROptical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程。通俗来说就是通过对图像进行处理提取裁剪出来有字符的区域然后对字符进行识别翻译成文字。

how-ocr.png

上面的图片是来自于Baidu的在线OCR识别。本文是基于tesseract-ocr(Tesseract是一个开源的OCR引擎,可以识别多种格式的图像文件并将其转换成文本,目前已支持包括中文在内的60多种语言。)和 OpenCV(OpenCV是一个开源的跨平台计算机视觉库)进行开发的。

环境准备

1、配置Cocoapods Podfile

推荐使用Cocoapods的方式进行集成,在Podfile中添加如下两个库:

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

如果下载OpenCV的库失败,可以手动的方式进行集成。到官网下载最新版本的OpenCV iOS Framework(当前最新的版本是3.2.0)直接拖到项目里面。

opencv-download.png

2、下载tesseract的训练库

git clone https://github.com/tesseract-ocr/tessdata.git

下载各个语言包训练库完成之后,需要切换到3.04.00版本。

git checkout 3.04.00

由于本次只需要识别身份证号码使用英语的语言包训练库就可以了,删除其他的只保留eng.traineddata既可。然后以Create folder reference的方式拖到项目中(蓝色group),如下图所示。

tessdata-group.png

操作步骤

1、图像处理

(1) 转化为灰度图像
cv::cvtColor(src, dest, cv::COLOR_BGR2GRAY);
(2) 二值化
cv::threshold(src, dest, 100, 255, CV_THRESH_BINARY);
(3) 图像腐蚀填充

将规范化的2值图像进行,因为之前进行了规范化,因此这里膨胀的幅度可以设为定值;(膨胀就是将黑点扩大范围,因此有字迹的地方将会连成一片,形成很多的contours)

cv::Mat erodeElement = getStructuringElement(cv::MORPH_RECT, cv::Size(26, 26));
cv::erode(src, dest, erodeElement);
(4) 轮廓检测

图片经过腐蚀操作后相邻点会连接在一起形成一个大的区域,这个时候通过轮廊检测就可以把每个大的区域找出来,这样就可以定位到身份证上面号码的区域。使用findContours方法可以找出其中所有的轮廓(contours),将返回一个列表,得到每个人contour的位置。函数原型如下:

CV_EXPORTS void findContours(InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset = Point());

参数说明:

  • image :要寻找轮廓的图片,注意这里的轮廓会直接改变在src上(需要备份);
  • contours:输出检测到的轮廓
  • mode:轮廓检索模式。CV_RETR_TREE:检索所有的轮廓
  • method: 轮廓近似方法。CV_CHAIN_APPROX_SIMPLE :表示去掉冗余信息
  • offset: 搜索的偏移

示例代码如下:

std::vector<std::vector<cv::Point>> contours;//定义一个容器来存储所有检测到的轮廊
cv::findContours(src, contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
(5) 身份证号码提取

由于身份证号码所在位置固定,拍照方式合适,则可以根据contour的位置和其本身size,找到包含身份证号码的contour。然后将这一片从之前的二值化处理后的图像里分割出来,单独处理。

std::vector<cv::Rect> rects;
cv::Rect numberRect = cv::Rect(0,0,0,0);
std::vector<std::vector<cv::Point>>::const_iterator itContours = contours.begin();
for ( ; itContours != contours.end(); ++itContours) {
    cv::Rect rect = cv::boundingRect(*itContours);
    rects.push_back(rect);
    //算法原理: 宽度/高度 > 5
    if (rect.width > numberRect.width && rect.width > rect.height * 5) {
            numberRect = rect;
        }
    }

2、信息提取

- (void)pd_recognizeImageWithTesseract:(UIImage *)image complete:(void (^)(BOOL status, NSString *result))complete {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        G8Tesseract *tesseract = [[G8Tesseract alloc] initWithLanguage:@"eng"];
        tesseract.image = [image g8_blackAndWhite];
        tesseract.charWhitelist = @"0123456789";
        BOOL status = [tesseract recognize];
        dispatch_async(dispatch_get_main_queue(), ^{
            complete(status, tesseract.recognizedText);
        });
    });
}

3、说明:

  • (1)测试素材可以从https://cloud.baidu.com/product/ocr/idcard获取
  • (2)优化的方向有几个方面:
    • ① 调整提取号码区域的算法(腐蚀与填充、号码区域提取)
    • ② 手动进行样本训练

参考资料

1、《OpenCV官网》

2、《iOS身份证号码识别》

3、《tesseract在使用过程中的一些常见问题》

4、《iOS实现身份证号码识别》

5、《OpenCV学习开发笔记一(iOS9)》

最近的文章

CentOS安装Docker

之前写过一篇关于在Mac上面使用并安装Docker的文章《Mac上Docker的安装和使用初探》,介绍了在Macos上面安装Docker的步骤。近期由于需要在一台CentOS 6.5的服务器上面部署一些服务,考虑到使用Docker来做这些事情,记录一下处理的步骤。检查内核版本uname -r如果输出的信息为2.6.32-431.el6.centos.plus.x86_64,表示当前的内核版本是2.6.32。docker需要的内核版本是3.10,所以需要升级Linux的内核,升级的步骤如下:...…

Note继续阅读
更早的文章

Eclipse无法正常启动Tomcat项目解决办法

以前一直使用 MyEclipse 开发 JavaEE 项目,实在是太卡了,近期将之前的项目全部迁移到了 Eclipse 上面。一段时间内都好好的,这两天突然发现启动 Tomcat 不正常了,具体表现如下:(1)Tomcat 在 Eclipse 里面能正常启动,但在浏览器中访问http://localhost:8080/报404错误。也就是说 Tomcat 启动了但是里面部署的 web 项目没有启动。(2)关闭 Eclipse 里面的 Tomcat,在 Tomcat 安装目录下双击start...…

Java继续阅读