前一阵子一直在写关于图像识别的东西,说实话,大大小小的困难遇到了不少,有一些bug真的非常非常蠢。。。。。。现在看来,还是自己太菜,opencv学的不精,对神经网络的理解也不够透彻,当然也包括一些C++语言上的不熟练,所以也能看出,代码能力虽然一部分取决于理论知识,但更多的是练啊啊啊啊啊啊啊!!!
下面进入正题。
跟题目说的一样,项目是关于图像识别的。是可以用来识别照片或图片的内容,然后识别出来后转成对应的文本,然后再对文本进行相应的处理的这么一个东西。成型的想法是类似于小猿搜题的这种App,大致思路是把包含题目的图片送入识别系统,然后由识别系统识别出题目的文本内容,然后把内容交给服务器,服务器去请求网络访问,进而返回该题的最优的匹配结果,这是最基本的功能。而本篇文章所要讨论的是前一部分内容,即识别系统。
识别系统分为图像的预处理,图像分割,图像特征提取和图像识别。
预处理阶段包括二值化啊,灰度转换啊,腐蚀啊,膨胀啊等操作,目的就是为了降低噪声,减少数据量等。
图像分割阶段就是在预处理完之后,把图像中一行行的字符分割成单个字符,以便于后面对单个字符进行识别,方法我采用的是分别对行列进行投影的经典方法。代码如下:
for(int col=0;col<width;++col)
{
for(int row=0;row<height;++row)
{
PerPixelValue = image.at<uchar>(row,col);
if(PerPixelValue == 255)
{
vec[col]++;
}
}
}
for(int i = 0;i<Image.cols;++i)
{
if(!InBlock && vec[i]!=0)//已进入字符区
{
InBlock = true;
StartIndex = i;
std::cout<<"StartIndex is"<<StartIndex<<std::endl;
}
else if(vec[i]==0 && InBlock)//进入空白区
{
EndIndex = i;
InBlock = false;
cv::Mat roiImg = Image(cv::Range(0,Image.rows),cv::Range(StartIndex,EndIndex+1));
RoiList.push_back(roiImg);
}
}
特征提取方面可以选择的面有很多,我选择的是梯度分布特征和灰度统计特征。梯度特征指的是计算图像水平方向和竖直方向的梯度图像,然后通过给梯度图像分划不同的区域,进行梯度图像每个区域亮度值的统计。具体步骤如下:
<1>将字符由RGB转化为灰度,然后将图像归一化到16*8;
<2>定义soble水平检测算子:x_mask=[−1,0,1;−2,0,2;–1,0,1]和