- Visual C++數字圖像模式識別典型案例詳解
- 馮偉興 梁洪 王臣業編著
- 852字
- 2018-12-31 19:39:01
3.4.2 平均值法
編程實現
[1] 在CBarRecog類中添加相應的函數PreProcess(),對條形碼圖像進行預處理,得出寬度序列,具體實現代碼如代碼3-2所示。
代碼3-2 PreProcess()函數
BOOL CBarRecog::PreProcess() { //閾值設為128 BinaryImage(160); int i, j; int tempMax; int tempArray[1000]; //進行水平方向和垂直方向上的直方圖統計 for(i=0; i<ImageHeight; i++) arPixelV[i] = 0; for(i=0; i<ImageWidth; i++) arPixelH[i] = 0; for(i=0; i<ImageHeight; i++) { for(j=0; j<ImageWidth; j++) { if(ImageArray[i][j] == 1) { arPixelV[i] += 1; arPixelH[j] += 1; } } } //尋找包含條形碼的區域 //先尋找水平方向上黑像素最大的行 tempMax = 0; for(i=0; i<ImageHeight; i++) { if(arPixelV[i]>tempMax) tempMax = arPixelV[i]; arMark[i] = false; } for(i=0; i<ImageHeight-1; i++) { //計算差分 arDifference[i] = arPixelV[i+1] - arPixelV[i]; //如果該行像素足夠多且變化不大,標記為true if( (abs(arDifference[i])<20) && (arPixelV[i]>(0.75*tempMax)) ) arMark[i] = true; } //確定包含條形碼的行 int iLengthThrehold = 40; int iCount; for(i=0; i<ImageHeight-iLengthThrehold; i++) { iCount = 0; for(j=0; j<iLengthThrehold; j++) { if(arMark[i+j] == true) iCount++; } if(iCount >= 37) { ImageTop = i+10; //確定頂部 break; } } for(i=ImageHeight-1; i>=iLengthThrehold-1; i--) { iCount = 0; for(j=0; j<iLengthThrehold; j++) { if(arMark[i-j] == true) iCount++; } if(iCount >= 37)//iLengthThrehold-3 { ImageBottom = i-10; //確定底部 break; } } //尋找左邊緣,為了保證穩健性,在已經確定的上下邊界內全局搜索 for(i=ImageTop; i<=ImageBottom; i++) { for(j=20; j<ImageWidth; j++) { if( (ImageArray[i][j-1]==0) && (ImageArray[i][j]==1) ) { arLeftEdge[i] = j; break; } } } { //為消除噪聲的干擾,下面確定準確的左邊界 tempMax = 0; int iMax = 0; for(i=ImageTop; i<=ImageBottom; i++) { if(arLeftEdge[i] > tempMax) tempMax = arLeftEdge[i]; iMax = i; } } //傾斜度不能大于1/10 iCount = 0; for(i=ImageTop; i<=ImageBottom; i++) { if( abs(tempMax-arLeftEdge[i]) < abs(i-iMax)/6+1 ) { } iCount++; } if( (iCount/(ImageBottom-ImageTop))<0.6 ) return false; //調整起點 for(i=iMax; i>ImageTop; i--) { if( abs(arLeftEdge[i]-arLeftEdge[i-1])>=2 ) { if(ImageArray[i-1][arLeftEdge[i]]-ImageArray[i-1][arLeftEdge[i]-1]== 1) arLeftEdge[i-1] = arLeftEdge[i]; else if(ImageArray[i-1][arLeftEdge[i]-1]-ImageArray[i-1][arLeft Edge[i]-2] == 1) arLeftEdge[i-1] = arLeftEdge[i]-1; else if(ImageArray[i-1][arLeftEdge[i]+1]-ImageArray[i-1][arLeft Edge[i]] == 1) arLeftEdge[i-1] = arLeftEdge[i]+1; else arLeftEdge[i-1] = arLeftEdge[i]; } } for(i=iMax; i<ImageBottom; i++) { if(i == ImageBottom) break; if( abs(arLeftEdge[i]-arLeftEdge[i+1])>=2 ) { if(ImageArray[i+1][arLeftEdge[i]]-ImageArray[i+1][arLeftEdge[i]-1] == 1) arLeftEdge[i+1] = arLeftEdge[i]; else if(ImageArray[i+1][arLeftEdge[i]-1]-ImageArray[i+1][arLeft Edge[i]-2] == 1) arLeftEdge[i+1] = arLeftEdge[i]-1; else if(ImageArray[i+1][arLeftEdge[i]+1]-ImageArray[i+1][arLeft Edge[i]] == 1) arLeftEdge[i+1] = arLeftEdge[i]+1; else arLeftEdge[i+1] = arLeftEdge[i]; } } int n; //搜索出所有的寬度 for(n=0; n<29; n++) { //搜索條的右邊緣 for(i=ImageTop; i<=ImageBottom; i++) { for(j = arLeftEdge[i]+1; j<ImageWidth; j++) { if( (ImageArray[i][j-1]==1) && (ImageArray[i][j]==0) ) { arLeftEdge1[i] = j; break; } } arDelta[i] = arLeftEdge1[i] - arLeftEdge[i]; } //假定條和空的寬度最多為11 //排序,可以認為最中間的5個寬度是平均寬度 for(i=ImageTop; i<ImageBottom; i++) tempArray[i] = arDelta[i]; for(i=ImageTop; i<ImageBottom; i++) { for(j=ImageBottom; j>i; j--) { int tempSwap; if(tempArray[j] < tempArray[j-1]) { tempSwap = tempArray[j]; tempArray[j] = tempArray[j-1]; tempArray[j-1] = tempSwap; } } } if(tempArray[ImageTop+(ImageBottom-ImageTop)/2+2]-tempArray[ImageTop+(ImageBottom-ImageTop)/2-2]>1) return false; else arWidth[2*n] = tempArray[ImageTop+(ImageBottom-ImageTop)/2]; //調整下一列邊緣 for(i=ImageTop; i<=ImageBottom; i++) { if(abs(arDelta[i] - arWidth[2*n])>2) arLeftEdge1[i] = arLeftEdge[i] + arWidth[2*n]; arLeftEdge[i] = arLeftEdge1[i]; } //搜索空的右邊緣 for(i=ImageTop; i<=ImageBottom; i++) { for(j = arLeftEdge[i]+1; j<ImageWidth; j++) { if( (ImageArray[i][j-1]==0) && (ImageArray[i][j]==1) ) { arLeftEdge1[i] = j; break; } } arDelta[i] = arLeftEdge1[i] - arLeftEdge[i]; } //假定條和空的寬度最多為11 //排序,可以認為最中間的5個寬度是平均寬度 for(i=ImageTop; i<ImageBottom; i++) tempArray[i] = arDelta[i]; for(i=ImageTop; i<ImageBottom; i++) { for(j=ImageBottom; j>i; j--) { int tempSwap; if(tempArray[j] < tempArray[j-1]) { tempSwap = tempArray[j]; tempArray[j] = tempArray[j-1]; tempArray[j-1] = tempSwap; } } } if(tempArray[ImageTop+(ImageBottom-ImageTop)/2+2]-tempArray[ImageTop+ (ImageBottom-ImageTop)/2-2]>1) return false; else arWidth[2*n+1] = tempArray[ImageTop+(ImageBottom-ImageTop)/2]; //調整下一列邊緣 for(i=ImageTop; i<=ImageBottom; i++) { if(abs(arDelta[i] - arWidth[2*n+1])>2) arLeftEdge1[i] = arLeftEdge[i] + arWidth[2*n+1]; arLeftEdge[i] = arLeftEdge1[i]; } } //搜索最后一個條的右邊緣 for(i=ImageTop; i<=ImageBottom; i++) { for(j = arLeftEdge[i]+1; j<ImageWidth; j++) { if( (ImageArray[i][j-1]==1) && (ImageArray[i][j]==0) ) { arLeftEdge1[i] = j; break; } } arDelta[i] = arLeftEdge1[i] - arLeftEdge[i]; } //假定條和空的寬度最多為11 //排序,可以認為最中間的5個寬度是平均寬度 for(i=ImageTop; i<ImageBottom; i++) tempArray[i] = arDelta[i]; for(i=ImageTop; i<ImageBottom; i++) { for(j=ImageBottom; j>i; j--) { int tempSwap; if(tempArray[j] < tempArray[j-1]) { tempSwap = tempArray[j]; tempArray[j] = tempArray[j-1]; tempArray[j-1] = tempSwap; } } } if(tempArray[ImageTop+(ImageBottom-ImageTop)/2+2]-tempArray[ImageTop+(Imag eBottom-ImageTop)/2-2]>1) return false; else arWidth[2*n] = tempArray[ImageTop+(ImageBottom-ImageTop)/2]; //調整下一列邊緣 for(i=ImageTop; i<=ImageBottom; i++) { if(abs(arDelta[i] - arWidth[2*n+1])>2) arLeftEdge1[i] = arLeftEdge[i] + tempArray[ImageTop+(ImageBottom- ImageTop)/2]; arLeftEdge[i] = arLeftEdge1[i]; } return true; }
[2] 在CBarRecog類中添加相應的函數:Recognize(),對條形碼圖像進行字符識別,具體實現代碼如代碼3-3所示。
代碼3-3 Recognize()函數
BOOL CBarRecog::Recognize() { //總共有7×12+3×2+5= 95個單位寬度 //有4×12+3×2+5=59個寬度 int i; int result[12]; double mx = 0.0; //平均寬度 for(i=0; i<59; i++) mx += (double)arWidth[i]; mx /= 95.0; //起始條紋 for(i=0; i<3; i++) { double dTemp = (double)arWidth[i]/mx; if( dTemp<0.6 || dTemp>1.4 ) break; } //起始碼不符合要求 //if(i<3) // return false; //識別前6個 for(i=0; i<6; i++) { result[i] = JudgNum(arWidth[i*4+3], arWidth[i*4+4], arWidth[i*4+5],arWidth[i*4+6], mx); } //識別后6個 for(i=6; i<12; i++) { result[i] = JudgNum(arWidth[i*4+8], arWidth[i*4+9], arWidth[i*4+10],arWidth[i*4+11], mx); } //判斷碼制 if( result[0]==7 && result[1]==7 ) { strCodeStyle = "ISSN"; } else if( result[0]==7 && result[1]==8 ) { strCodeStyle = "ISBN"; } else strCodeStyle = "Unknown!"; //判斷是否全部識別出來 for(i=0; i<12; i++) if(result[i] == -1) return false; CString strTemp; strCodeNumber.Format(""); for(i=0; i<12; i++) { strTemp.Format("%d", result[i]); strCodeNumber += strTemp; } return true; }
[3] 代碼3-3中調用了函數JudgNumt(),該函數的實現代碼如代碼3-4所示。
代碼3-4 JudgNumt()函數
int CBarRecog::JudgNum(int w1, int w2, int w3, int w4, double mx)
{
double a1, a2, a3;
int ia1, ia2, ia3;
a1 = (double)(w1+w2)/mx;
a2 = (double)(w2+w3)/mx;
a3 = (double)(w3+w4)/mx;
ia1 = (int)(a1+0.5);
ia2 = (int)(a2+0.5);
ia3 = (int)(a3+0.5);
//判斷該碼值
if( (ia1==5 && ia2==3 && ia3==2) || (ia1==2 && ia2==3 && ia3==5) )
return 0;
if( (ia1==4 && ia2==4 && ia3==3) || (ia1==3 && ia2==4 && ia3==4) )
{
if(ia1 == 4)
{
double dw2 = (double)w2/mx;
if(dw2 < 2.4)
return 1;
else if(dw2 > 2.6)
return 7;
else return -1;
}
if(ia1 == 3)
{
double dw3 = (double)w3/mx;
if(dw3 < 2.4)
return 1;
else if(dw3 > 2.6)
return 7;
else return -1;
}
}
if( (ia1==3 && ia2==3 && ia3==4) || (ia1==4 && ia2==3 && ia3==3) )
{
if(ia1 == 3)
{
double dw4 = (double)w4/mx;
if(dw4 < 2.4)
return 2;
else if(dw4 > 2.6)
return 8;
else return -1;
}
if(ia1 == 4)
{
double dw1 = (double)w1/mx;
if(dw1 < 2.4)
return 2;
else if(dw1 > 2.6)
return 8;
else return -1;
}
}
if( (ia1==5 && ia2==5 && ia3==2) || (ia1==2 && ia2==5 && ia3==5) )
return 3;
if( (ia1==2 && ia2==4 && ia3==5) || (ia1==5 && ia2==4 && ia3==2) )
return 4;
if( (ia1==3 && ia2==5 && ia3==4) || (ia1==4 && ia2==5 && ia3==3) )
return 5;
if( (ia1==2 && ia2==2 && ia3==5) || (ia1==5 && ia2==2 && ia3==2) )
return 6;
if( (ia1==4 && ia2==2 && ia3==3) || (ia1==3 && ia2==2 && ia3==4) )
return 9;
return false;
}