• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 298  文章 - 377  trackbacks - 0
            <2013年1月>
            303112345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            常用鏈接

            留言簿(34)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊

            收藏夾

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            菜鳥學(xué)習(xí)筆記供新手學(xué)習(xí)參考,一個有著很多限制的小程序,大神路過多多指點。


              不廢話,正題如下:


              bmp驗證碼識別的流程大概分為:

                1、獲取bmp圖片中識別需要用到的數(shù)據(jù),包括像素高度、像素寬度以及位圖數(shù)據(jù)。

                2、對獲取的數(shù)據(jù)進行必要的處理,包括灰度化、二值化、去噪等。

                3、對處理后的數(shù)據(jù)(一個二值化的數(shù)組)進行掃描,分割出各個字符(即確定多對數(shù)組下標(biāo))。

                4、建立字符模板庫,將分割出的字符與模板一一對比,找出對應(yīng)的字符。


              下面具體講解:

              1、獲取數(shù)據(jù)。

                bmp文件結(jié)構(gòu)與讀取遍地都是,細節(jié)不贅述。

                需要注意:1)簡單識別用到的也就是biWidth(19-22字節(jié)),biHeight(23-26字節(jié)),以及位圖數(shù)據(jù)(>54字節(jié))。

                                   2)位圖數(shù)據(jù)是倒著存放,讀取或處理的時候要進行處理。

                                           位圖數(shù)據(jù)每行會自動填充字節(jié)為4的倍數(shù),讀取或處理時最好跳過相應(yīng)數(shù)目的字節(jié)。

                                    3)每個像素有3個分量RGB,對應(yīng)3個字節(jié)。

                                   4)關(guān)于調(diào)色板:由于現(xiàn)在基本都是24位真彩圖,所以這個基本可以不考慮,所以才是讀取54字節(jié)以后的為位圖數(shù)據(jù)。

                                                                   調(diào)色板個人理解:     類似超市寄存物品,每個格子就是一種顏色,通過你的編號(即位圖數(shù)據(jù),注

                                                                                                       意這里每個像素不是3字節(jié),而是因多少位的圖片而異),拿到你想要的顏色。

            1. //      提供方法:  
            2. //              1、取得圖片信息。  
            3. //              2、取得圖片數(shù)據(jù)。  
            4.   
            5.   
            6.   
            7. class readBmp  
            8. {  
            9. public:  
            10.     bool            getWidth(long &);                   //得到位圖的寬  
            11.     bool            getHeight(long &);                  //得到位圖的高  
            12.     bool            getBit(int &);                      //得到位圖位數(shù)  
            13.     bool            getData(bit_t *&);              //讀取文件的顏色信息,即像素部分,即rgb信息  
            14.   
            15.     readBmp(const char *path);  
            16.     ~readBmp();  
            17.   
            18. private:  
            19.     int             bitWidth;                 
            20.     int             bitHeight;                
            21.     int             bitBit;                   
            22.     bool            bitReadSuccess;         //記錄構(gòu)造函數(shù)里bmp文件是否成功讀取  
            23.     void            distroy();  
            24.     bit_t          *tmpData;                //從文件讀出的數(shù)據(jù)地址  
            25.     bool            isInforExisted(void);   //判斷bmp文件是否成功讀取  
            26. };  
            27.   
            28. /* 
            29. 在構(gòu)造函數(shù)里讀取所需的文件信息,包括像素高度、寬度、和位圖數(shù)據(jù) 
            30. 自己申請的空間在析構(gòu)函數(shù)釋放 
            31. */  
            32.   
            33. readBmp::readBmp(const char *path)  
            34. {  
            35.     ifstream  bmpFile(path, ios::in | ios::binary);         //創(chuàng)建一個讀取文件流對象, 不自動生成不存在文件,二進制方式打開  
            36.     bitReadSuccess = bmpFile.good();                        //判斷文件是否成功打開  
            37.     if(true == bitReadSuccess)  
            38.     {  
            39.         bmpFile.seekg(18, ios::beg);                        //bmp文件結(jié)構(gòu)中WIDTH 和 HEIGHT為long類型,在19-26字節(jié)  
            40.         bmpFile.read((char *)(&bitWidth), 4);               //由于read方法參數(shù)類型限制,要將第一個參數(shù)如左處理  
            41.   
            42.         //64位系統(tǒng)g++ long 為8字節(jié),不能用sizeof(long)獲取字節(jié)數(shù),否則文件指針偏移量過大,讀取過多  
            43.   
            44.         bmpFile.read((char *)(&bitHeight), 4);        
            45.         bmpFile.seekg(2, ios::cur);  
            46.         bmpFile.read((char *)(&bitBit), sizeof (bitBit));  
            47.           
            48.         if (bitBit != 24)                                   //暫時只考慮24位圖片的讀取,2、4、8位的可以以后擴充  
            49.         {  
            50.             cout << "非24位圖片,請選擇合適的圖片重試!" << endl;  
            51.         }  
            52.         else  
            53.         {  
            54.             long count = 0;  
            55.             bmpFile.seekg(22, ios::cur);  
            56.             tmpData = new bit_t[bitWidth * bitHeight * 3];  
            57.             long    skipWidth = (4 - bitWidth*3%4)%4;           //計算每行讀取時要skip的字節(jié)數(shù)  
            58.             for(int i = bitHeight - 1; i >= 0; i--)  
            59.             {  
            60.                 for( int j = 0; j < bitWidth * 3; j++)  
            61.                     bmpFile.get(tmpData[count++]);  
            62.                 bmpFile.seekg(skipWidth, ios::cur);                     //跳過計算過的字節(jié)數(shù)  
            63.             }  
            64.         }  
            65.                   
            66.         bmpFile.close();  
            67.     }  
            68. }  
            69.   
            70.   
            71. bool    readBmp::getWidth(long &width)                                      //獲取像素寬度  
            72. {  
            73.     if (isInforExisted() == true)  
            74.         width = bitWidth;  
            75.     else  
            76.         return false;  
            77.     return true;  
            78. }  
            79.   
            80. bool    readBmp::getHeight(long &height)                                        //獲取像素高度  
            81. {  
            82.     if (isInforExisted() == true)  
            83.         height = bitHeight;  
            84.     else  
            85.         return false;  
            86.     return true;  
            87. }  
            88.   
            89. bool    readBmp::getBit(int &bit)                                           //獲取位圖位數(shù)  
            90. {  
            91.     if (isInforExisted() == true)  
            92.         bit = bitBit;  
            93.     else  
            94.         return false;  
            95.     return true;  
            96. }  
            97.   
            98. bool    readBmp::isInforExisted()                                           //判斷文件信息是否讀入  
            99. {  
            100.     if (false == bitReadSuccess)  
            101.         cout << "圖片文件信息讀取失敗,請重新讀取后重試!" << endl;  
            102.     return bitReadSuccess;  
            103. }  
            104.   
            105. bool    readBmp::getData(bit_t *&data)  
            106. {  
            107.     if (isInforExisted() == true)  
            108.         data = tmpData;  
            109.     else  
            110.         return false;  
            111.     return true;  
            112. }  
            113.   
            114. readBmp::~readBmp()  
            115. {  
            116.     delete []tmpData;  
            117. }  


              2、數(shù)據(jù)處理。

                位圖數(shù)據(jù)讀取完成應(yīng)該得到一個一維數(shù)組,總共biWidth*biHeight*3個字節(jié)。(本人用char類型存儲)

                1)灰度化。

                       像素信息RGB 3個分量一般是不同的,共同表達一中顏色信息。當(dāng)R=G=B時表達的是一種灰色。因此將圖像灰度化只需要將

                 3個分量的值變?yōu)橄嗟鹊募纯桑梢圆捎眉訖?quán)法、最大值法等,具體可百度“灰度化”。

                  注意:采用何種方法灰度化對后面的二值化影響很大,可分別采用測試效果,由于本人處理的圖片比較特殊,用的最大值法。

                               前面得到的一維數(shù)組在這一步可以轉(zhuǎn)化為一個二維數(shù)組  arr[biHeight][biWidth]  (3個分量可合并為1個)。

                 2)二值化。

                       其實就是根據(jù)算法或經(jīng)驗從位圖數(shù)據(jù)中得到一個值(網(wǎng)稱閾值),遍歷灰度化后得到的二維數(shù)組,利用這個值將數(shù)組二值化。

                  我用的是全域迭代法,效果一般,求閾值可自選算法或自選值。

                 3)去噪。

                        也就是去除圖片中的干擾點、雜點。我用的是很屌絲的與周圍的點比較異同的方法(多調(diào)用幾遍效果也還不錯)。大神自尋算法。

            1. //一些圖片的處理方法  
            2. //創(chuàng)建此對象時同時進行灰度化  
            3.   
            4. class sortBmp  
            5. {  
            6. public:  
            7.     sortBmp(int width, int height, char *indata);  
            8.     ~sortBmp();  
            9.     int             getThreshold();                             //計算閾值  
            10.     bool            binarize();                                 //二值化  
            11.     bool            show();                                     //輸出數(shù)據(jù)信息  
            12.     bool            noiseSort();                                //去噪  
            13.     int           **getData();  
            14.   
            15. private:  
            16.     bool            isGrey;  
            17.     bool            isBinary;  
            18.     int             bitWidth;  
            19.     int             bitHeight;  
            20.     int           **bmpData;  
            21.     int             maxGreyValue, minGreyValue;  
            22.     int             Threshold;  
            23.     int             greyValueExisted[256], greyValueCount[256], greyValueExistedCount;  
            24.     bool            isGreyValueExisted(int);  
            25.     bool            addGreyValueCount(int);  
            26.     bool            addGreyValueMember(int);  
            27.     bool            greyValueExistedSort();  
            28.     double          sum_data(intintint *, int *);  
            29.     double          sum_data(intintint *);  
            30.     bool            deleteNoisePoint();  
            31. };    
            32.   
            33. sortBmp::sortBmp(const int width, const int height, char *indata):bitWidth(width), bitHeight(height)  
            34. {  
            35.     int i, j, k, key;  
            36.     int tmp[3];  
            37. //動態(tài)申請一個二維數(shù)組  
            38.     bmpData = new int*[height];  
            39.   
            40.     for(k = 0; k < height; k++)  
            41.     {   
            42.         bmpData[k] = new int[width];  
            43.     }  
            44. //key記錄以為數(shù)組的下標(biāo)  
            45.     key = -1;  
            46. //注意第一維的下標(biāo),以此實現(xiàn)數(shù)據(jù)的倒置  
            47.     for (i = height - 1; i >= 0; i--)  
            48.         for (j = 0; j < width; j++)  
            49.         {  
            50. //          bmpData[i][j] = ((indata[++key] & 0xFF)*0.3 + (indata[++key] & 0xFF)*0.59 + (indata[++key] & 0xFF)*0.11);  //jia quan  
            51. //            bmpData[i][j] = ((indata[++key] & 0xFF) + (indata[++key] & 0xFF) + (indata[++key] & 0xFF))/3;               //ping jun  
            52.            tmp[0] = indata[++key] & 0xFF;  
            53.            tmp[1] = indata[++key] & 0xFF;  
            54.            tmp[2] = indata[++key] & 0xFF;                       //與0xff與運算char轉(zhuǎn)換為int  
            55.            bmpData[i][j] = (tmp[0]>tmp[1]?tmp[0]:tmp[1])>tmp[2]?(tmp[0]>tmp[1]?tmp[0]:tmp[1]):tmp[2];  
            56.         }  
            57.     isGrey = true;  
            58.     isBinary = false;  
            59. //測試輸出  
            60. //  cout << endl << endl;  
            61. //  for(int i = 0; i < width*height*3; i++)  
            62. //      cout << (indata[i] & 0xFF) << '\t';  
            63. //  cout << endl;  
            64.  }  
            65.   
            66. sortBmp::~sortBmp()  
            67. {   
            68.     for (int i = 0; i < bitHeight; i++)  
            69.         delete []bmpData[i];  
            70.     delete []bmpData;  
            71. //  delete []bmpData;  
            72. //  cout << "對象析構(gòu)。" << endl;  
            73. }  
            74. int sortBmp::getThreshold()             //獲取閾值的算法。 本質(zhì)是漸進到一個合適的值  
            75. {  
            76.     int threshold[2], tmpThreshold; //用來保存初始閾值、緩存閾值和最終的閾值  
            77.     maxGreyValue = **bmpData;  
            78.     minGreyValue = **bmpData;  
            79.     for (int i = 0; i < 256; i++)  
            80.         greyValueCount[i] = 0;  
            81.     greyValueExistedCount = 0;  
            82.     for (int i = 0; i < bitHeight; i++)  
            83.         for (int j = 0; j < bitWidth; j++)  
            84.         {  
            85. //獲取最大最小灰度值  
            86. //測試語句  
            87. //          cout << bmpData[i][j] << ' ' ;  
            88.             if (maxGreyValue < bmpData[i][j])  
            89.                 maxGreyValue = bmpData[i][j];  
            90.             if (minGreyValue > bmpData[i][j])  
            91.                 minGreyValue = bmpData[i][j];  
            92.         //如果灰度值已錄入,就增加統(tǒng)計的數(shù)目,如果未錄入,就將其錄入       
            93.             if (isGreyValueExisted(bmpData[i][j]) == true)  
            94.                 addGreyValueCount(bmpData[i][j]);  
            95.             else  
            96.                 addGreyValueMember(bmpData[i][j]);      //此函數(shù)要在greyValueExisted里添加數(shù)據(jù),修改greyValueCount和greyValueExistedCount的值  
            97.         }  
            98.       
            99.     greyValueExistedSort();  
            100.     //準(zhǔn)備數(shù)據(jù)完畢。  
            101.     threshold[0] = 0;  
            102.     threshold[1] = (maxGreyValue + minGreyValue)/2;  
            103.     while(threshold[1] != threshold[0])  
            104.     {  
            105.         tmpThreshold =   
            106.             0.4 * (  
            107.             sum_data(greyValueExisted[0], threshold[1], greyValueExisted, greyValueCount)  
            108.             /sum_data(greyValueExisted[0], threshold[1], greyValueCount)  
            109.             +  
            110.             sum_data(threshold[1]+1, greyValueExisted[greyValueExistedCount-1], greyValueExisted, greyValueCount)  
            111.             /sum_data(threshold[1]+1, greyValueExisted[greyValueExistedCount-1], greyValueCount)  
            112.             );  
            113.     threshold[0] = threshold[1];  
            114.     threshold[1] = tmpThreshold;  
            115.     }  
            116.   
            117.     Threshold = threshold[1];  
            118.     return threshold[1];  
            119. }   
            120.   
            121. double sortBmp::sum_data(int start_value, int end_value, int *value_data, int *count_data)  
            122. {  
            123.     int sum_4_arg = 0;  
            124.     int i = 0;  
            125.     while (greyValueExisted[i] < start_value)  
            126.         i++;  
            127.         while (greyValueExisted[i] <= end_value && i < greyValueExistedCount)  
            128.     {  
            129.         sum_4_arg += value_data[i]*count_data[i];  
            130.             i++;  
            131.      }  
            132.     return sum_4_arg;  
            133. }   
            134.   
            135. double sortBmp::sum_data(int start_value, int end_value, int *count_data)  
            136. {   
            137.     int sum_3_arg = 0;  
            138.     int i = 0;  
            139.     while (greyValueExisted[i] < start_value)  
            140.         i++;  
            141.     while (greyValueExisted[i] <= end_value && i < greyValueExistedCount)  
            142.     {  
            143.         sum_3_arg += count_data[i];  
            144.             i++;  
            145.      }  
            146.     return sum_3_arg;  
            147. }   
            148.   
            149. bool sortBmp::isGreyValueExisted(int data)  
            150. {  
            151.     if (greyValueExistedCount == 0)  
            152.         return false;  
            153.     for (int i = 0; i < greyValueExistedCount; i++)  
            154.         if (data == greyValueExisted[i])  
            155.             return true;  
            156.     return false;  
            157. }   
            158.   
            159. bool    sortBmp::addGreyValueMember(int data)  
            160. {   
            161.     greyValueExisted[greyValueExistedCount] = data;  
            162.     greyValueCount[greyValueExistedCount]++;  
            163.     greyValueExistedCount++;  
            164.     return true;  
            165. }  
            166.   
            167. bool    sortBmp::addGreyValueCount(int data)  
            168. {  
            169.     for (int i = 0; i < greyValueExistedCount; i++)  
            170.         if (greyValueExisted[i] == data)  
            171.             greyValueCount[i]++;  
            172.     return true;  
            173. }   
            174.   
            175. bool    sortBmp::greyValueExistedSort()  
            176. {  
            177.     int tmp_existed, tmp_count;  
            178.   
            179.     for (int i = 0; i < greyValueExistedCount - 1; i++)  
            180.         for (int j = i+1; j < greyValueExistedCount; j++)  
            181.         {  
            182.             if (greyValueExisted[i] > greyValueExisted[j])  
            183.             {  
            184.                 tmp_existed = greyValueExisted[i];  
            185.                 greyValueExisted[i] = greyValueExisted[j];  
            186.                 greyValueExisted[j] = tmp_existed;  
            187.                 tmp_count = greyValueCount[i];  
            188.                 greyValueCount[i] = greyValueCount[j];  
            189.                 greyValueCount[j] = tmp_count;  
            190.             }   
            191.         }  
            192.     return true;  
            193. }  
            194. //以上都是為算法服務(wù) -。-  
            195. bool    sortBmp::binarize()  
            196. {  
            197.     for (int i = 0; i < bitHeight; i++)  
            198.         for (int j = 0; j < bitWidth; j++)  
            199.             if (bmpData[i][j] > Threshold)  
            200.                 bmpData[i][j] = 255;  
            201.             else  
            202.                 bmpData[i][j] = 0;  
            203.     return true;  
            204. }  
            205.   
            206. bool    sortBmp::show()  
            207. {  
            208.     for(int i = 0; i < bitWidth; i++)  
            209.         cout << '-';  
            210.     cout << endl;  
            211.     for (int i = 0; i < bitHeight; i++)  
            212.     {  
            213.         for (int j = 0; j < bitWidth; j++)  
            214.             if (bmpData[i][j] == 0)  
            215.                 cout << '*';  
            216.             else  
            217.                 cout << ' ';  
            218.         cout << '|' << endl;         
            219.     }  
            220.     for(int i = 0; i < bitWidth; i++)  
            221.         cout << '-';  
            222.     cout << endl;  
            223. /*    for (int i = 0; i < bitHeight; i++) 
            224.     { 
            225.         for (int j = bitWidth+1; j < bitWidth; j++) 
            226.             if (bmpData[i][j] == 0) 
            227.                 cout << '*'; 
            228.             else 
            229.                 cout << ' ';   
            230.     } 
            231.  */   
            232.   
            233. }  
            234.   
            235. bool    sortBmp::deleteNoisePoint()                 //在這里去噪,道理簡單,寫起來真難受  
            236. {  
            237.     for (int i = 1; i < bitHeight-1; i++)  
            238.         for (int j = 1; j < bitWidth-1; j++)  
            239.             if (((bmpData[i-1][j-1] != bmpData[i][j]) + (bmpData[i-1][j] != bmpData[i][j]) + (bmpData[i-1][j+1] != bmpData[i][j]) + (bmpData[i][j-1] != bmpData[i][j]) + (bmpData[i][j+1] != bmpData[i][j]) + (bmpData[i+1][j-1] != bmpData[i][j]) + (bmpData[i+1][j] != bmpData[i][j]) + (bmpData[i+1][j+1] != bmpData[i][j])) >= 7)//用6會損失很多數(shù)據(jù)點,選擇后續(xù)處理3個噪點在一起的情況   
            240.                 bmpData[i][j] = 255;//~bmpData[i][j];  
            241.    //處理4個角   
            242. /*  if ((bmpData[0][0] != bmpData[0][1]) + (bmpData[0][0] != bmpData[1][0]) + (bmpData[0][0] != bmpData[1][1]) >= 2) 
            243.         bmpData[0][0] = ~bmpData[0][0]; 
            244.     if ((bmpData[0][bitWidth-1] != bmpData[0][bitWidth-2]) + (bmpData[0][bitWidth-1] != bmpData[1][bitWidth-2]) + (bmpData[0][bitWidth-1] != bmpData[1][bitWidth-1]) >= 2) 
            245.         bmpData[0][bitWidth-1] = ~bmpData[0][0]; 
            246.     if ((bmpData[bitHeight-1][0] != bmpData[bitHeight-2][0]) + (bmpData[bitHeight-1][0] != bmpData[bitHeight-2][1]) + (bmpData[bitHeight-1][0] != bmpData[bitHeight-1][1]) >= 2) 
            247.         bmpData[0][0] = ~bmpData[0][0]; 
            248.     if ((bmpData[bitHeight-1][bitWidth-1] != bmpData[bitHeight-2][bitWidth-1]) + (bmpData[bitHeight-1][bitWidth-1] != bmpData[bitHeight-2][bitWidth-2]) + (bmpData[bitHeight-1][bitWidth-1] != bmpData[bitHeight-1][bitWidth-2]) >= 2) 
            249.         bmpData[0][0] = ~bmpData[0][0]; 
            250.         */  
            251.     bmpData[0][0] = bmpData[0][bitWidth-1] = bmpData[bitHeight-1][0] = bmpData[bitHeight-1][bitWidth-1] = 255;  
            252.     //處理除角的邊界  
            253.     for (int i = 1; i < bitWidth-2; i++)  
            254.         if ((bmpData[0][i] != bmpData[0][i-1]) + (bmpData[0][i] != bmpData[0][i+1]) + (bmpData[0][i] != bmpData[1][i]) + (bmpData[0][i] != bmpData[1][i-1]) + (bmpData[0][i] != bmpData[1][i+1]) >= 4)  
            255.             bmpData[0][i] = 255;//~bmpData[0][i];  
            256.     for (int i = 1; i < bitHeight-2; i++)  
            257.         if ((bmpData[i][0] != bmpData[i-1][0]) + (bmpData[i][0] != bmpData[i+1][0]) + (bmpData[i][0] != bmpData[i][1]) + (bmpData[i][0] != bmpData[i-1][1]) + (bmpData[i][0] != bmpData[i+1][1]) >= 4)  
            258.             bmpData[i][0] = 255;//~bmpData[i][0];  
            259.   
            260.     for (int i = 1; i < bitWidth-2; i++)  
            261.         if ((bmpData[bitHeight-1][i] != bmpData[bitHeight-1][i-1]) + (bmpData[bitHeight-1][i] != bmpData[bitHeight-1][i+1]) + (bmpData[bitHeight-1][i] != bmpData[bitHeight-2][i]) + (bmpData[bitHeight-1][i] != bmpData[bitHeight-2][i-1]) + (bmpData[bitHeight-1][i] != bmpData[bitHeight-2][i+1]) >= 4)  
            262.             bmpData[bitHeight-1][i] = 255;//~bmpData[bitHeight-1][i];  
            263.   
            264.    for (int i = 1; i < bitHeight-2; i++)  
            265.         if ((bmpData[i][bitWidth-1] != bmpData[i-1][bitWidth-1]) + (bmpData[i][bitWidth-1] != bmpData[i+1][bitWidth-1]) + (bmpData[i][bitWidth-1] != bmpData[i][bitWidth-2]) + (bmpData[i][bitWidth-1] != bmpData[i-1][bitWidth-2]) + (bmpData[i][bitWidth-1] != bmpData[i+1][bitWidth-2]) >= 4)  
            266.             bmpData[i][bitWidth-1] = 255;//~bmpData[i][bitWidth-1];  
            267.     return true;  
            268. }  
            269.   
            270. bool    sortBmp::noiseSort()   //多調(diào)用即便去噪更徹底  
            271. {  
            272.     deleteNoisePoint();  
            273.     deleteNoisePoint();  
            274.     deleteNoisePoint();  
            275.     return true;  
            276. }  
            277. int**   sortBmp::getData()  
            278. {  
            279.     return bmpData;  
            280. }  


              3、字符分割。

                其實從數(shù)據(jù)處理開始可選行就很強了,流程是一樣的,方法卻有很多,可以根據(jù)自己的能力和想要的效果自己選取合適的算法。

                 由于我要處理的圖片只有4個字符且字符都是分開的,所以我也就遍歷這個二維數(shù)組,得到8對邊界, 每個字符兩對。


              4、模板匹配。

                這個算法可選行也很強,由于要求不高我還是用的最簡單的方法。

                將所有字符高、寬中的最大值最為二維數(shù)組的兩個范圍,這個限定大小的二維數(shù)組加上一個char類型數(shù)據(jù)就是一個模板。

                比如所有的字符最寬的1個寬為12,最的一個為14,那么模板就是arr[14][12]、在加上其對應(yīng)字符。

                遇到一個字符先判斷模板文件中是否存在,存在就輸出對應(yīng)信息。

                如果不存在,將字符存入這個數(shù)組,然后將這個二維數(shù)組和對應(yīng)的字符(自己輸入)存入文件。  

            1. class recognizeBmp  
            2. {   
            3. public:  
            4.     recognizeBmp(intintint **);  
            5.     void        showCharacter();  
            6.     void        showResult();  
            7. private:  
            8.     int         wide_range[8];  
            9.     int         height_range[8];  
            10.     int         bitHeight;  
            11.     int         bitWidth;  
            12.     int       **bmpData;  
            13.     void        getCharacter(void);  
            14.     void        getRanges(void);  
            15.     void        get_inform(void);  
            16.     bool        recognize(int (*)[16], char &, intint);  
            17.     void        addCharacter(int (*)[16], char);  
            18.     bool        compare_char_arr(int (*)[16], int (*)[16], intint);  
            19. };  
            20.   
            21.   
            22.     recognizeBmp::recognizeBmp(int height, int width, int**tmpData):bitWidth(width), bitHeight(height), bmpData(tmpData)  
            23.     {  
            24.         getRanges();  
            25.     }   
            26.   
            27. void    recognizeBmp::getRanges(void)               //取得邊界范圍  
            28. {  
            29.   
            30.     int      i          = 0;  
            31.     int      h          = 0;  
            32.     int      w          = 0;  
            33.     long     sum        = 255;  
            34.     long     tmp_sum    = 255;  
            35.   
            36.     for (w = 0; w < bitWidth; w++)               //處理4對左右邊界  
            37.     {  
            38.         tmp_sum = sum;  
            39.         sum = 255;  
            40.         h = 0;  
            41.         while (h < bitHeight)  
            42.         {  
            43.             sum &= bmpData[h++][w];  
            44.         }  
            45.         if (sum != tmp_sum)  
            46.             wide_range[i++] = w;  
            47.     }  
            48.     sum = 255;  
            49.     for (h = 0; h < bitHeight; h++)  
            50.     {  
            51.         sum &= bmpData[h][bitWidth-1];  
            52.     }  
            53.     if (sum == 0)  
            54.         wide_range[7] = bitWidth-1;  
            55.   
            56.   
            57.     for (i = 1; i <= 7; i+=2)                    //處理4對上下邊界  
            58.         if (wide_range[i] != bitWidth-1)  
            59.             wide_range[i]--;    
            60.     for (int count = 0; count < 4; count++)  
            61.     {   
            62.         tmp_sum = 255;  
            63.         sum = 255;  
            64.         for (h = 0; h < bitHeight; h++)  
            65.         {  
            66.             tmp_sum = sum;                      //從上找上邊界  
            67.             sum = 255;  
            68.             for (w = wide_range[2*count]; w < wide_range[2*count+1]; w++)  
            69.             {  
            70.                 sum &= bmpData[h][w];  
            71.              }  
            72.              if (tmp_sum != sum)  
            73.              {  
            74.                 height_range[2*count] = h;  
            75.                 break;  
            76.              }  
            77.         }  
            78.         tmp_sum = 255;  
            79.         sum = 255;  
            80.         for (h = bitHeight-1; h >= 0; h--)  
            81.         {  
            82.             tmp_sum = sum;                  //從下找下邊界  
            83.             sum = 255;  
            84.             for (w = wide_range[2*count]; w < wide_range[2*count+1]; w++)  
            85.             {  
            86.                 sum &= bmpData[h][w];  
            87.             }  
            88.             if (tmp_sum != sum)  
            89.             {  
            90.               height_range[2*count+1] = h;  
            91.               break;  
            92.             }  
            93.         }  
            94.     }              
            95.   
            96.     for (int count = 0; count < 4; count++)                  //假如有字符邊界在最底部的話  
            97.     {  
            98.         sum = 255;  
            99.         for (i = wide_range[2*count]; i < wide_range[2*count+1]; i++)  
            100.         {  
            101.             sum &= bmpData[bitHeight-1][w];  
            102.         }  
            103.         if (sum != 255)  
            104.           height_range[2*count +1] = bitHeight-1;  
            105.     }   
            106. }   
            107.   
            108. void    recognizeBmp::showCharacter(void)                   //輸出字符  
            109. {  
            110.     for (int count = 0; count < 4; count++)  
            111.     {  
            112.         for (int i = height_range[count*2]; i <= height_range[count*2+1]; i++)  
            113.         {  
            114.             for (int j = wide_range[count*2]; j <= wide_range[count*2+1]; j++)  
            115.             {  
            116.                 if (bmpData[i][j] == 255)  
            117.                     cout << ' ';  
            118.                 else  
            119.                     cout << '*';  
            120.             }  
            121.             cout << endl;  
            122.         }  
            123.         cout << endl;  
            124.     }  
            125. }  
            126.   
            127. /* 
            128. void    recognizeBmp::normalize(void) 
            129.     int sum = 0; 
            130.     int tmp_char[10][10] = {0}; 
            131.  
            132.     for (int c = 0; c < 4; c++) 
            133.     { 
            134.         for (int i = 0; i < 10; i++) 
            135.             for (int j = 0; j < 10; j++) 
            136.             { 
            137.                 sum = 0; 
            138.                 for (int h = height_range[2*c]+i*(height_range[2*c+1]-height_range[2*c]+1)/10; 
            139.                      h < height_range[2*c]+(i+1)*(height_range[2*c+1]-height_range[2*c]+1)/10  
            140.                       && h <= height_range[2*c+1];  h++)  
            141.                     for (int w = wide_range[2*c]+j*(wide_range[2*c+1]-wide_range[2*c]+1)/10; 
            142.                         w < wide_range[2*c]+(j+1)*(wide_range[2*c+1]-wide_range[2*c]+1)/10 
            143.                         && w <= wide_range[2*c+1]; w++) 
            144.                         if (bmpData[h][w] == 0) 
            145.                             sum++; 
            146. //              if (sum > (i*(height_range[2*c+1]-height_range[2*c]+1)/10 +1 )*(j*(wide_range[2*c+1]-wide_range[2*c]+1)/10 +1 )*0.4 && sum != 0) 
            147.                 if (sum >= 2) 
            148.                     tmp_char[i][j] = 1; 
            149.             } 
            150.         //測試語句 
            151.         for (int i = 0; i < 10; i++) 
            152.         { 
            153.             for (int j = 0; j < 10; j++) 
            154.                 cout << tmp_char[i][j] << ' '; 
            155.             cout << endl; 
            156.         } 
            157.         cout << endl; 
            158.     } 
            159. */      //歸一化失敗,另尋它法  
            160.   
            161. void    recognizeBmp::get_inform(void)  
            162. {  
            163.     int     tmp_char[16][16]    = {0};              //字符最大有16  
            164.     int     i                   = 0;  
            165.     int     j                   = 0;  
            166.     int     width               = 0;  
            167.     int     height              = 0;  
            168.     char    character;  
            169.     for (int c = 0; c < 4; c++)                      //4個字符4次識別或者錄入  
            170.     {  
            171.         height = height_range[2*c+1] - height_range[2*c] + 1;  
            172.         width  =   wide_range[2*c+1] -   wide_range[2*c] + 1;  
            173.         i = 0;  
            174.         for (int h = height_range[2*c]; h <= height_range[2*c+1]; h++)  //只輸入字符范圍的數(shù)據(jù)  
            175.         {  
            176.             j = 0;  
            177.             for (int w = wide_range[2*c]; w <= wide_range[2*c+1]; w++)  
            178.             {  
            179.                 tmp_char[i][j] = bmpData[h][w];  
            180.                 j++;  
            181.             }  
            182.             i++;  
            183.         }  
            184.         if (true == recognize(tmp_char, character, height, width))      //檢驗是否可識別  
            185.             cout << "第" << c+1 << "個字符是:" << character << endl;  
            186.         else  
            187.         {  
            188.             cout << "字符信息不存在,請?zhí)砑右员阆麓问褂? << endl << "字符:" << endl;  //不可識別的話就錄入  
            189.             for (int h = height_range[2*c]; h <= height_range[2*c+1]; h++)           //輸出讓用戶判斷是什么字符  
            190.             {  
            191.                 for (int w = wide_range[2*c]; w <= wide_range[2*c+1]; w++)  
            192.                     if (bmpData[h][w] == 0)  
            193.                         cout << '*';  
            194.                     else  
            195.                         cout << ' ';  
            196.                     cout << endl;  
            197.             }  
            198.             cout << endl << "第" << c+1 << "個字符是:" << endl;  
            199.             cin >> character;  
            200.             addCharacter(tmp_char, character);  
            201.         }  
            202.     }  
            203. }  
            204.       
            205.   
            206. void    recognizeBmp::showResult(void)  
            207. {  
            208.     get_inform();  
            209.     cout << endl << endl;  
            210. }  
            211.   
            212. bool    recognizeBmp::recognize(int (*tmp_char)[16], char &character, int height, int width)  
            213. {  
            214.     int     test_char[16][16] = {0};  
            215.     if ((double)height/width >= 1.5)             //對特殊字符的處理,提高準(zhǔn)確率,不過貌似沒什么效果,不知到問題在哪  
            216.     {  
            217.         width *= 2;  
            218.     }  
            219.     ifstream infile("../data/characters", ios::binary | ios::in);  
            220.     if (infile.eof())  
            221.         return false;  
            222.     while (!infile.eof())  
            223.     {  
            224.         infile.read((char *)test_char, 16*16*4);  
            225.         character = infile.get();  
            226.         if (true == compare_char_arr(tmp_char, test_char, height, width))  //字符與模板比較  
            227.             return true;  
            228.     }  
            229.     return false;  
            230.     infile.close();  
            231. }  
            232.   
            233. void    recognizeBmp::addCharacter(int (*tmp_char)[16], char character)     //存入新的模板  
            234. {  
            235.     ofstream outfile("../data/characters", ios::binary | ios::app);  
            236.     outfile.write((char *)tmp_char, 16*16*4);  
            237.     outfile.put(character);  
            238.     outfile.close();  
            239. }  
            240.   
            241. bool    recognizeBmp::compare_char_arr(int (*tmp_char)[16], int (*test_char)[16], int height, int width)  
            242. {  
            243.     int count = 0;  
            244.     for (int i = 0; i < height; i++)  
            245.         for (int j = 0; j < width; j++)  
            246.             if (tmp_char[i][j] == test_char[i][j])  
            247.                 count++;  
            248.     if(count >= height*width*7/8)  //  7/8是多次測試得到的合適的值  
            249.         return true;  
            250.     else  
            251.         return false;  
            252. }  



              基本就這么多了,只是給毫無頭緒的朋友們提供一個思路,具體細節(jié)可以自己實現(xiàn)。

              這個程序其實是未完成的,所以有很多缺陷和限制。

              本來的思路:

                            1、先掃描一定數(shù)量的圖片,啟動學(xué)習(xí)模塊,將未識別的字符存入模板文件,最終得到一個模板文件。

                             2、識別圖片, 啟動識別模塊,無法識別直接跳過識別下一個圖片(假如以刷票為目的,保證一定成功率就行了)

            posted on 2013-04-07 22:58 聶文龍 閱讀(4247) 評論(2)  編輯 收藏 引用

            FeedBack:
            # re: 簡單的bmp驗證碼識別 (c++) 2013-04-07 23:01 聶文龍
            簡單驗證碼是指驗證碼圖片里的字符,固定不變,或者變化很小的驗證碼,比如:字符上會有一些感擾點感擾線等情況,或者只有少數(shù)幾種字體變化和字體大小變化。

            這里給出源代碼都是非常簡單的源代碼,學(xué)過《C程序設(shè)計》的都可以看懂,不會超出書本范圍,而且不使用指針,這樣VB,Delphi,JAVA 等語言都可以照此寫出相應(yīng)的源代碼。

            驗證碼識別可以分為三個大的步驟:預(yù)處理,分割,識別。預(yù)處理又可細分為讀取圖片,二值化,去感擾點,去感擾線等等步驟。

            讀取圖片很簡單就是把要識別的驗證碼圖片讀取到我們的程序里,網(wǎng)絡(luò)上常見的驗證碼圖片格式有BMP,JPG,GIF,PNG,其中BMP的圖片格式種類很多,但都不復(fù)雜,24位BMP格式最簡單,除去54字節(jié)的文件頭,只需要順序讀取BMP文件的字節(jié)信息就可以了,256色的也就是8位的BMP格式也很常見,256色BMP圖片在文件頭后多一個索引表,后面也是順序存儲圖片信息的。JPG,GIF,PNG的格式都復(fù)雜一點,不過網(wǎng)上都有這些公司或組織發(fā)布的source code。

            下面以24位BMP格式的源代碼進行說明:

            #define W 40 //定義驗證碼圖片的寬度
            #define H 20 //定義驗證碼圖片的寬度
            #define N 4 //定義字符位數(shù),一般是4位
            #define BMP_filename "c:\\test.bmp"
            int x,y,i,s,temp;
            int YZM[W][H]={0};
            int YZM_red[W][H]={0};
            int YZM_green[W][H]={0};
            int YZM_blue[W][H]={0};
            int rec[W]={0};
            int lf[N],rt[N],up[N],dw[N];
            char result[N];

            FILE *fp=fopen(BMP_filename,"rb");//以二進制只讀方式打開BMP文件
            for(i=0;i<54;i++)temp=fgetc(fp);//跳過54個字節(jié)的文件頭數(shù)據(jù)
            for(y=H-1;y>=0;y--)//BMP圖片數(shù)據(jù)是倒序存儲的,據(jù)說是為了下載顯示方便,呵呵
            {
            for(x=0;x<W;x++){YZM_red[x][y]=fgetc(fp);YZM_green[x][y]=fgetc(fp);YZM_blue[x][y]=fgetc(fp);}
            //依次讀取每個像素的RGB值
            }
            fclose(fp);//關(guān)閉文件

            好的,通過以上幾個語句就可以把圖片信息讀取到程序的數(shù)組里了,然后對其進行二值化,去感擾等工作。
            二值化就是把剛才讀取的RGB信息,轉(zhuǎn)換成01數(shù)據(jù),0表示空白背景,1表示字符。

            for(x=0;x<W;x++)for(y=0;y<H;y++)
            {
            if(YZM_red[x][y]*0.3+YZM_green[x][y]*0.6+YZM_blue[x][y]*0.1<200)YZM[x][y]=1;else YZM[x][y]=0;
            //red*0.3+green*0.6+blue*0.1 是計算亮度的公式
            }
            //如果圖片里有感擾點,可以用下面的語句去除。
            for(x=1;x<W-1;x++)for(y=1;y<H-1;y++)
            {
            if(YZM[x][y]==1 && YZM[x-1][y-1]==0 && YZM[x][y-1]==0 && YZM[x+1][y-1]==0 && YZM[x-1][y]==0 && YZM[x+1][y]==0 && YZM[x-1][y+1]==0 && YZM[x][y+1]==0 && YZM[x+1][y+1]==0)YZM[x][y]=0;
            //如果一個點的值是1,而且它的周圍8個點的值都是0,那么這個點就是感擾點
            }

            經(jīng)過這些預(yù)處理工作就可以得到一個二進制數(shù)組數(shù)據(jù)了。我們以一組普通的驗證碼圖片為例,



            for(y=0;y<H;y++) { for(x=0;x<W;x++) printf(" %c",YZM[x][y]+'0'); printf("\n"); }

            我們可以用上面的輸出語句進行輸出,輸出語句在最終的程序中可以刪除或者注釋掉。
            輸出結(jié)果如下:

            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 1 1 1 0 0 0 0
            0 0 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0
            0 0 1 1 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0
            0 0 1 1 0 1 1 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0 0 0 0
            0 0 1 1 1 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 1 1 0 1 1 1 0 0 0 1 1 1 0 0 1 1 0 0 0 0
            0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 1 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0
            0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0
            0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 1 1 0 0 0 0 1 1 0 0 0
            0 0 0 1 1 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0 1 1 0 0 1 1 0 0 0 1 1 0 0 1 1 0 0 0 0
            0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

            for(x=0;x<W;x++)
            { s=0;
            for(y=0;y<H;y++)s=s+YZM[x][y];
            if(s>0)rec[x]=1;else rec[x]=0;//rec記錄數(shù)組的斷連情況
            }
            for(i=0,x=1;x<W-1;x++)if(rec[x-1]==0 && rec[x]==1 && rec[x+1]==1){i++;lf[i]=x;}//計算每個字符的左邊界
            for(i=0,x=1;x<W-1;x++)if(rec[x-1]==1 && rec[x]==1 && rec[x+1]==0){i++;rt[i]=x;}//計算每個字符的右邊界
            for(i=1;i<=N;i++)for(x=0;x<W;x++)for(y=0;y<H;y++) if(x>=lf[i] && x<=rt[i] && YZM[x][y]==1)YZM[x][y]=i;
            for(y=H-1;y>=0;y--)for(x=0;x<W;x++)for(i=1;i<=N;i++)if(YZM[x][y]==i)up[i]=y;//計算每個字符的上邊界

            經(jīng)過上面的分割語句,我們就完成了分割工作,我們可以用輸出語句進行輸出,輸出結(jié)果如下:

            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 1 1 1 1 1 1 1 0 0 0 0 0 2 2 0 0 0 0 0 0 3 3 3 3 0 0 0 4 4 4 4 4 4 4 0 0 0 0
            0 0 1 1 0 0 0 0 0 0 0 0 0 2 2 2 0 0 0 0 0 3 3 0 0 3 3 0 0 4 4 0 0 0 0 0 0 0 0 0
            0 0 1 1 0 0 0 0 0 0 0 0 2 2 2 2 0 0 0 0 3 3 0 0 0 0 3 0 0 4 4 0 0 0 0 0 0 0 0 0
            0 0 1 1 0 1 1 1 0 0 0 0 0 0 2 2 0 0 0 0 3 3 0 0 0 0 0 0 0 4 4 0 4 4 4 0 0 0 0 0
            0 0 1 1 1 0 0 1 1 0 0 0 0 0 2 2 0 0 0 0 3 3 0 3 3 3 0 0 0 4 4 4 0 0 4 4 0 0 0 0
            0 0 0 0 0 0 0 0 1 1 0 0 0 0 2 2 0 0 0 0 3 3 3 0 0 3 3 0 0 0 0 0 0 0 0 4 4 0 0 0
            0 0 0 0 0 0 0 0 1 1 0 0 0 0 2 2 0 0 0 0 3 3 0 0 0 0 3 3 0 0 0 0 0 0 0 4 4 0 0 0
            0 0 1 1 0 0 0 0 1 1 0 0 0 0 2 2 0 0 0 0 3 3 0 0 0 0 3 3 0 4 4 0 0 0 0 4 4 0 0 0
            0 0 0 1 1 0 0 1 1 0 0 0 0 0 2 2 0 0 0 0 0 3 3 0 0 3 3 0 0 0 4 4 0 0 4 4 0 0 0 0
            0 0 0 0 1 1 1 1 0 0 0 0 2 2 2 2 2 2 0 0 0 0 3 3 3 3 0 0 0 0 0 4 4 4 4 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0


            最后我們就可以進行識別工作,識別的方法有很多,可以進行逐點的精確識別,也可以進行模糊識別等等,甚至也可以不進行去感擾和分割工作直接進行識別(主要用于粘連的驗證碼),這都要根據(jù)具體情況來具體分析用什么方法最有效,簡單驗證碼的識別則沒有那么復(fù)雜,用很多方法都可以識別,這里使用的是從每個字符的左上邊界開始,精確判斷5行3列15個點來進行識別。

            for(i=1;i<=N;i++)
            {
            if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==0 &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==0 && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==0 && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==i &&
            YZM[lf[i]+0][up[i]+3]==i && YZM[lf[i]+1][up[i]+3]==i && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==i && YZM[lf[i]+1][up[i]+4]==i && YZM[lf[i]+2][up[i]+4]==0 )result[i-1]='0';
            if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==i &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==0 && YZM[lf[i]+2][up[i]+3]==i &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==0 && YZM[lf[i]+2][up[i]+4]==i )result[i-1]='1';
            if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==0 && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==0 && YZM[lf[i]+2][up[i]+4]==0 )result[i-1]='2';
            if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==i && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==i && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==0 &&
            YZM[lf[i]+0][up[i]+2]==0 && YZM[lf[i]+1][up[i]+2]==0 && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==0 && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==0 && YZM[lf[i]+2][up[i]+4]==0 )result[i-1]='3';
            if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==0 &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==0 && YZM[lf[i]+2][up[i]+1]==0 &&
            YZM[lf[i]+0][up[i]+2]==0 && YZM[lf[i]+1][up[i]+2]==0 && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==0 && YZM[lf[i]+2][up[i]+3]==i &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==i && YZM[lf[i]+2][up[i]+4]==i )result[i-1]='4';
            if( YZM[lf[i]+0][up[i]+0]==i && YZM[lf[i]+1][up[i]+0]==i && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==i && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==0 &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==i && YZM[lf[i]+1][up[i]+3]==i && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==i && YZM[lf[i]+1][up[i]+4]==i && YZM[lf[i]+2][up[i]+4]==i )result[i-1]='5';
            if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==i && YZM[lf[i]+1][up[i]+3]==i && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==i && YZM[lf[i]+1][up[i]+4]==i && YZM[lf[i]+2][up[i]+4]==0 )result[i-1]='6';
            if( YZM[lf[i]+0][up[i]+0]==i && YZM[lf[i]+1][up[i]+0]==i && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==0 && YZM[lf[i]+2][up[i]+1]==0 &&
            YZM[lf[i]+0][up[i]+2]==0 && YZM[lf[i]+1][up[i]+2]==0 && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==0 && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==0 && YZM[lf[i]+2][up[i]+4]==0 )result[i-1]='7';
            if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==i && YZM[lf[i]+2][up[i]+3]==i &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==0 && YZM[lf[i]+2][up[i]+4]==i )result[i-1]='8';
            if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==i && YZM[lf[i]+1][up[i]+3]==i && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==i && YZM[lf[i]+2][up[i]+4]==i )result[i-1]='9';
            }
            printf("%s",result);//輸出識別結(jié)果  回復(fù)  更多評論
              
            # re: 簡單的bmp驗證碼識別 (c++) 2013-04-07 23:07 聶文龍
            1:BMP文件組成

              BMP文件由文件頭、位圖信息頭、顏色信息和圖形數(shù)據(jù)四部分組成。
              2:BMP文件頭(14字節(jié))
              BMP文件頭數(shù)據(jù)結(jié)構(gòu)含有BMP文件的類型、文件大小和位圖起始位置等信息。
              其結(jié)構(gòu)定義如下:
              typedef struct tagBITMAPFILEHEADER
              {
              WORD bfType; // 位圖文件的類型,必須為BM(1-2字節(jié))
              DWORD bfSize; // 位圖文件的大小,以字節(jié)為單位(3-6字節(jié))
              WORD bfReserved1; // 位圖文件保留字,必須為0(7-8字節(jié))
              WORD bfReserved2; // 位圖文件保留字,必須為0(9-10字節(jié))
              DWORD bfOffBits; // 位圖數(shù)據(jù)的起始位置,以相對于位圖(11-14字節(jié))
              // 文件頭的偏移量表示,以字節(jié)為單位
              } BITMAPFILEHEADER;
              3:位圖信息頭(40字節(jié))
              BMP位圖信息頭數(shù)據(jù)用于說明位圖的尺寸等信息。
              typedef struct tagBITMAPINFOHEADER{
              DWORD biSize; // 本結(jié)構(gòu)所占用字節(jié)數(shù)(15-18字節(jié))
              LONG biWidth; // 位圖的寬度,以像素為單位(19-22字節(jié))
              LONG biHeight; // 位圖的高度,以像素為單位(23-26字節(jié))
              WORD biPlanes; // 目標(biāo)設(shè)備的級別,必須為1(27-28字節(jié))
              WORD biBitCount;// 每個像素所需的位數(shù),必須是1(雙色),(29-30字節(jié))
              // 4(16色),8(256色)或24(真彩色)之一
              DWORD biCompression; // 位圖壓縮類型,必須是 0(不壓縮),(31-34字節(jié))
              // 1(BI_RLE8壓縮類型)或2(BI_RLE4壓縮類型)之一
              DWORD biSizeImage; // 位圖的大小,以字節(jié)為單位(35-38字節(jié))
              LONG biXPelsPerMeter; // 位圖水平分辨率,每米像素數(shù)(39-42字節(jié))
              LONG biYPelsPerMeter; // 位圖垂直分辨率,每米像素數(shù)(43-46字節(jié))
              DWORD biClrUsed;// 位圖實際使用的顏色表中的顏色數(shù)(47-50字節(jié))
              DWORD biClrImportant;// 位圖顯示過程中重要的顏色數(shù)(51-54字節(jié))
              } BITMAPINFOHEADER;
              4:顏色表
              顏色表用于說明位圖中的顏色,它有若干個表項,每一個表項是一個RGBQUAD類型的結(jié)構(gòu),定義一種顏色。RGBQUAD結(jié)構(gòu)的定義如下:
              typedef struct tagRGBQUAD {
              BYTE rgbBlue;// 藍色的亮度(值范圍為0-255)
              BYTE rgbGreen; // 綠色的亮度(值范圍為0-255)
              BYTE rgbRed; // 紅色的亮度(值范圍為0-255)
              BYTE rgbReserved;// 保留,必須為0
              } RGBQUAD;
              顏色表中RGBQUAD結(jié)構(gòu)數(shù)據(jù)的個數(shù)有biBitCount來確定:
              當(dāng)biBitCount=1,4,8時,分別有2,16,256個表項;
              當(dāng)biBitCount=24時,沒有顏色表項。
              位圖信息頭和顏色表組成位圖信息,BITMAPINFO結(jié)構(gòu)定義如下:
              typedef struct tagBITMAPINFO {
              BITMAPINFOHEADER bmiHeader; // 位圖信息頭
              RGBQUAD bmiColors[1]; // 顏色表
              } BITMAPINFO;
              5:位圖數(shù)據(jù)
              位圖數(shù)據(jù)記錄了位圖的每一個像素值,記錄順序是在掃描行內(nèi)是從左到右,掃描行之間是從下到上。位圖的一個像素值所占的字節(jié)數(shù):
              當(dāng)biBitCount=1時,8個像素占1個字節(jié);
              當(dāng)biBitCount=4時,2個像素占1個字節(jié);
              當(dāng)biBitCount=8時,1個像素占1個字節(jié);
              當(dāng)biBitCount=24時,1個像素占3個字節(jié);
              Windows規(guī)定一個掃描行所占的字節(jié)數(shù)必須是
              4的倍數(shù)(即以long為單位),不足的以0填充,
              biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;

            這個在百度百科大家可以做個詳細的了解,這里就不多說了。

            驗證碼圖片:

            1.預(yù)處理:

            接下來就是對圖片進行讀取,

            2.灰度化:

            對其各個像素的GBR值進行灰度化處理,我用的公式是求平均值的方法,比較方便,效果也還不錯。,將求得的平均值存入一個二維數(shù)組中,方便后面的處理。

            3.二值化

            二值化有很多種算法,我試了試大津法(最大方差法)還有自適應(yīng)閾值法,不知道什么原因,二值化出來的圖片簡直把圖片就給毀了。。。。最后還是將圖片的GBR信息打印出來,自己找了個臨界值,效果還不錯,二值化之后的噪點也只有幾個。后面的處理就方便多了。將大于這個臨界值的像素點設(shè)為255,小于的設(shè)為0.出來的圖像就完全黑白二值了。

            4.去噪

            去噪,看了看幾張驗證碼,發(fā)現(xiàn)字母組成最少的就是i,j上面的點了,4個像素點組成,于是將圖片中一個像素點周圍的8個點進行判斷,如果這個點周圍有不超過三個黑點,則證明這個點為噪點,需要去除,需要注意的是邊界周圍只有5個點,需要進行判斷是否為邊界。



            5.分割

            因為我們的BMP圖片是有間據(jù)的,所以分割就用最簡單的一種了

            先將去噪完后的BMP像素數(shù)組在按自左向右的基礎(chǔ)上從上往下找,找到的第一個黑點即為字符的左邊界,再向右,找到的一列全不為黑點的話,則上一列即為字符的右邊界,再在左邊界和右邊界的區(qū)間下,從下往上按行遍歷,找到字符的下邊界,再從上往下找到上邊界,其他字符同理。就可以將圖片分割出來了。



            6.識別

            我用的識別方法還是比較麻煩的,先是對驗證碼的字符進行輸出(0,1組成),然后再找他們之間的不同相似之處,所以不是很方便,這里也就不細提了,看代碼就應(yīng)該理解了。

            下面是代碼:


            view plainprint?
            #include <iostream>
            #include <cstdlib>
            #include <cstdio>
            #include <cstring>
            using namespace std;
            void OtsuThreshold(int *p_data)
            {
            int i,j;
            int nWidth = 70;
            int nHeight = 30;
            for(j = 0;j < nHeight; j++)
            {//二值化實現(xiàn)
            for(i = 0; i < nWidth ; i++)
            {
            if(p_data[j * nWidth +i] < 38)
            p_data[j * nWidth + i] = 0;
            else
            p_data[j * nWidth + i] = 255;
            }
            }

            }
            void Print(int graph[][70])
            { int i,j;
            for(i = 0; i < 30; i++)
            { for(j = 0; j < 70; j++)
            {
            if(graph[i][j] == 255)
            {
            // printf(" ");
            graph[i][j] = 1;
            }
            // else printf("*");
            }
            // printf("\n");
            }


            // printf("\n\n\n\n");
            }
            void duibi(int z[][20][20],int bl1,int br1,int bl2,int br2,int bl3,int br3,int bl4,int br4)
            {
            int jianju[4];
            int i;
            jianju[0] = br1-bl1+1;
            jianju[1] = br2-bl2+1;
            jianju[2] = br3-bl3+1;
            jianju[3] = br4-bl4+1;
            for(i = 0; i < 4; i++)
            {
            if(jianju[i] <= 5)//<=5 字符占 小于等于5列的
            {
            if(jianju[i] == 5)
            {
            if(z[i][0][0] == 0)
            printf("r");
            else if(z[i][0][1] == 1)
            printf("i");
            else printf("t");
            }
            else printf("i");
            }
            else if(jianju[i] == 6)//6 字符占 6列
            {
            if(z[i][0][1] == 0)
            {
            if(z[i][0][4] == 1)
            printf("t");
            else printf("s");
            }
            else if(z[i][0][2] == 1)
            printf("j");
            else if(z[i][0][4] == 1)
            printf("t");
            else printf("f");
            }
            else if(jianju[i] == 7)//7
            {
            if(z[i][0][0] == 1 && z[i][0][1] == 1 && z[i][0][2] == 1)
            {
            if(z[i][0][6] == 1)
            printf("e");
            else if(z[i][0][3] == 0 && z[i][0][4] == 0 && z[i][0][5] == 0 && z[i][0][6] == 0)printf("c");
            else printf("f");
            }
            else if(z[i][0][0] == 1 && z[i][0][1] == 1)
            {
            if(z[i][0][5] == 1)
            {
            if(z[i][1][1] == 1)
            printf("t");
            else printf("e");
            }
            else if(z[i][0][4] == 1)
            printf("r");
            else printf("f");
            }
            else if(z[i][0][0] == 1)
            {
            printf("3");
            }
            else if(z[i][0][2] == 1 && z[i][0][3] == 0)
            printf("p");
            else if(z[i][0][0] == 0 && z[i][0][1] == 0 && z[i][0][2] == 0)printf("z");
            else if(z[i][0][0] == 0 && z[i][0][1] == 0 && z[i][0][2] == 1 && z[i][0][3] == 1) printf("h");
            else printf("r");
            }
            else if(jianju[i] == 8)//8
            {
            if(z[i][0][0] == 1 && z[i][1][1] == 1 && z[i][2][2] == 1 && z[i][3][3] == 1)
            printf("j");
            else if(z[i][0][0] == 1 && z[i][1][1] == 1 && z[i][2][2] == 1)
            printf("d");
            else if(z[i][0][0] == 1 && z[i][1][1] == 1)
            {
            if(z[i][3][3] == 1 &&z[i][4][4] == 1)
            printf("c");
            else if(z[i][3][3] == 1 && z[i][4][4] ==0)printf("a");
            else printf("f");
            }
            else if(z[i][0][0] == 1 && z[i][2][2] == 1)
            {
            if(z[i][1][0] == 0) printf("3");
            else if(z[i][4][4] == 1 && z[i][0][1] == 0)
            printf("2");
            else printf("a");
            }
            else if(z[i][0][0] == 1 && z[i][6][6] == 1)
            printf("c");
            else if(z[i][0][0] == 1 && z[i][3][3] == 1)
            printf("g");
            else if(z[i][0][0] == 1)
            printf("s");
            else if(z[i][1][1] == 1)
            printf("2");
            else if(z[i][2][2] != 1)
            printf("n");
            else if(z[i][4][4] == 1)
            {
            if(z[i][5][5] == 1) printf("u");
            else printf("7");
            }
            else if(z[i][7][7] == 1) printf("z");
            else printf("h");

            }
            else if(jianju[i] == 9) //9
            {
            if(z[i][0][0] == 1 && z[i][3][3] == 1 && z[i][4][4] == 0 && z[i][5][5] == 0 && z[i][6][6] == 0 && z[i][7][7] ==0 && z[i][8][8] == 0)
            printf("a");
            else if(z[i][2][2] == 0 && z[i][3][3] ==1 && z[i][4][4] == 0 && z[i][5][5] == 0 && z[i][6][6] == 1 && z[i][7][7] == 1)
            printf("e");
            else if(z[i][0][0] == 1 && z[i][1][1] == 1 &&z[i][2][2]== 1)
            printf("d");
            else if(z[i][1][1] == 0 && z[i][2][2] == 0 && z[i][4][4] ==1 && z[i][5][5] == 1 && z[i][7][7] == 0)
            {
            if(z[i][0][5] == 1) printf("g");
            else if(z[i][0][7] == 0) printf("n");
            else printf("p");
            }
            else if(z[i][0][0] ==0 && z[i][1][1] == 0 && z[i][3][3] == 1 && z[i][4][4] == 1 && z[i][5][5] == 0 && z[i][7][7] ==1 && z[i][8][8] ==1)
            {
            if(z[i][0][3] == 1 && z[i][10][0] == 0)
            printf("v");
            else if(z[i][0][3] == 1 && z[i][10][0] == 1) printf("y");
            else printf("7");
            }
            else if(z[i][0][0] == 0 && z[i][1][1] ==0 && z[i][2][2] ==0 && z[i][3][3] ==1 &&z[i][4][4] == 1)
            {
            printf("y");
            }
            else if(z[i][0][0] == 1 && z[i][1][1] ==1 && z[i][2][2] == 0)
            {
            if(z[i][3][3] == 1)printf("6");
            else if(z[i][4][4] == 1)printf("k");
            else if(z[i][5][5] == 1 && z[i][12][4] == 1)printf("h");
            else if(z[i][12][4] == 0 && z[i][12][2] == 1) printf("b");
            else printf("s");
            }
            else if(z[i][0][0] == 1 && z[i][1][1] == 0)
            {
            if(z[i][2][2] == 1)
            {
            if(z[i][4][4] ==1 ) printf("2");
            else printf("z");
            }
            else if(z[i][3][3] == 0)printf("r");
            else printf("8");
            }
            else printf("b");
            }
            else if(jianju[i] == 10) //10
            {
            if(z[i][0][0] == 1 && z[i][1][1] == 1 && z[i][2][2] == 1)
            {
            if(z[i][3][3] == 1) printf("d");
            else printf("x");
            }
            else if(z[i][0][0] == 1 && z[i][1][1] == 1 && z[i][2][2] == 0)
            {
            if(z[i][3][3] == 1 && z[i][10][0] == 0)printf("3");
            else if(z[i][3][3] == 1 && z[i][10][0] == 1) printf("2");
            else if(z[i][4][4] == 1 && z[i][5][5] == 1 && z[i][6][6] ==1)printf("p");
            else if(z[i][6][6] == 1) printf("b");
            else if(z[i][5][5] == 1) printf("k");
            else if(z[i][9][9] == 1) printf("5");
            else if(z[i][4][4] == 1) printf("6");
            else printf("8");
            }
            else if(z[i][0][0] == 1 && z[i][1][1] == 0)
            {
            if(z[i][2][2] == 0)printf("n");
            else if(z[i][4][4] == 1) printf("7");
            else printf("z");
            }
            else if(z[i][5][5] == 0) printf("x");
            else if(z[i][12][0] == 1) printf("y");
            else printf("v");
            }


            else if(jianju[i] == 11)//11
            {
            if(z[i][0][2] == 1)
            {
            if(z[i][0][3] == 1)
            printf("4");
            else printf("2");
            }
            else if(z[i][0][8] == 1)
            printf("x");
            else printf("u");
            }
            else if(jianju[i] >=13)//>=13
            {
            if(jianju[i] == 13||jianju[i] == 15)
            {
            if(jianju[i] == 15)
            if(z[i][0][0] == 1) printf("m");
            else printf("w");
            }
            else if(jianju[i] == 14)
            printf("m");
            else if(z[i][0][0] == 1)
            printf("m");
            else printf("w");
            }
            }
            }
            int main(int argc,char *argv[])
            {
            FILE *fp;
            int rgb[30*70];
            int gbr[30 * (70*3)];
            int graph[30][70] = {0};
            int g=0,b=0,r=0;
            int i,j,n,a,d,k;
            int Height,Width;
            int bl1=0,br1=0,bg1=0,bd1=0,bl2=0,br2=0,bg2=0,bd2=0;
            int bl3=0,br3=0,bg3=0,bd3=0,bl4=0,br4=0,bg4=0,bd4=0;
            int z[4][20][20] = {0};
            // memset(z,0,sizeof(z));
            fp = fopen(argv[1],"rb");
            if(fp == NULL)
            cout<<"read error!";
            fseek(fp,18,0);
            fread(&Width,4,1,fp);
            fread(&Height,4,1,fp);
            fseek(fp,54,0);
            for(i = 0; i < 30 ; i++)//讀取圖片進行灰度化并保存到rgb數(shù)組
            { for(j = 0; j < 70; j++)
            {
            fread(&g,1,1,fp);
            fread(&b,1,1,fp);
            fread(&r,1,1,fp);
            rgb[i * 70 + j]=(g+b+r)/3;//灰度化
            }
            fseek(fp,2,1);
            }
            OtsuThreshold(rgb);//二值化
            for(i = 0; i < Height; i++)
            {
            for(j = 0; j < Width; j++)
            graph[30-1-i][j] = rgb[i * 70 + j];
            }


            //輸出圖片
            Print(graph);
            //去噪

            for(i = 0; i < 30; i++)
            {
            for(j = 0; j < 70; j++)
            { n = 0;
            if(i == 29)
            {
            if(graph[i][j] == 0 && graph[i][j-1] != 0 && graph[i][j+1] != 0 && graph[i-1][j] != 0)
            graph[i][j] = 1;
            if(graph[i][j] == 0)
            { n = 0;
            if(graph[i-1][j-1] == 0 )
            n++;
            if(graph[i-1][j] == 0)
            n++;
            if(graph[i-1][j+1] == 0)
            n++;
            if(graph[i][j-1] == 0)
            n++;
            if(graph[i][j+1] == 0)
            n++;
            if(n < 2)
            graph[i][j] = 1;
            }
            }
            /* if(graph[i][j] == 0 && graph[i-1][j-1] != 0 && graph[i-1][j] != 0 && graph[i-1][j+1] != 0 && graph[i][j-1] != 0 && graph[i][j+1] != 0 && graph[i+1][j-1] != 0 && graph[i+1][j] != 0 && graph[i+1][j+1] != 0)
            graph[i][j] = 1;
            */
            if(graph[i][j] == 0)
            { n = 0;
            if(graph[i-1][j-1] == 0 )
            n++;
            if(graph[i-1][j] == 0)
            n++;
            if(graph[i-1][j+1] == 0)
            n++;
            if(graph[i][j-1] == 0)
            n++;
            if(graph[i][j+1] == 0)
            n++;
            if(graph[i+1][j-1] == 0)
            n++;
            if(graph[i+1][j] == 0)
            n++;
            if(graph[i+1][j+1] == 0)
            n++;
            if(n < 2)
            graph[i][j] = 1;
            }


            }
            }


            //第一個字符
            // 左邊界
            for(i = 0; i < Width; i++)
            {
            for(j = 0; j < Height; j++)
            {
            if(graph[j][i] == 0)
            {
            bl1 = i;
            break;
            }
            }
            if(bl1 != 0)
            break;
            }
            //右邊界
            for(i = bl1; i < Width; i++)
            {
            n = 0;
            for(j = 0; j < Height; j++)
            {
            if(graph[j][i] == 0)
            n++;
            }
            if(n == 0)
            {
            br1 = i-1;
            break;
            }
            }
            //上邊界
            for(i = 0; i < Height; i++ )
            { n = 0;
            for(j = bl1; j <= br1; j++)
            {
            if(graph[i][j] == 0)
            { bg1 = i;
            n = 1;
            break;
            }
            }
            if(n != 0)
            break;
            }
            //下邊界
            for(i = Height-1; i >= 0 ; i--)
            {
            n = 0;
            for(j = bl1; j <= br1; j++)
            {
            if(graph[i][j] == 0)
            {
            bd1 = i;
            n = 1;
            break;
            }
            }
            if(n != 0)
            break;
            }
            //第二個字符
            //左邊界
            for(i = br1+1; i < Width; i++)
            {
            for(j = 0; j < Height; j++)
            {
            if(graph[j][i] == 0)
            {
            bl2 = i;
            break;
            }
            }
            if(bl2 != 0)
            break;
            }
            //右邊界
            for(i = bl2; i < Width; i++)
            {
            n = 0;
            for(j = 0; j < Height; j++)
            {
            if(graph[j][i] == 0)
            n++;
            }
            if(n == 0)
            {
            br2 = i-1;
            break;
            }
            }
            //上邊界
            for(i = 0; i < Height; i++)
            { n = 0;
            for(j = bl2; j <= br2; j++)
            {
            if(graph[i][j] == 0)
            n++;
            }
            if(n != 0)
            { bg2 = i;
            break;
            }
            }
            //下邊界
            for(i = Height-1; i >= 0; i--)
            { n = 0;
            for(j = bl2; j <= br2; j++)
            {
            if(graph[i][j] == 0)
            { n = 1;
            bd2 = i;
            }
            }
            if(n != 0)
            break;
            }
            //第三個字符
            //左邊界
            for(i = br2+1; i < Width; i++)
            {
            for(j = 0; j < Height; j++)
            {
            if(graph[j][i] == 0 )
            { bl3 = i;
            break;
            }
            }
            if(bl3 != 0)
            break;
            }
            //右邊界
            for(i = bl3; i < Width; i++)
            { n = 0;
            for(j = 0; j < Height; j++)
            {
            if(graph[j][i] == 0)
            {
            n++;
            break;
            }
            }
            if(n == 0)
            {
            br3 = i-1;
            break;
            }
            }
            //上邊界
            for(i = 0; i < Height; i++)
            {
            for(j = bl3; j <= br3; j++)
            {
            if(graph[i][j] == 0)
            {
            bg3 = i;
            break;
            }
            }
            if(bg3 != 0)
            break;
            }
            //下邊界
            for(i = Height-1; i >= 0; i--)
            { n = 0;
            for(j = bl3; j <= br3; j++)
            {
            if(graph[i][j] == 0)
            { n = 1;
            bd3 = i;
            break;
            }
            }
            if(n != 0)
            break;
            }
            //第四個字符
            //左邊界
            for(i = br3+1; i < Width; i++)
            {
            for(j = 0; j < Height; j++)
            {
            if(graph[j][i] == 0)
            {
            bl4 = i;
            break;
            }
            }
            if(bl4 != 0)
            break;
            }
            //右邊界
            for(i = bl4; i < Width; i++)
            { n = 0;
            for(j = 0; j < Height; j++)
            {
            if(graph[j][i] == 0)
            { n++;
            break;
            }
            }
            if(n == 0)
            {
            br4 = i-1;
            break;
            }
            }
            if(i == Width)
            br4 = Width-1;
            //上邊界
            for(i = 0; i < Height; i++)
            {
            for(j = bl4; j <= br4; j++)
            {
            if(graph[i][j] == 0)
            {
            bg4 = i;
            break;
            }
            }
            if(bg4 != 0)
            break;
            }
            //下邊界
            for(i = Height-1; i >= 0; i--)
            { n = 0;
            for(j = bl4; j <= br4; j++)
            {
            if(graph[i][j] == 0)
            {
            n = 1;
            bd4 = i;
            break;
            }
            }
            if(n != 0)
            break;


            }


            //輸出圖片
            //Print(graph);
            //將圖片保存到z【】【】【】數(shù)組中
            for(i = bg1,a = 0;i <= bd1; i++,a++)
            { for(j = bl1,d = 0; j <= br1; j++,d++)
            z[0][a][d] = graph[i][j];
            }
            for(i = bg2,a = 0;i <= bd2; i++,a++)
            { for(j = bl2,d = 0; j <= br2; j++,d++)
            z[1][a][d] = graph[i][j];
            }
            for(i = bg3,a = 0;i <= bd3; i++,a++)
            { for(j = bl3,d = 0; j <= br3; j++,d++)
            z[2][a][d] = graph[i][j];
            }
            for(i = bg4,a = 0;i <= bd4; i++,a++)
            { for(j = bl4,d = 0; j <= br4; j++,d++)
            z[3][a][d] = graph[i][j];
            }
            duibi(z,bl1,br1,bl2,br2,bl3,br3,bl4,br4);
            printf("\n");
            /* for(i = 0; i < 4; i++)
            {
            for(j = 0; j < 20; j++)
            { for(k = 0; k < 20; k++)
            if(z[i][j][k] == 1)
            printf("1,");
            else printf("0,");
            printf("\n");
            }
            printf("\n");
            }
            */
            cout<<endl;
            fclose(fp);
            return (0);
            }
              回復(fù)  更多評論
              

            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            99热成人精品免费久久| 亚洲精品无码久久久久去q| 久久久久国产一区二区| 四虎影视久久久免费| 一本一本久久a久久综合精品蜜桃| 亚洲午夜久久久影院| jizzjizz国产精品久久| 久久亚洲国产欧洲精品一| 亚洲国产精品成人久久蜜臀| 中文字幕无码精品亚洲资源网久久| 久久国产亚洲高清观看| 99久久精品免费观看国产| 久久综合久久综合亚洲| 久久99国产综合精品女同| 精品无码久久久久久久久久| 久久久久人妻一区二区三区| 久久精品国产影库免费看| 亚洲午夜久久久| 久久国产精品-国产精品| 亚洲国产视频久久| 一本色道久久88加勒比—综合| 久久久久久伊人高潮影院 | 色妞色综合久久夜夜| 91亚洲国产成人久久精品网址| 久久无码中文字幕东京热| 久久亚洲国产中v天仙www | 国产精自产拍久久久久久蜜| 偷偷做久久久久网站| 国产ww久久久久久久久久| 亚洲人成伊人成综合网久久久| 精品人妻伦九区久久AAA片69| 久久精品蜜芽亚洲国产AV| 色偷偷88欧美精品久久久| 女人香蕉久久**毛片精品| 婷婷综合久久中文字幕蜜桃三电影| 91精品婷婷国产综合久久| 久久不见久久见免费视频7| 久久亚洲精品国产精品婷婷| 99久久国产综合精品五月天喷水| 久久国产色AV免费看| 亚洲国产精品久久电影欧美|