圖像 - 識別出圖片里的數字和字母


本文給大家分享的是C#識別出圖片里的數字和字母的代碼,主要是識別以前公司的軟件注冊碼截圖里的數字和字母,功能很簡單,也存在很大的局限性,這里僅僅是分享,小伙伴們參考下。
一個圖片識別小工具,原先主要是識別以前公司的軟件注冊碼截圖里的數字和字母(每次要一個一個框復制出來粘貼到注冊器里,很麻煩!),因為注冊碼出現的字母和數字基本就那幾個,所以識別庫的范圍設定的比較少。
原理和算法在代碼中做了詳細說明,功能存在很大的局限性,但我的想法是把這個思路和實現的辦法共享出來。
源碼下載地址:
http://git.oschina.net/bobo2cj/iamge2text

 
         
  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Text;
  7 using System.Windows.Forms;
  8 
  9 namespace iamge2text
 10 {
 11     public partial class FormLicense : Form
 12     {
 13 
 14         /*
 15          * 開發思路:圖片灰度處理,二進制,然后和圖片中的字二進制庫精確對比
 16          * 
 17          * 獲取字庫:通過下面代碼中generateLicense(Bitmap singlepic)方法獲得,具體操作:
 18          *      從圖片中截圖出(摳出)一個字符,然后處理得到二維的二進制矩陣,比如下面的字符1對應的二維矩陣
 19          *      00000
 20          *      00100
 21          *      11100
 22          *      00100
 23          *      00100
 24          *      00100
 25          *      00100
 26          *      00100
 27          *      00100
 28          *      11111
 29          *      00000
 30          *      00000
 31          *      
 32          * 注意:【相同字符,比如1,不同字體,字號,不同縮放大小的圖片,獲得到的二位矩陣中0、1排列和數量都是不同的!
 33          *          故按照此方法來寫出匹配所有字的話,那字庫就大了。。。】
 34          * 
 35          * 
 36         */
 37         public FormLicense()
 38         {
 39             InitializeComponent();
 40             buttonGenerate.Enabled = false;         //在pictureBox控件中無圖片時buttonGenerate按鈕不可用
 41             richTextBoxLicense.ReadOnly = true;     //並且不可以在文本框中改動輸出后的字符
 42             this.AcceptButton = this.buttonOpen;    //回車鍵作用在打開按鈕上
 43         }
 44 
 45         #region 在用的字符對應黑白顏色二進制碼的字庫,我的工具中只需要下面的幾個字符,所有不是所有文字都能識別出來
 46         static string stringByte0 = "000000001100010010100001100001100001100001100001010010001100000000000000";
 47         static char[] char0 = stringByte0.ToCharArray();
 48         static int BinaryWidth0 = 5, BinaryHeight0 = 11;    //0的平面像素長寬(從0開始數起)
 49 
 50         static string stringByte1 = "000000010011100001000010000100001000010000100111110000000000";
 51         static char[] char1 = stringByte1.ToCharArray();
 52         static int BinaryWidth1 = 4, BinaryHeight1 = 11;    //1的平面像素長寬(從0開始數起)
 53 
 54         static string stringByte2 = "000000111010001100010000100010001000100010001111110000000000";
 55         static char[] char2 = stringByte2.ToCharArray();
 56         static int BinaryWidth2 = 4, BinaryHeight2 = 11;    //2的平面像素長寬(從0開始數起)
 57 
 58         static string stringByte3 = "000000111010001100010011000001000011000110001011100000000000";
 59         static char[] char3 = stringByte3.ToCharArray();
 60         static int BinaryWidth3 = 4, BinaryHeight3 = 11;    //3的平面像素長寬(從0開始數起)
 61 
 62         static string stringByte4 = "000010000010000110001010010010010010100010011111000010000111000000000000";
 63         static char[] char4 = stringByte4.ToCharArray();
 64         static int BinaryWidth4 = 5, BinaryHeight4 = 11;    //4的平面像素長寬(從0開始數起)
 65 
 66         static string stringByte5 = "000001111110000100001111010001000011000110001011100000000000";
 67         static char[] char5 = stringByte5.ToCharArray();
 68         static int BinaryWidth5 = 4, BinaryHeight5 = 11;    //5的平面像素長寬(從0開始數起)
 69 
 70         static string stringByte6 = "000000001111010001100000101110110001100001100001100001011110000000000000";
 71         static char[] char6 = stringByte6.ToCharArray();
 72         static int BinaryWidth6 = 5, BinaryHeight6 = 11;    //6的平面像素長寬(從0開始數起)
 73 
 74         static string stringByte7 = "000001111110001100100001000100001000010000100001000000000000";
 75         static char[] char7 = stringByte7.ToCharArray();
 76         static int BinaryWidth7 = 4, BinaryHeight7 = 11;    //7的平面像素長寬(從0開始數起)
 77 
 78         static string stringByte8 = "000000011110100001100001010010011110100001100001100001011110000000000000";
 79         static char[] char8 = stringByte8.ToCharArray();
 80         static int BinaryWidth8 = 5, BinaryHeight8 = 11;    //8的平面像素長寬(從0開始數起)
 81 
 82         static string stringByte9 = "000000011110100001100001100001100011011101000001100010111100000000000000";
 83         static char[] char9 = stringByte9.ToCharArray();
 84         static int BinaryWidth9 = 5, BinaryHeight9 = 11;    //9的平面像素長寬(從0開始數起)
 85 
 86         static string stringByteA = "000000000000000000000000011100100010001110010010100010011111000000000000";
 87         static char[] charA = stringByteA.ToCharArray();
 88         static int BinaryWidthA = 5, BinaryHeightA = 11;    //a的平面像素長寬(從0開始數起)
 89 
 90         static string stringByteB = "000000110000010000010000011110010001010001010001010001011110000000000000";
 91         static char[] charB = stringByteB.ToCharArray();
 92         static int BinaryWidthB = 5, BinaryHeightB = 11;    //b的平面像素長寬(從0開始數起)
 93 
 94         static string stringByteC = "000000000000000000000111110001100001000010001011100000000000";
 95         static char[] charC = stringByteC.ToCharArray();
 96         static int BinaryWidthC = 4, BinaryHeightC = 11;    //c的平面像素長寬(從0開始數起)
 97 
 98         static string stringByteD = "000000000110000010000010011110100010100010100010100010011111000000000000";
 99         static char[] charD = stringByteD.ToCharArray();
100         static int BinaryWidthD = 5, BinaryHeightD = 11;    //d的平面像素長寬(從0開始數起)
101 
102         static string stringByteE = "000000000000000000000111010001111111000010001011100000000000";
103         static char[] charE = stringByteE.ToCharArray();
104         static int BinaryWidthE = 4, BinaryHeightE = 11;    //e的平面像素長寬(從0開始數起)
105 
106         static string stringByteF = "000000000111001001001000111110001000001000001000001000011110000000000000";
107         static char[] charF = stringByteF.ToCharArray();
108         static int BinaryWidthF = 5, BinaryHeightF = 11;    //f的平面像素長寬(從0開始數起)
109 
110         static string stringByteP = "000000000000000000000000111110010001010001010001010001011110010000111000";
111         static char[] charP = stringByteP.ToCharArray();
112         static int BinaryWidthP = 5, BinaryHeightP = 11;    //p的平面像素長寬(從0開始數起)
113 
114         static string stringByteY = "000000000000000000000000000011101110100010001010000101000001000000100000100001110000";
115         static char[] charY = stringByteY.ToCharArray();
116         static int BinaryWidthY = 6, BinaryHeightY = 11;    //y的平面像素長寬(從0開始數起)
117         #endregion
118 
119         static int[,] intStartXY = new int[128, 3];    //記錄匹配上時的“X坐標”和“Y坐標”對應的“值”以及該“字符像素的寬度”
120         static int numIdentfied = 0;    //負責記錄總共有多少匹配的字符
121 
122         //打開圖片按鈕
123         private void buttonOpen_Click(object sender, EventArgs e)
124         {
125             try
126             {
127                 Bitmap m_Bitmap;    //定義個Bitmap型變量存儲圖片
128                 OpenFileDialog openFileDialog = new OpenFileDialog();    //打開圖片
129                 openFileDialog.Filter = "Bitmap文件(*.bmp)|*.bmp|Jpeg文件(*.jpg)|*.jpg|所有合適文件(*.bmp/*.jpg)|*.bmp/*.jpg";    //設置圖片類型
130                 openFileDialog.FilterIndex = 1;    //打開對話框中默認第一個類型(即上面的Bitmap文件(*.bmp)|*.bmp)
131                 openFileDialog.RestoreDirectory = true;    //記錄最后一次打開的文件路徑
132                 if (DialogResult.OK == openFileDialog.ShowDialog())//確定打開文件
133                 {
134                     m_Bitmap = (Bitmap)Bitmap.FromFile(openFileDialog.FileName, false);    //通過(Bitmap)將打開的圖片類型轉換
135                     pictureBoxLicense.Image = m_Bitmap;    //為pictureBox控件加載所打開的圖片
136                     AutoScroll = true;
137                     AutoScrollMinSize = new Size((int)(m_Bitmap.Width), (int)m_Bitmap.Height);
138                     buttonGenerate.Enabled = true;    //在pictureBox控件中有圖片時buttonGenerate按鈕可用
139                     this.buttonGenerate.Select();
140                 }
141             }
142             catch { }
143         }
144 
145         //提取注冊碼按鈕
146         private void buttonGenerate_Click(object sender, EventArgs e)
147         {
148             try
149             {
150                 buttonGenerate.Enabled = false;    //該圖片只可進行一次提取,之后就不可用除非再加載該圖片
151                 this.buttonOpen.Select();
152                 numIdentfied = 0;    //將計數器清零
153                 Bitmap Sourcebm = (Bitmap)pictureBoxLicense.Image;    //為了保險起見將pictureBox的圖片類型進行格式轉換(Bitmap)
154                 int iw = Sourcebm.Width;    //圖片寬度  
155                 int ih = Sourcebm.Height;    //圖片高度  
156                 //下面雙循環是圖片灰度處理  
157                 for (int i = 0; i < iw; i++)
158                 {//從左到右
159                     for (int j = 0; j < ih; j++)
160                     {//從上到下
161                         Color c = Sourcebm.GetPixel(i, j);    //獲取該點的顏色
162                         int luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);    //將顏色轉換為數值體現  
163                         Sourcebm.SetPixel(i, j, Color.FromArgb(luma, luma, luma));    //將這一點進行灰度處理,非白色的部分變黑
164                     }
165                 }
166                 generateLicense(Sourcebm);    //通過該方法進行提取字符
167             }
168             catch { }
169         }
170 
171         /// <summary>
172         /// 提取出該圖片內的字符(將進過灰度處理的圖片轉化為0、1的二位數組)
173         /// </summary>
174         /// <param name="singlepic">圖片來源</param>
175         public void generateLicense(Bitmap singlepic)
176         {
177             try
178             {
179                 char[,] charArray = new char[singlepic.Height, singlepic.Width];    //定義個chai型的二維數組記錄每個像素上0/1的值,形成一個矩形
180                 int imageWidth = 0;    //記錄圖片的像素寬度
181                 int imageHeight = 0;    //記錄圖片的像素高度
182                 int dgGrayValue = 128;    //灰度值
183                 Color piexl;
184                 //string code = "";    //存儲每個像素的0/1
185                 for (int posy = 0; posy < singlepic.Height; posy++)
186                 {//從上到下
187                     string codeCache = "";    //存儲每行的像素的0/1
188                     for (int posx = 0; posx < singlepic.Width; posx++)
189                     {//從左到右
190                         piexl = singlepic.GetPixel(posx, posy);
191                         if (piexl.R < dgGrayValue)    
192                         {// 如果該像素的顏色為黑色,值就為“1”
193                             codeCache = codeCache + "1";
194                         }
195                         else
196                         {// 否則該像素的顏色為白色,值就為“0”
197                             codeCache = codeCache + "0";                            
198                         }
199                     }
200                     char[] array = codeCache.ToCharArray();    //每行的0/1的值用數字保存,以便於進行循環處理
201                     //code += codeCache + "\n";
202                     for (imageWidth = 0; imageWidth < array.Length; imageWidth++)
203                         charArray[imageHeight, imageWidth] = array[imageWidth];    //通過循環將每行值轉存到二維數組中
204                     imageHeight++;
205                 }       //*********************以上代碼可用來獲取一個字的圖片二進制數組,即字庫*****************************
206 
207                 //開始和字庫進行匹配(我的工具中只需要下面的幾個字符)
208                 findWord(charArray, char0, imageHeight, imageWidth, BinaryWidth0, BinaryHeight0, '0');
209                 findWord(charArray, char1, imageHeight, imageWidth, BinaryWidth1, BinaryHeight1, '1');
210                 findWord(charArray, char2, imageHeight, imageWidth, BinaryWidth2, BinaryHeight2, '2');
211                 findWord(charArray, char3, imageHeight, imageWidth, BinaryWidth3, BinaryHeight3, '3');
212                 findWord(charArray, char4, imageHeight, imageWidth, BinaryWidth4, BinaryHeight4, '4');
213                 findWord(charArray, char5, imageHeight, imageWidth, BinaryWidth5, BinaryHeight5, '5');
214                 findWord(charArray, char6, imageHeight, imageWidth, BinaryWidth6, BinaryHeight6, '6');
215                 findWord(charArray, char7, imageHeight, imageWidth, BinaryWidth7, BinaryHeight7, '7');
216                 findWord(charArray, char8, imageHeight, imageWidth, BinaryWidth8, BinaryHeight8, '8');
217                 findWord(charArray, char9, imageHeight, imageWidth, BinaryWidth9, BinaryHeight9, '9');
218                 findWord(charArray, charA, imageHeight, imageWidth, BinaryWidthA, BinaryHeightA, 'a');
219                 findWord(charArray, charB, imageHeight, imageWidth, BinaryWidthB, BinaryHeightB, 'b');
220                 findWord(charArray, charC, imageHeight, imageWidth, BinaryWidthC, BinaryHeightC, 'c');
221                 findWord(charArray, charD, imageHeight, imageWidth, BinaryWidthD, BinaryHeightD, 'd');
222                 findWord(charArray, charE, imageHeight, imageWidth, BinaryWidthE, BinaryHeightE, 'e');
223                 findWord(charArray, charF, imageHeight, imageWidth, BinaryWidthF, BinaryHeightF, 'f');
224                 findWord(charArray, charP, imageHeight, imageWidth, BinaryWidthP, BinaryHeightP, 'p');
225                 findWord(charArray, charY, imageHeight, imageWidth, BinaryWidthY, BinaryHeightY, 'y');
226                 //------------------------------------END---------------------------------------------
227                 richTextBoxLicense.Text += identifySort();    //執行identifySort方法,將我需要的格式在richTextBoxLicense文本框中顯示
228                 richTextBoxLicense.SelectionStart = richTextBoxLicense.TextLength;    //將光標移到最后面
229             }
230             catch { }
231         }
232 
233         /// <summary>
234         /// 和字庫進行匹配
235         /// </summary>
236         /// <param name="charArray">記錄圖片中每個像素的二維數組</param>
237         /// <param name="charNum">字庫中0/1值一維數組形式的字符</param>
238         /// <param name="imageHeight">圖片的像素高度</param>
239         /// <param name="imageWidth">圖片的像素寬度</param>
240         /// <param name="binaryWidth">字庫中該字符的像素寬度</param>
241         /// <param name="binaryHeight">字庫中該字符的像素高度</param>
242         /// <param name="stringChar">字庫中該字符</param>
243         public void findWord(char[,] charArray, char[] charNum, int imageHeight, int imageWidth, int binaryWidth, int binaryHeight, char stringChar)
244         {
245             try
246             {
247                 int upLeftX, upLeftY, x, y;
248                 for (y = 0; y < imageHeight - binaryHeight; y++)//從圖片的每行開始
249                 {
250                     for (x = 0; x < imageWidth - binaryWidth; x++)//從當前行的第一格開始
251                     {
252                         bool isIdentified = false;    //負責辨別是否匹配
253                         int count = 0;    //負責計數
254                         for (upLeftY = 0; upLeftY <= binaryHeight; upLeftY++)//從圖片中取出一塊進行對比,從的每行開始
255                         {
256                             for (upLeftX = 0; upLeftX <= binaryWidth; upLeftX++)//從這一塊當前行的第一格開始
257                             {
258                                 //下面進行每格的對比,大數字去除的“塊”是二維數組,小數組是一維數組
259                                 if (charArray[y + upLeftY, x + upLeftX] == charNum[upLeftY * (binaryWidth + 1) + upLeftX])
260                                 {
261                                     isIdentified = true;    //記錄像素點是否比對成功
262                                     count++;
263                                     if (count == (binaryWidth + 1) * (binaryHeight + 1))//判斷是否對比到了最后一個像素點
264                                     {
265                                         intStartXY[numIdentfied, 0] = y;    //記錄字庫中該字符在圖片中出現的Y值
266                                         intStartXY[numIdentfied, 1] = x;    //記錄字庫中該字符在圖片中出現的X值
267                                         intStartXY[numIdentfied, 2] = Convert.ToInt32(stringChar);    //將該字符轉換為數字型
268                                         numIdentfied++;    //記錄圖片中總共多少個字庫中的數字
269                                         break;    //一旦匹配即將結束比對
270                                     }
271                                 }
272                                 else
273                                 {
274                                     isIdentified = false;    //此像素點比對不成功
275                                     break;    //如果該像素點值比對不成功即將結束比對
276                                 }
277                             }
278                             if (!isIdentified)//如果一個不符就向后退一格,同時小數組的比對又需要從第一格開始
279                                 break;    //並且結束這次的比對
280                         }
281                     }
282                 }
283             }
284             catch { }
285         }
286 
287         /// <summary>
288         /// 對比對后的結果通過坐標進行排序
289         /// </summary>
290         /// <returns>提取出的圖片中的字符串</returns>
291         public string identifySort()
292         {
293             string stringLicense = "";    //存儲該結果
294             try
295             {
296                 int intTemp = 0;
297                 for (int a = 0; a < numIdentfied; a++)
298                 {//從第一列開始
299                     for (int b = 0; b < numIdentfied; b++)
300                     {//然后從該列中第一行開始對比
301                         if (intStartXY[a, 0] < intStartXY[b, 0])
302                         {//通過Y坐標(離頂端距離)判斷那個字符在上面,並進行對調
303                             for (int c = 0; c < 3; c++)
304                             {
305                                 intTemp = intStartXY[a, c];
306                                 intStartXY[a, c] = intStartXY[b, c];
307                                 intStartXY[b, c] = intTemp;
308                             }
309                         }
310                         if (intStartXY[a, 0] == intStartXY[b, 0] && intStartXY[a, 1] < intStartXY[b, 1])
311                         {//當Y坐標(離頂端距離)相同時,通過X坐標(離左端距離)判斷那個字符在左面,並進行對調
312                             for (int c = 0; c < 3; c++)
313                             {
314                                 intTemp = intStartXY[a, c];
315                                 intStartXY[a, c] = intStartXY[b, c];
316                                 intStartXY[b, c] = intTemp;
317                             }
318                         }
319                     }
320                 }
321 
322                 //------------------------下面是我需要的格式-------------------------------------------------------------
323                 /*
324                     yp_12_125
325                     yp_12_125
326                     e4ebf340-563b5e1c-b04957df-baacc576
327                  */
328                 for (int h = 0; h < numIdentfied; h++)
329                 {
330                     stringLicense += Convert.ToChar(intStartXY[h, 2]);
331                     if ((intStartXY[h + 1, 0] == intStartXY[h, 0] && intStartXY[h + 1, 1] - intStartXY[h, 1] >= 12 && h < numIdentfied - 32))
332                         stringLicense += "_";    //當同一行時,相差一個下划線距離就顯示下划線_
333                     if (intStartXY[h + 1, 0] - intStartXY[h, 0] >= 11 && h < numIdentfied - 17)
334                         stringLicense += "\n";    //當不上一行時就輸出\n
335                     if (h == numIdentfied - 25 || h == numIdentfied - 17 || h == numIdentfied - 9)
336                         stringLicense += "-";    //每8個顯示一個中划線-
337                 }
338                 //---------------------------------------END---------------------------------------------------------------------------------
339             }
340             catch { }
341             return stringLicense + "\n";    //對返回的結果進行換行,保證在richTextBox文本框顯示的時候光標始終在下行
342         }
343 
344         private void pictureBoxLicense_DoubleClick(object sender, EventArgs e)
345         {//通過雙擊控件粘貼圖片
346             try
347             {
348                 IDataObject iData = Clipboard.GetDataObject();    //GetDataObject檢索當前剪貼板上的數據            
349                 if (iData.GetDataPresent(DataFormats.Bitmap))//將數據與指定的格式進行匹配
350                 {
351                     // GetData檢索數據並指定一個格式
352                     Bitmap bitmapLicense = (Bitmap)iData.GetData(DataFormats.Bitmap);
353                     pictureBoxLicense.Image = bitmapLicense;    //加載截屏后的圖片
354                     buttonGenerate.Enabled = true;    //pictureBox中新圖片時提取按鈕便可使用
355                     this.buttonGenerate.Select();
356                 }
357                 else
358                 {
359                     MessageBox.Show("目前剪貼板中數據不是圖片\n   請先截圖再雙擊此處!", "Error");
360                 }
361             }
362             catch { }
363         }
364 
365         private void FormLicense_Load(object sender, EventArgs e)
366         {
367 
368         }
369     }
370 }
 
         

 

 
        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM