看了一些数字识别的文章,研究了一翻得到一些心得,这里就不保留完全写上来!
博主原来做游戏辅助也有数字识别,当时用的是特征码技术,这种技术识别2D的数字还是非常准确的,因为2D游戏数字像素点很纯,比如字体是纯白色,然后R,G,B都是255,那我只取255,255,255指定区域的所有像素,然后生成一个数字特征码,比如0就是"62226"表示0,"02810"表示1,"43333"表示2,
这个特征码就是图片像素的宽和高中取得对应坐标的白色像素点。但如果用于有锯齿或者有渐变的游戏数字就识别不了了,因为这个针对性太强了,一对一。不过也不怕,也有解决方案。我们可以把数字二值化,然后取得各数字的像素和,0~9的像素和各不一样,后期就按这个像素和来判断是哪个数字。这种方法不仅高效,而且准确性也相当不错。当然前提是字体和大小都一样,如果不一样的话,那肯定也不自然不准了。
思想就这些,实现方法百度一查就一大堆,我这里就不写了。几十行代码的事儿!
void COpenCv::IdenNumer(void)
{
//数字识别流程处理,方案:首先二值化取出所有的数字,然后切割每个一数字,
//求每个数字的像素平方和(就是所有像素总和)去对应模板数字的总和,相差最小的应该就是对应的数字了
IplImage* src = cvLoadImage("20131112221252453.png",CV_LOAD_IMAGE_GRAYSCALE);//CV_LOAD_IMAGE_GRAYSCALE加载灰度图
//对大于dThreshold的像素值进行截断,大于dThreshold则为255,不大于dThreshold的为原值
cvThreshold(src,src,0,255,CV_THRESH_OTSU);//二值化处理CV_THRESH_OTSU适用于局部颜色色差大
//接下来找到轮廓
CvMemStorage *pStore = cvCreateMemStorage();//创建一个内存存储器
CvSeq *pOut = NULL;//CvSeq本身就是一个可增长的序列,不是固定的序列
cvFindContours(src,pStore,&pOut,sizeof(CvContour),CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);//从二值位图找轮廓
//cvFindContours(img,pStore,&pOut,sizeof(CvContour),CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
//填充所有轮廓
cvDrawContours(src, pOut, CV_RGB(255,255,255),CV_RGB(255,255,255), 2, CV_FILLED, 8, cvPoint(0, 0));
vector<Mimg> vec;
while(pOut)
{
CvRect rect = cvBoundingRect(pOut,0);
//绘制出每个数字的轮廓
//cvRectangle(src, cvPoint(rect.x, rect.y), cvPoint(rect.x + rect.width, rect.
// y + rect.height),CV_RGB(255,255,255), 1, 1, 0);
cvSetImageROI(src,rect);
IplImage* dst = cvCreateImage(cvSize(rect.width,rect.height),src->depth,src->nChannels);
cvCopy(src,dst);
cvResetImageROI(src);
Mimg img = {rect,dst};
vec.push_back(img);
pOut = pOut->h_next;//下一个值
}
//这里按坐标从左到右排序
std::sort(vec.begin(),vec.end(),SortFunc);//排序
for (vector<Mimg>::iterator it=vec.begin();it!=vec.end();it++)
{
//从左右到识别
}
cvReleaseMemStorage(&pStore);
pStore = NULL;
//cvShowImage("",src);
cvReleaseImage(&src);
}
本文链接:https://it72.com/11137.htm