📄 subject_36020.htm
字号:
<p>
序号:36020 发表者:许剑峰 发表日期:2003-04-11 12:52:19
<br>主题:求简单的文字识别源代码
<br>内容:想要一个简单的文字识别vc源代码,从黑白图像中识别出文字,就是背景是白色,文字是黑色。只需简单识别英文26个大小写字母就够了。
<br><a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p>
<hr size=1>
<blockquote><p>
<font color=red>答案被接受</font><br>回复者:jinzuo 回复日期:2003-04-11 18:07:38
<br>内容:To xujianfeng:<BR> 我做过类似的程序,用摄像头采集类似于电话充值卡的图象,对其的卡号,密码区域进行识别,只识别数字。(0-9)但原理相同,你只需改一下字库即可使用。<BR> 我先说下步骤:<BR> 1. 字符和字符之间都有间隔,首先要根据间隔确定每个字符的区域(Rect).<BR> 2. 然后一个一个象素地和标准字符比较。也就是比较 26 * 2 = 52 次,误差最小的,就认为是该字符。<BR>(注:这种算法比较简单,易于理解,缺点就是效率不高,我用摄像头采集图象识别数字成功率为 98%以上。我曾请教过一位做这方面的专家,他称无论什么识别,影响识别的最重要因数就是源图象的质量。如果识别率不到 90% 请你仔细考虑源图象的采集质量,并重新考虑该方法的可行性。)<BR> 附代码如下:<BR><BR>/** 取得每个字符的边界***/<BR>void CPOCRNuberDlg::GetCharRect(HBITMAP bit, RECT rect,int type, CDC* pDC )<BR>{<BR> CString strTemp2;<BR> CBitmap bitmap;<BR> bitmap.m_hObject = CopyImage(bit,IMAGE_BITMAP,0,0,LR_MONOCHROME);<BR><BR> //CDC *pDC = GetDC();<BR> CDC mDC;<BR> <BR> mDC.CreateCompatibleDC( pDC );<BR> mDC.SetBoundsRect( &rect, DCB_RESET);<BR> mDC.SelectObject(bitmap.m_hObject);<BR><BR> BOOL bIsChar = false;<BR> corInfo = new OCR_Info[50];<BR> int index = 0;<BR><BR> COLORREF colPix;<BR> int iR;<BR> int iG;<BR><BR>/************** 取出每个数字所占的Rect **************/<BR>// 列扫描<BR><BR> CString str;<BR> for (int i = rect.left; i < rect.right ; i++)<BR> {<BR> for (int j = rect.top - 250 ; j < rect.bottom - 250; j++)<BR> {<BR> colPix = mDC.GetPixel(i,j);<BR> iG = GetGValue(colPix);<BR> <BR> // 字符开始<BR> if ( (iG == 0) && (!bIsChar) )<BR> {<BR> corInfo[index].rect.left = i;<BR> corInfo[index].Index = index;<BR> bIsChar = true;<BR> <BR> break;<BR> }<BR> // 字符继续<BR> else if ((iG == 0) && (bIsChar))<BR> {<BR> break;<BR> }<BR> // 字符结束<BR> else if ((iG == 255) && ( j > rect.bottom -252) && (bIsChar))<BR> {<BR> corInfo[index].rect.right = i-1;<BR> if ((corInfo[index].rect.right - corInfo[index].rect.left) > 3)<BR> index++;<BR> bIsChar = false;<BR> break;<BR> }<BR> <BR> } <BR> }<BR><BR> CClientDC lDC(this);<BR> <BR>// 行扫描<BR> bIsChar = false;<BR> int iBZ =0;<BR> for ( int iinx = 0; iinx < index; iinx++)<BR> {<BR> for (int ii = rect.top-250 ; ii < rect.bottom -250; ii++)<BR> {<BR> for (int j = corInfo[iinx].rect.left ; j < corInfo[iinx].rect.right ; j++)<BR> {<BR> colPix = mDC.GetPixel(j,ii); <BR> iG = GetGValue(colPix); <BR> // 字符顶端开始<BR> if ( (iG == 0) && (!bIsChar) )<BR> {<BR> corInfo[iinx].rect.top = ii; <BR> bIsChar = true; <BR> break; <BR> }<BR> // 字符继续<BR> else if ((iG == 0) && (bIsChar))<BR> {<BR> break;<BR> }<BR> // 字符底端结束<BR> else if ((iG == 255) && ( j > corInfo[iinx].rect.right -2 ) && (bIsChar))<BR> { <BR> corInfo[iinx].rect.bottom = ii-1; <BR> bIsChar = false;<BR> break;<BR> } <BR> } <BR> }<BR> }<BR><BR>/****** 位置确定完成,每个字符的位置信息写在 corInfo.rect 中********/<BR><BR> char m_pFilePath[255];<BR> CStdioFile fInfo; <BR><BR> strcpy(m_pFilePath,"D:\\info.ini");<BR> fInfo.Open( m_pFilePath, CFile::modeCreate | CFile::modeWrite );<BR><BR> CDC NewDC; <BR> NewDC.CreateCompatibleDC(pDC);<BR> CBitmap memBmp;<BR> memBmp.CreateCompatibleBitmap( &mDC, 14, 20 );<BR> NewDC.SelectObject( memBmp );<BR>/* <BR>// 标志定义<BR> iBZ =0;<BR> BOOL bBZ = false; <BR><BR> <BR> for (int bn = 0; bn<index; bn++)<BR> {<BR> NewDC.StretchBlt( 0,0,14,20,<BR> &mDC,corInfo[bn].rect.left +1,<BR> corInfo[bn].rect.top +1,<BR> corInfo[bn].rect.right - corInfo[bn].rect.left -1,<BR> corInfo[bn].rect.bottom - corInfo[bn].rect.top -1,<BR> SRCCOPY);<BR><BR> <BR> for (int yy = 0; yy <20; yy ++)<BR> {<BR> for (int xx = 0; xx <14;xx++)<BR> {<BR> colPix = NewDC.GetPixel(xx,yy);<BR> iR = GetRValue(colPix); <BR> if (iR == 255) <BR> str = "□";<BR> else<BR> str ="■";<BR> fInfo.WriteString(str);<BR> }<BR> fInfo.WriteString("\n");<BR> }<BR> str.Format("NEXT%d\n",bn);<BR> fInfo.WriteString(str);<BR> }<BR>/************************** OCR **************************/<BR> CString strField;<BR> CString strtemp;<BR> char cNum[281];<BR> int iNumIndex = 0;<BR> int iErrCount[10];<BR> int iECount =0;<BR> int iBlack = 0;<BR> int idx = 0;<BR> int ww =0;<BR> int w = 0;<BR> <BR> GetCurrentDirectory(255,m_pFilePath);<BR> strcat(m_pFilePath,HOCRINI);<BR> //strcat(m_pFilePath,"\\stdinfo.ini");<BR>// 逐个扫描,识别 <BR> for (int l = 0; l<index; l++)<BR> { <BR> NewDC.StretchBlt( 0,0,14,20,<BR> &mDC,corInfo[l].rect.left +1,<BR> corInfo[l].rect.top +1,<BR> corInfo[l].rect.right - corInfo[l].rect.left -1,<BR> corInfo[l].rect.bottom - corInfo[l].rect.top -1,<BR> SRCCOPY); <BR><BR> for (w = 0 ;w< 10; w++)<BR> iErrCount[w] = 0;<BR><BR> for (int itmp = 0; itmp < 10; itmp++)<BR> {<BR> strtemp.Format("%d",itmp);<BR> GetPrivateProfileString("Number",strtemp,"",<BR> cNum,281,m_pFilePath);<BR> for(int iy = 0; iy < 20; iy ++)<BR> {<BR> for(int ix = 0; ix<14;ix++)<BR> {<BR> colPix = NewDC.GetPixel(ix,iy);<BR> iR = GetRValue(colPix);<BR> if (iR == 255)<BR> iR = 49;<BR> else<BR> iR = 48;<BR> if ( iR != cNum[iNumIndex])<BR> iErrCount[itmp]++; <BR> iNumIndex++; <BR> } <BR> } <BR> iNumIndex = 0; <BR> }<BR> iECount = iErrCount[0];<BR> idx = 0;<BR> for(ww =0; ww< 10; ww++)<BR> {<BR> if (iErrCount[ww] < iECount)<BR> {<BR> iECount = iErrCount[ww];<BR> idx = ww;<BR> }<BR> }<BR> // 区别1<BR> if (idx != 1)<BR> {<BR> for (int itx = 7; itx < 9; itx++)<BR> {<BR> for (int ity = 0; ity < 20; ity++)<BR> {<BR> colPix = NewDC.GetPixel(itx,ity);<BR> iR = GetRValue(colPix);<BR> if (iR == 0)<BR> iBlack++;<BR> }<BR> }<BR> if (iBlack > 39)<BR> {<BR> idx = 1;<BR> }<BR> iBlack = 0;<BR> }<BR> // 再将0 和8 进行判断<BR> if ((idx == 0) | (idx ==8))<BR> {<BR> for (int ity = 8; ity < 10; ity++)<BR> {<BR> for (int itx = 2; itx < 12; itx++)<BR> {<BR> colPix = NewDC.GetPixel(itx,ity);<BR> iR = GetRValue(colPix);<BR> if (iR == 0)<BR> iBlack++;<BR> }<BR> }<BR> if (iBlack > 14)<BR> idx = 8;<BR> else<BR> idx = 0;<BR> iBlack = 0;<BR> }<BR> // 再将5 和6 进行判断<BR> if (( idx == 5) | (idx == 6))<BR> {<BR> <BR> }<BR> str.Format("%d",idx);<BR> strTemp2 += str;<BR> /*<BR> if (type == 1)<BR> //m_CardNum += str;<BR> else<BR> //m_CardPWD += str;<BR> */<BR> }<BR> <BR>/*****************************************/<BR> delete [] corInfo; <BR><BR> if (type == 1)<BR> m_ctrlCardNum.SetWindowText( strTemp2 ); <BR> else<BR> m_ctrlCardPWD.SetWindowText( strTemp2 ); <BR> //::ReleaseDC(m_hWnd,(HDC)pDC);<BR> //UpdateData(false); <BR>}<BR> <BR>希望能对你有所帮助!<BR><BR>jinzuo007<BR>
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:许剑峰 回复日期:2003-04-11 22:12:28
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -