1.概述
OCR字符识别,最常用的就是图像分割+模板匹配,前面博客中已经有写车牌识别过程中进行图像分割处理的流程,本文重点讲解如何使用汉明距离计算图像的模板匹配从而进行数字识别。
图像识别硬件:stm32F407VET6 ,192KB RAM,168MHz主频,具备DCMI数字图像接口,采用无FIFO OV7670图像,直接采集摄像头数据;
2.整体设计思路
汉明距离是用来计算两幅图像相似度的一种快速有效的方法,特别是对于数字/字符这种简单、结构清晰的目标图像,直接计算汉明距离可有效进行模板匹配;汉明距离的原理是计算两个图像中对应位置为1的累计个数,相同的个数越多,相似度越高;
对于二值化图像来说,如果0xff表示有效像素,即代表对应的0xff越多,相似度越高;也就是说直接选择模板为二值化图像,可使用图像二值化和数字分割,然后进行图像缩放进行快速计算;最后计算目标图像与二值化模板的汉明距离即可实现数字模板匹配;
2.数字识别流程
(1)图像采集,前面博文有介绍图像采集的流程,不懂的可以去看看,这里直接将摄像头设置为YUV422图像输出,然后在DMA传输中断处理函数中,将Y分量拷贝至图像缓存,直接得到灰度图像,不用再进行复杂的图像变换处理。
(2)图像二值化处理,对于简单背景的图像直接均值二值化,对于有光照影响的采用OTSU自适应阈值分割;
OTSU二值化分割:
int OtsuThread(unsigned char *src,int width,int height)
{
int th;
const int GrayScale = 256; //单通道图像总灰度256级
unsigned char*psrc=src;
int pixCount[GrayScale] = {
0};//每个灰度值所占像素个数
int pixSum = width * height;//图像总像素点
float pixPro[GrayScale] = {
0};//每个灰度值所占总像素比例
float w0, w1, u0tmp, u1tmp, u0, u1, deltaTmp, deltaMax = 0;
for(int i = 0; i < pixSum ; i++)
{
pixCount[*psrc++];//统计每个灰度级中像素的个数
}
for(int i = 0; i < GrayScale; i++)
{
pixPro[i] = pixCount[i] * 1.0 / pixSum;//计算每个灰度级的像素数目占整幅图像的比例
}
for(int i = 0; i < GrayScale; i++)//遍历所有从0到255灰度级的阈值分割条件,测试哪一个的类间方差最大
{
w0 = w1 = u0tmp = u1tmp = u0 = u1 = deltaTmp = 0;
for(int j = 0; j < GrayScale; j++)
{
if(j <= i)//背景
{
w0 += pixPro[j];
u0tmp += j * pixPro[j];
}
else//前景
{
w1 += pixPro[j];
u1tmp += j * pixPro[j];
}
}
u0 = u0tmp / w0;
u1 = u1tmp / w1;
deltaTmp = (float)(w0 *w1* pow((u0 - u1), 2)); //类间方差公式
g = w1 * w2 * (u1 - u2) ^ 2
if(deltaTmp > deltaMax)
{
deltaMax = deltaTmp;
th = i;
}
}
return th;
}
(2)图像分割,将二值化后的图像进行横向和纵向像素统计,然后进行数字区域分割处理,提取出每个数字的位置坐标;对于对齐的目标,采用这种简单分割即可实现,对于非对齐的目标,可以采用计算连通域的方式获取每个目标的位置;以及倾斜的目标,可以先分割再采用图像旋转的方法进行处理;
(3)图像缩放,将图像缩放到二值化模板大小,缩放的快速算法在前面车牌识别的博文中也有介绍;字符取模方法:先用字符取模软件,生成字符模板,或者用matlab将图像转换成二值化模板方便计算;
(4)汉明距离计算相似度
//***************
输入: 目标图像,模板个数
输出:模板匹配结果
*********************//
void Hanming_zoen(unsigned char *iamge_zoen,unsigned char numb)
{
unsigned short i,kk,number,hanming_value,numb_tem=0;
unsigned char error[numb];//记录每个模板的误差个数
float zoen_rate;
char result; //字符结果
for(i=0;i<numb;i++)
{
for(kk=0;kk<MODULE_LENGTH;K++) //MODULE_LENGTH为单个模板的长度
{
if(image_zoen[kk]==TARGET_VAL) //TARGET_VAL由二值化后有效像素决定
{
number++;
if(module[i][kk]==TARGET_VAL) //module为const 型模板数据
{
hanming_value++;
}
}
}
zoen_rate=1.0*hanming_value/number;//将汉明值转换成相似度;
if(zoen_rate>0.5) error[i]=number-hanming_value;
else error[i]=255;
number=0;
hanming_value=0;
}
for(i=0,number=0;i<numb;i++)
{
if(error[i]<error[number]
{
number=i; //找误差最小的一个
}
}
result=table_char[number];
printf("result:%s",result);//串口输出结果
}
```