7.找最小矩形框
void findMinRectangle(Mat inputImg, int& st, int& ed, int& let, int& righ) { //inputImg是输入的二值图 for (int i = 0;i < inputImg.rows;i++) { int j; for (j = 0;j < inputImg.cols;j++) { if (inputImg.at<uchar>(i, j) != 0) { st = i; break; } }//找到第一行不全为0的行,并将该行作为截取的上界 if (inputImg.at<uchar>(i, j) != 0) { break; } } for (int i = inputImg.rows-1;i >= 0;i--) { int j; for (j = 0;j < inputImg.cols;j++) { if (inputImg.at<uchar>(i, j) != 0) { ed = i; break; } } //对矩阵的行反向遍历找到最后一行不全为0的行,并将该行作为截取的下界 if (inputImg.at<uchar>(i, j) != 0) { break; } } for (int j = 0;j < inputImg.cols;j++) { int i; for (i = 0;i < inputImg.rows;i++) { if (inputImg.at<uchar>(i, j) != 0) { let = j; break; } }//找到第一列不全为0的列,并将该列作为截取的左界 if (inputImg.at<uchar>(i, j) != 0) { break; } } for (int j = inputImg.cols - 1;j >= 0;j--) { int i; for (i = 0;i < inputImg.rows;i++) { if (inputImg.at<uchar>(i, j) != 0) { righ = j; break; } }//对矩阵的列反向遍历找到最后一列不全为0的列,并将该列作为截取的右界 if (inputImg.at<uchar>(i, j) != 0) { break; } } }
讲解:利用for循环对inputImg的行和列进行正向与反向的遍历,通过找到不全为0的行和列找到inputImg二值图的上界st,下界ed,左界let,右界righ,并根据st,ed,let,righ对inputImg进行截取,找到截取出的数字或字符的最小矩形框。
8.模板匹配 字符识别
//两张图做差(统计两张图片不同点像素点的个数) double absDi(Mat inputImg, Mat sampleImg) { //记录两张图不同的像素点的个数 double diffNums = 0;double sameNums = 0; for (int i=0;i<inputImg.rows;i++) { for (int j=0;j<inputImg.cols;j++) { //对应位置的像素值不同 则diffnums++ if (inputImg.at<uchar>(i, j) != sampleImg.at<uchar>(i, j)) diffNums++; else sameNums++; } } return diffNums; } //字符识别 char recognition(Mat inputImg,int k) { string sampleImgPath = "样例3"; vector<String> sampleImgFN; glob(sampleImgPath, sampleImgFN, false); int sampleImgNums = sampleImgFN.size(); vector<pair< double,int> >nums(sampleImgNums+1); for (int i = 0; i < sampleImgNums; i++) { nums[i].second= i; Mat numImg = imread(sampleImgFN[i], 0); //大小同一 resize(numImg, numImg, Size(40, 60)); resize(inputImg,inputImg,Size(40,60)); nums[i].first = absDi(inputImg, numImg); } //imshow("图片", inputImg); //waitKey(); //排序 越小说明匹配度越高 sort(&nums[0], &nums[sampleImgNums]); int index= nums[0].second; //截取模板的函数 splitSample(index,k,inputImg); return sampleImgFN[index][sampleImgPath.size() + 1]; }
讲解:字符识别用的是模板匹配这种方法实现的,具体来说就是把所有可能出现的每一个字符情况都找一定数量(我们用的在2~4个)的模板,当要识别未知字符时需要与所有模板一一比对,找到最接近的模板进行匹配。这里就有一个衡量标准的问题,即:怎样算“最接近”?我们用的是“找不同的”方法,即先将模板与待识别的字符图片调成一样大小(40X60),再对比对应位置的像素值是否相同,统计两幅图片不同的像素点的个数。如果不同点的数量越少,就认为该模板与待识别的字符越接近;因而最接近自然就是不同的像素点个数最少的模板。上面两个函数中absDi()就是用来统计不同的像素点个数的函数,而在 recognition()中就是通过找“最接近”达到模板匹配,字符识别的目的。
五、项目测试
1.图片读取效果
2.原图转灰度图效果
3.去噪效果
4.二值化效果
5.图片旋转效果
6.截取所在行效果
7.裂分割 最小矩形的效果
8.识别效果
六、研究结果并讨论
最终在不断测试用例,更换模板,调整代码之后,我们将正确率和准确率提升到了一个比较令人满意的程度,在规定时间内也完成了ISBN识别系统。这个过程中我们初步接触了 opencv+VS 的开发环境,提高了 C++语言的应用能力,也开始了解计算机视觉方面的技术以及其研究前景。明白了小组通力合作的重要性。相信在以后的项目中我们会活用这次经验来更好的迎接挑战。
结论
在本项目中我们主要任务是开发ISBN识别系统,其中运用了简单的计算机视觉技术,以实现数字识别的功能。在我们小组成员的不断努力之后,我们对训练集的测试结果为:正确率达到了九成以上,识别效果可观,可以说是较高质量的完成了这套 ISBN 识别系统的。这样的效果离不开组内成员间的齐心协力,是我们互相的鼓励让我们不畏艰难险阻砥砺前行,在代码有BUG的时候互相支持。我们能够开发出这个ISBN识别系统,也源自我们永不放弃,越挫越勇的品质。下一步准备加一个从外界读取图片的系统,以达到自动识别书籍ISBN编号的功能。
附页
开发环境
编译环境:Windows10
编译工具:VS2017
OpenCV库版本:3.4.1
项目源码下载
这个是工程文件,可以运行,这个源码和下面的不一样,正确率刚八十多,仅供参考,设置的零积分,下载不花钱
源码链接:https://download.csdn.net/download/weixin_45525272/84078100
载完了,改配置,要不也运行不了,改配置不会看这个:
https://yangyongli.blog.csdn.net/article/details/122654193
OpenCV的基础知识我也有专栏,不懂的可以看看学习:
https://blog.csdn.net/weixin_45525272/category_11211390.html
或者直接看毛佬的教程:
https://blog.csdn.net/poem_qianmo/category_9262318.html