官术网_书友最值得收藏!

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;
        }
主站蜘蛛池模板: 奎屯市| 光山县| 皮山县| 武城县| 广州市| 恩施市| 西林县| 苏州市| 左云县| 彰化市| 湘潭县| 郎溪县| 工布江达县| 嘉峪关市| 什邡市| 南雄市| 普陀区| 措美县| 全州县| 绩溪县| 德阳市| 博乐市| 莱阳市| 酒泉市| 开鲁县| 高要市| 牙克石市| 仁怀市| 五常市| 广东省| 广汉市| 贵德县| 闻喜县| 清水县| 新竹县| 永嘉县| 随州市| 长葛市| 屏山县| 黔西| 福建省|