简介
最近做一个识别护照护照号码OCR的项目,需要识别一张图像的护照号码,每张图片的号码的位置有些变化,这样就不好截取护照号码的图像,好在护照号码的以“ED”开头,长度,宽度固定.于是可以使用Emgu的模板匹配函数MatchTemplate来匹配字符串“ED”,以确定护照号码的开始位置,截取图片,然后使用Tesseract OCR来识别截取的图片中的护照号码.
MatchTemplate接口:
void MatchTemplate(IInputArray image, IInputArray templ, IOutputArray result, TemplateMatchingType method, IInputArray mask = null);
参数解释:
image-被匹配的图像矩阵(W*H)
templ-模板图像矩阵(w*h)
result-匹配结果矩阵((W-w)(H-h)):templ图像和image的卷积即temp在image图像上面从左到右,从上往下滑动,所以矩阵的大小是((W-w)(H-h)),result矩阵存放的数据是每个位置的图像的匹配度.
method-图像的匹配度计算方法:
method=TemplateMatchingType.Sqdiff,使用平方差的方法计算匹配度,很显然匹配度越高,平方差的和就越小,如果完全匹配,则平方差的和就为0,使用MinMaxLoc计算矩阵最大 最小值的时候,需要取最小值的位置坐标.
method=TemplateMatchingType.CcorrNormed,使用归一化相关系数匹配法计算匹配度.这个公式使用使用余弦相似度计算两个图像矩阵的相似度.详情参考(https://blog.csdn.net/u012160689/article/details/15341303),所以,匹配度越高,相关系数就越大,如果完全匹配,则相关系数为1(0度夹角的余弦值为1,完全相似),使用MinMaxLoc计算矩阵最大 最小值的时候,需要取最大值的位置坐标.
- 代码
/// <summary>
/// 获取匹配图像的位置
/// </summary>
/// <param name="Src">被匹配的源图像</param>
/// <param name="Template">模板图像</param>
/// <returns>匹配位置</returns>
Rectangle GetMatchPos(Mat Src,Mat Template)
{
Mat MatchResult = new Mat();//匹配结果
CvInvoke.MatchTemplate(Src, Template, MatchResult, Emgu.CV.CvEnum.TemplateMatchingType.CcorrNormed);//使用相关系数法匹配
Point max_loc = new Point();
Point min_loc = new Point();
double max = 0, min = 0;
CvInvoke.MinMaxLoc(MatchResult, ref min, ref max, ref min_loc, ref max_loc);//获得极值信息
DisplayInfo("\r\nX:" + max_loc.X + " Y:" + max_loc.Y + " 最大相似度:" + max + " 最小相似度:" + min);
return new Rectangle(max_loc,Template.Size);
}
运行效果:
就这样完成了一张图片的护照号码的截取,但是有时由于翻页的机构的问题,多翻了一页,导致图片里边没有护照号码,需要提示人工翻到资料页,这时就需要使用最大相似度max判断图片是否包含护照号码,经过多个样本测试,相似度小于0.98就表示该图片里边没有护照号码,翻页机构出问题了.