zoukankan      html  css  js  c++  java
  • 图像

    本文给大家分享的是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 + "
    ";
    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 += "
    ";    //当不上一行时就输出
    
    335                     if (h == numIdentfied - 25 || h == numIdentfied - 17 || h == numIdentfied - 9)
    336                         stringLicense += "-";    //每8个显示一个中划线-
    337                 }
    338                 //---------------------------------------END---------------------------------------------------------------------------------
    339             }
    340             catch { }
    341             return stringLicense + "
    ";    //对返回的结果进行换行,保证在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("目前剪贴板中数据不是图片
       请先截图再双击此处!", "Error");
    360                 }
    361             }
    362             catch { }
    363         }
    364 
    365         private void FormLicense_Load(object sender, EventArgs e)
    366         {
    367 
    368         }
    369     }
    370 }
    
    
    
    
    
  • 相关阅读:
    【收藏】如何理解二维数组
    【algo&ds】9.拓扑排序、AOV&AOE、关键路径问题
    【algo&ds】8.最小生成树
    【algo&ds】7.最短路径问题
    【algo&ds】6.图及其存储结构、遍历
    【c&c++】变量初始化
    【algo&ds】【pat】5.并查集及其应用
    【algo&ds】4.B树、字典树、红黑树、跳表
    【algo&ds】4.树和二叉树、完全二叉树、满二叉树、二叉查找树、平衡二叉树、堆、哈夫曼树、散列表
    【algo&ds】3.栈和队列
  • 原文地址:https://www.cnblogs.com/DuanLaoYe/p/5386338.html
Copyright © 2011-2022 走看看