使用C++结合Opencv库实现简易汉字识别。
导入图像进行一系列预处理,使其便于用来识别和其他计算。
灰度化
使用opencv的库函数来实现。
cv::cvtColor(image, image_gray, CV_BGR2GRAY);
二值化
同样选用库函数来实现,本例使用的是自适应二值化函数。
cv::adaptiveThreshold(image_gray, image_value, 255, 0, 1, 5, 10);
降噪(去除干扰线)
实现的思路并非去除干扰线,而是尽量不把干扰线选中到识别区域。
先通过腐蚀,使较细的干扰线消去。
erode(image_value, temp, kernel2);
再通过膨胀,使汉字主体明显。
dilate(temp, dst, kernel1);
轮廓识别
使用库函数找出外轮廓点集。
findContours(dst, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point());
最小矩阵
汉字分割
灰度化
本身就只有大部分为黑白色,故灰度化结果不明显。
二值化
可以发现干扰线已经基本看不见了,但是汉字好似被断裂开。不利于后面的寻找轮廓,故进行膨胀操作。
膨胀
膨胀有两个目的:一是使腐蚀后断裂的文字合起来。二是使某些上下结构或左右结构明显的字合起来。否则在识别(吴)的区域时,容易将(口)(天)分别框出,不利于识别整体的汉字。
最小矩阵
在膨胀后的基础上,寻找轮廓,并找出轮廓的最小矩阵。
切割后保存
框出文字的矩阵只在测试时画出,实际裁剪保存的时候,并不绘制出矩阵,是为了排除矩阵的存在对识别精确度的影响。
分割后保存的模板
本例使用直方图匹配的方式,此方式的精确度实际并不高。其他如卷积神经网络难度较大,暂时没有足够的时间研究。故采用此种方法。
主要是将c。三者关系一一对应。找出与识别对象的直方图数据匹配图最高的模板图像,就可以确定其文字。
模板图像——直方图数据——汉字
采用结构体。
struct pimage {
char c_name[3];
Mat img_zft;
};
从模板数据库中,读取每张文字对应的图片。将其灰度化后,计算直方图数据。
本例的数据都没有采用写入到文件的方式保存,故每次运行前都要导入一次模型,用于计算这些数据。
数据关联
for (i = 0; i < num; i++) {
//直方图计算
calcHist(&imgNo_gray[i], 1,&channels ,Mat(), hist[i], 1, &histSize,&phranges_arr);
strcpy_s(p_imgNo[i].c_name, img_word[i]);//手写字关联
p_imgNo[i].img_zft = hist[i];//直方图关联
}
完成上面的模型制作,以及数据关联后。就可以进行识别过程了。
先进行预处理过程,再同样计算直方图。和模型数据进行对比。
double Compare,compare;
int word = 0;
for (int j = 0; j < contours.size()-1; j++) {
if (contours[j].size() < 10) { word++; continue; }
compare = 0;
for (int k = 0; k < num; k++) {
//使用CV_COMP_CORREL方法进行对比
Compare = compareHist(hist1[j], p_imgNo[k].img_zft, 0);
//精准度达90%
if (Compare >= 0.9) {
if (compare > Compare) { continue; }
else {
compare = Compare;
strcpy_s(p_img[j].c_name, p_imgNo[k].c_name);
}
}
}
}
//识别完成,输出结果
printf_s("检测到%d个文字,分别是\n",contours.size()-word);
for (int i = 0; i < contours.size(); ++i) {
cout << p_img[i].c_name;
}
constexpr auto img_data = "E:/img"; //模板图像存储路径
#define num 77 //模板汉字个数
若已有模板图的文件则无需进行训练。
操作:根据提示输入2和训练模型所用的图片。
结果:会在默认的模型保存路径存有模型图片下的每个汉字的切割图。
需要自己手动操作。
在img_word[]
数组内,按下标顺序依次输入所对应的汉字。
就是结构体内数据依次计算,存入的过程。
识别的图像最好是模板图或者其截图的一部分。这是由于使用直方图匹配,重复的概率太大所导致的。
根据提示操作即可。
可以发现识别的准确率还是很高的。
思路就是这样,源码也有。
源码