图像-识别出图⽚⾥的数字和字母
本⽂给⼤家分享的是C#识别出图⽚⾥的数字和字母的代码,主要是识别以前公司的软件注册码截图⾥的数字和字母,功能很简单,也存在很⼤的局限性,这⾥仅仅是分享,⼩伙伴们参考下。
⼀个图⽚识别⼩⼯具,原先主要是识别以前公司的软件注册码截图⾥的数字和字母(每次要⼀个⼀个框复制出来粘贴到注册器⾥,很⿇烦!),因为注册码出现的字母和数字基本就那⼏个,所以识别库的范围设定的⽐较少。原理和算法在代码中做了详细说明,功能存在很⼤的局限性,但我的想法是把这个思路和实现的办法共享出来。
源码下载地址:
git.oschina/bobo2cj/iamge2text
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Data;
5using System.Drawing;
6using System.Text;
7using System.Windows.Forms;
8
9namespace iamge2text
10 {
11public 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*/
37public FormLicense()
38        {
39            InitializeComponent();
40            buttonGenerate.Enabled = false;        //在pictureBox控件中⽆图⽚时buttonGenerate按钮不可⽤
41            richTextBoxLicense.ReadOnly = true;    //并且不可以在⽂本框中改动输出后的字符
42this.AcceptButton = this.buttonOpen;    //回车键作⽤在打开按钮上
43        }
44
45#region在⽤的字符对应⿊⽩颜⾊⼆进制码的字库,我的⼯具中只需要下⾯的⼏个字符,所有不是所有⽂字都能识别出来
46static string stringByte0 = "000000001100010010100001100001100001100001100001010010001100000000000000";
47static char[] char0 = stringByte0.ToCharArray();
48static int BinaryWidth0 = 5, BinaryHeight0 = 11;    //0的平⾯像素长宽(从0开始数起)
49
50static string stringByte1 = "000000010011100001000010000100001000010000100111110000000000";
51static char[] char1 = stringByte1.ToCharArray();
52static int BinaryWidth1 = 4, BinaryHeight1 = 11;    //1的平⾯像素长宽(从0开始数起)
53
54static string stringByte2 = "000000111010001100010000100010001000100010001111110000000000";
55static char[] char2 = stringByte2.ToCharArray();
56static int BinaryWidth2 = 4, BinaryHeight2 = 11;    //2的平⾯像素长宽(从0开始数起)
57
58static string stringByte3 = "000000111010001100010011000001000011000110001011100000000000";
59static char[] char3 = stringByte3.ToCharArray();
60static int BinaryWidth3 = 4, BinaryHeight3 = 11;    //3的平⾯像素长宽(从0开始数起)
61
62static string stringByte4 = "000010000010000110001010010010010010100010011111000010000111000000000000";
63static char[] char4 = stringByte4.ToCharArray();
64static int BinaryWidth4 = 5, BinaryHeight4 = 11;    //4的平⾯像素长宽(从0开始数起)
65
66static string stringByte5 = "0000011111100001000011110100010000110001100010111000000000
00";
67static char[] char5 = stringByte5.ToCharArray();
68static int BinaryWidth5 = 4, BinaryHeight5 = 11;    //5的平⾯像素长宽(从0开始数起)
69
70static string stringByte6 = "000000001111010001100000101110110001100001100001100001011110000000000000";
71static char[] char6 = stringByte6.ToCharArray();
72static int BinaryWidth6 = 5, BinaryHeight6 = 11;    //6的平⾯像素长宽(从0开始数起)
73
74static string stringByte7 = "000001111110001100100001000100001000010000100001000000000000";
75static char[] char7 = stringByte7.ToCharArray();
76static int BinaryWidth7 = 4, BinaryHeight7 = 11;    //7的平⾯像素长宽(从0开始数起)
77
78static string stringByte8 = "000000011110100001100001010010011110100001100001100001011110000000000000";
79static char[] char8 = stringByte8.ToCharArray();
80static int BinaryWidth8 = 5, BinaryHeight8 = 11;    //8的平⾯像素长宽(从0开始数起)
81
82static string stringByte9 = "000000011110100001100001100001100011011101000001100010111100000000000000";
83static char[] char9 = stringByte9.ToCharArray();
84static int BinaryWidth9 = 5, BinaryHeight9 = 11;    //9的平⾯像素长宽(从0开始数起)
85
86static string stringByteA = "000000000000000000000000011100100010001110010010100010011111000000000000";
87static char[] charA = stringByteA.ToCharArray();
88static int BinaryWidthA = 5, BinaryHeightA = 11;    //a的平⾯像素长宽(从0开始数起)
89
90static string stringByteB = "000000110000010000010000011110010001010001010001010001011110000000000000";
91static char[] charB = stringByteB.ToCharArray();
92static int BinaryWidthB = 5, BinaryHeightB = 11;    //b的平⾯像素长宽(从0开始数起)
93
94static string stringByteC = "000000000000000000000111110001100001000010001011100000000000";
95static char[] charC = stringByteC.ToCharArray();
96static int BinaryWidthC = 4, BinaryHeightC = 11;    //c的平⾯像素长宽(从0开始数起)
97
98static string stringByteD = "000000000110000010000010011110100010100010100010100010011111000000000000";
99static char[] charD = stringByteD.ToCharArray();
100static int BinaryWidthD = 5, BinaryHeightD = 11;    //d的平⾯像素长宽(从0开始数起)
101
102static string stringByteE = "000000000000000000000111010001111111000010001011100000000000";
103static char[] charE = stringByteE.ToCharArray();
104static int BinaryWidthE = 4, BinaryHeightE = 11;    //e的平⾯像素长宽(从0开始数起)
105
106static string stringByteF = "000000000111001001001000111110001000001000001000001000011110000000000000";
图片下载站源码107static char[] charF = stringByteF.ToCharArray();
108static int BinaryWidthF = 5, BinaryHeightF = 11;    //f的平⾯像素长宽(从0开始数起)
109
110static string stringByteP = "000000000000000000000000111110010001010001010001010001011110010000111000";
111static char[] charP = stringByteP.ToCharArray();
112static int BinaryWidthP = 5, BinaryHeightP = 11;    //p的平⾯像素长宽(从0开始数起)
113
114static string stringByteY = "00000000000000000000000000001110111010001000101000010100
0001000000100000100001110000"; 115static char[] charY = stringByteY.ToCharArray();
116static int BinaryWidthY = 6, BinaryHeightY = 11;    //y的平⾯像素长宽(从0开始数起)
117#endregion
118
119static int[,] intStartXY = new int[128, 3];    //记录匹配上时的“X坐标”和“Y坐标”对应的“值”以及该“字符像素的宽度”
120static int numIdentfied = 0;    //负责记录总共有多少匹配的字符
121
122//打开图⽚按钮
123private void buttonOpen_Click(object sender, EventArgs e)
124        {
125try
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;    //记录最后⼀次打开的⽂件路径
132if (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按钮可⽤
139this.buttonGenerate.Select();
140                }
141            }
142catch { }
143        }
144
145//提取注册码按钮
146private void buttonGenerate_Click(object sender, EventArgs e)
147        {
148try
149            {
150                buttonGenerate.Enabled = false;    //该图⽚只可进⾏⼀次提取,之后就不可⽤除⾮再加载该图⽚
151this.buttonOpen.Select();
152                numIdentfied = 0;    //将计数器清零
153                Bitmap Sourcebm = (Bitmap)pictureBoxLicense.Image;    //为了保险起见将pictureBox的图⽚类型进⾏格式转换(Bitmap)
154int iw = Sourcebm.Width;    //图⽚宽度
155int ih = Sourcebm.Height;    //图⽚⾼度
156//下⾯双循环是图⽚灰度处理
157for (int i = 0; i < iw; i++)
158                {//从左到右
159for (int j = 0; j < ih; j++)
160                    {//从上到下
161                        Color c = Sourcebm.GetPixel(i, j);    //获取该点的颜⾊
162int 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            }
168catch { }
169        }
170
171///<summary>
172///提取出该图⽚内的字符(将进过灰度处理的图⽚转化为0、1的⼆位数组)
173///</summary>
174///<param name="singlepic">图⽚来源</param>
175public void generateLicense(Bitmap singlepic)
176        {
177try
178            {
179char[,] charArray = new char[singlepic.Height, singlepic.Width];    //定义个chai型的⼆维数组记录每个像素上0/1的值,形成⼀个矩形180int imageWidth = 0;    //记录图⽚的像素宽度
181int imageHeight = 0;    //记录图⽚的像素⾼度
182int dgGrayValue = 128;    //灰度值
183                Color piexl;
184//string code = "";    //存储每个像素的0/1
185for (int posy = 0; posy < singlepic.Height; posy++)
186                {//从上到下
187string codeCache = "";    //存储每⾏的像素的0/1
188for (int posx = 0; posx < singlepic.Width; posx++)
189                    {//从左到右
190                        piexl = singlepic.GetPixel(posx, posy);
191if (piexl.R < dgGrayValue)
192                        {// 如果该像素的颜⾊为⿊⾊,值就为“1”
193                            codeCache = codeCache + "1";
194                        }
195else
196                        {// 否则该像素的颜⾊为⽩⾊,值就为“0”
197                            codeCache = codeCache + "0";
198                        }
199                    }
200char[] array = codeCache.ToCharArray();    //每⾏的0/1的值⽤数字保存,以便于进⾏循环处理
201//code += codeCache + "\n";
202for (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            }
230catch { }
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>
243public void findWord(char[,] charArray, char[] charNum, int imageHeight, int imageWidth, int binaryWidth, int binaryHeight, char stringChar) 244        {
245try
246            {
247int upLeftX, upLeftY, x, y;
248for (y = 0; y < imageHeight - binaryHeight; y++)//从图⽚的每⾏开始
249                {
250for (x = 0; x < imageWidth - binaryWidth; x++)//从当前⾏的第⼀格开始
251                    {
252bool isIdentified = false;    //负责辨别是否匹配
253int count = 0;    //负责计数
254for (upLeftY = 0; upLeftY <= binaryHeight; upLeftY++)//从图⽚中取出⼀块进⾏对⽐,从的每⾏开始
255                        {
256for (upLeftX = 0; upLeftX <= binaryWidth; upLeftX++)//从这⼀块当前⾏的第⼀格开始
257                            {
258//下⾯进⾏每格的对⽐,⼤数字去除的“块”是⼆维数组,⼩数组是⼀维数组
259if (charArray[y + upLeftY, x + upLeftX] == charNum[upLeftY * (binaryWidth + 1) + upLeftX])
260                                {
261                                    isIdentified = true;    //记录像素点是否⽐对成功
262                                    count++;
263if (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++;    //记录图⽚中总共多少个字库中的数字
269break;    //⼀旦匹配即将结束⽐对
270                                    }
271                                }
272else
273                                {
274                                    isIdentified = false;    //此像素点⽐对不成功
275break;    //如果该像素点值⽐对不成功即将结束⽐对
276                                }
277                            }
278if (!isIdentified)//如果⼀个不符就向后退⼀格,同时⼩数组的⽐对⼜需要从第⼀格开始
279break;    //并且结束这次的⽐对
280                        }
281                    }
282                }
283            }
284catch { }
285        }
286
287///<summary>
288///对⽐对后的结果通过坐标进⾏排序
289///</summary>
290///<returns>提取出的图⽚中的字符串</returns>
291public string identifySort()
292        {
293string stringLicense = "";    //存储该结果
294try
295            {
296int intTemp = 0;
297for (int a = 0; a < numIdentfied; a++)
298                {//从第⼀列开始
299for (int b = 0; b < numIdentfied; b++)
300                    {//然后从该列中第⼀⾏开始对⽐
301if (intStartXY[a, 0] < intStartXY[b, 0])
302                        {//通过Y坐标(离顶端距离)判断那个字符在上⾯,并进⾏对调
303for (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                        }
310if (intStartXY[a, 0] == intStartXY[b, 0] && intStartXY[a, 1] < intStartXY[b, 1])
311                        {//当Y坐标(离顶端距离)相同时,通过X坐标(离左端距离)判断那个字符在左⾯,并进⾏对调
312for (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*/
328for (int h = 0; h < numIdentfied; h++)
329                {
330                    stringLicense += Convert.ToChar(intStartXY[h, 2]);
331if ((intStartXY[h + 1, 0] == intStartXY[h, 0] && intStartXY[h + 1, 1] - intStartXY[h, 1] >= 12 && h < numIdentfied - 32)) 332                        stringLicense += "_";    //当同⼀⾏时,相差⼀个下划线距离就显⽰下划线_
333if (intStartXY[h + 1, 0] - intStartXY[h, 0] >= 11 && h < numIdentfied - 17)
334                        stringLicense += "\n";    //当不上⼀⾏时就输出\n
335if (h == numIdentfied - 25 || h == numIdentfied - 17 || h == numIdentfied - 9)
336                        stringLicense += "-";    //每8个显⽰⼀个中划线-
337                }
338//---------------------------------------END---------------------------------------------------------------------------------
339            }
340catch { }
341return stringLicense + "\n";    //对返回的结果进⾏换⾏,保证在richTextBox⽂本框显⽰的时候光标
始终在下⾏
342        }
343
344private void pictureBoxLicense_DoubleClick(object sender, EventArgs e)
345        {//通过双击控件粘贴图⽚
346try
347            {
348                IDataObject iData = Clipboard.GetDataObject();    //GetDataObject检索当前剪贴板上的数据
349if (iData.GetDataPresent(DataFormats.Bitmap))//将数据与指定的格式进⾏匹配
350                {
351// GetData检索数据并指定⼀个格式
352                    Bitmap bitmapLicense = (Bitmap)iData.GetData(DataFormats.Bitmap);
353                    pictureBoxLicense.Image = bitmapLicense;    //加载截屏后的图⽚
354                    buttonGenerate.Enabled = true;    //pictureBox中新图⽚时提取按钮便可使⽤
355this.buttonGenerate.Select();
356                }
357else
358                {
359                    MessageBox.Show("⽬前剪贴板中数据不是图⽚\n  请先截图再双击此处!", "Error");
360                }
361            }
362catch { }
363        }
364
365private void FormLicense_Load(object sender, EventArgs e)
366        {
367
368        }
369    }
370 }

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。