前段时间,研究了下Emgu图像处理,发现也可以做OCR识别,依赖中文字库chi_sim.traineddata,网络搜一下Tesseract字库,我记得我是在github上下载的,有需要的自己去下载。
后来公司需要做证件的ocr识别,当时是用的别人的收费的ocr识别,基于此自己也试着抽时间简单的实现了一下OCR识别身份证,包括切出头像照片。
总体思路:
1、为了增加识别率,照片需要清晰度高,并且光线充足;
2、要求证件照片端正,并完全占满整个照片;
3、考虑到身份证各个部分内容在证件中都是固定位置,可以首先将各部分内容单独切图;以减少噪音,增加识别的准确性;
4、单独对这些图做灰度、二值化处理;
5、最后对处理后的图片做ocr识别;
具体图片:
1、定义好,各部分的区域
Size sSource = new Size(450, 290);
Rectangle rName = new Rectangle(90, 30, 290 - 90, 40);
Rectangle rSex = new Rectangle(90, 70, 130 - 90, 40);
Rectangle rNation = new Rectangle(207, 70, 290 - 207, 40);
Rectangle rBirth = new Rectangle(90, 108, 290 - 90, 140 - 108);
Rectangle rYear = new Rectangle(90, 108, 138 - 90, 140 - 108);
Rectangle rMonth = new Rectangle(165, 108, 198 - 165, 140 - 108);
Rectangle rDay = new Rectangle(228, 108, 258 - 228, 140 - 108);
Rectangle rAddress = new Rectangle(90, 140, 295 - 90, 220 - 140);
Rectangle rNumber = new Rectangle(195, 230, 450 - 195, 270 - 230);
Rectangle rFace = new Rectangle(290, 30, 440 - 290, 230 - 30);
2、加载源图
OpenFileDialog of = new OpenFileDialog();
of.Title = "请选择图片";
if (of.ShowDialog() == DialogResult.OK)
{
image = new Image<Bgr, byte>(of.FileName);
picFace.Image = image.GetSubRect(getRect(sSource, rFace, image.Size)).ToBitmap();
picSource.Image = image.ToBitmap();
}
3、从原图中切出需要的图片,做灰度处理、二值化处理
Image<Bgr, Byte> imageSource = image.GetSubRect(getRect(sSource, rName, image.Size));
picName1.Image = imageSource.ToBitmap();
Image<Gray, byte> imageGrayscale = imageSource.Convert<Gray, Byte>();
iName = imageGrayscale.ThresholdBinary(new Gray(100), new Gray(255));
this.picName.Image = iName.ToBitmap();
4、定义OCR关键代码,并识别文字
Emgu.CV.OCR.Tesseract _ocr = new Emgu.CV.OCR.Tesseract(Application.StartupPath + @"\tessdata", "chi_sim", OcrEngineMode.Default);
_ocr.Recognize(iName);
String text = _ocr.GetText();
this.textBox1.Text = text + "\n";
/// <summary>
/// 获取实际图片大小的Rectangle
/// </summary>
/// <param name="sSource"></param>
/// <param name="rSource"></param>
/// <returns></returns>
private Rectangle getRect(Size sSource, Rectangle rSource, Size sDec)
{
return new Rectangle((rSource.X * sDec.Height / sSource.Height), (rSource.Y * sDec.Width / sSource.Width), (rSource.Width * sDec.Width / sSource.Width), (rSource.Height * sDec.Height / sSource.Height));
}
最后的效果如下:
最后说明:
这里指贴出了部分关键代码,代码看懂后,其他的就可以自己补充了;
识别的准确性,与中文字库有关,这是一个不可控的因素,想要准确,可以自己试着训练自己的字库;
二值化处理时,可以适当的调整阈值的大小,这里使用了100,255
iName = imageGrayscale.ThresholdBinary(new Gray(100), new Gray(255));
这里说一下大家最关心的准确率,我使用了自己身份证照片做模板,调整阈值后,识别的准确率是100%;
同时用了同事的3张身份证测试,别率基本可以达到99%;识别错误的基本集中在地址文字中。
感兴趣可以自己试试;