游戏密保卡图片识别

识别主要步骤

1.图像预处理。包括确认图片有效区域,灰度化,二值化。

2.字符分割。即将识别信息最小化。由于密保卡图片文字宽度固定且无粘连,只需要使用固定宽度切割。

3.对分割后的信息提取特征,建立特征库

4.提取特征和特征库样本进行匹配,输出识别结果

 

首先看下密保卡图片

1、减少识别区域。由于密保卡有效区域固定,故将有效区域直接截取出来。

2、图片灰度化

 图片灰度算法有平均值法,分量法,最大值法,加权平均法,本例用的加权平均法

 public static Bitmap CorlorGray(Bitmap bmp)
        {//位图矩形
                System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
                //以可读写方式锁定全部位图像素
                System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
                //得到首地址
                IntPtr ptr = bmpData.Scan0;
                //定义被锁定的数组大小,由位图数据与未用空间组成
                int bytes = bmpData.Stride * bmpData.Height;
                byte[] rgbValues = new byte[bytes];
                //复制被锁定的位图像素值到数组中
                System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
                //灰度化
                double colorTemp = 0;
                for (int i = 0; i < bmpData.Height; i++)
                {
                    //只处理每行图像像素数据,舍弃未用空间
                    for (int j = 0; j < bmpData.Width * 3; j += 3)
                    {
                        colorTemp = rgbValues[i * bmpData.Stride + j + 2] * 0.299 + rgbValues[i * bmpData.Stride + j + 1] * 0.587 + rgbValues[i * bmpData.Stride + j] * 0.114;
                        rgbValues[i * bmpData.Stride + j] = rgbValues[i * bmpData.Stride + j + 1] = rgbValues[i * bmpData.Stride + j + 2] = (byte)colorTemp;
                    }
                }
                //把数组复位回位图
                System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
                //解锁位图
                bmp.UnlockBits(bmpData);
            return bmp;
        }

 

3、图片二值化

 

最常见的二值处理方法是计算像素的平均值K,扫描图像的每个像素值如像素值大于K

像素值设为255(白色),值小于等于K像素值设为0(黑色)

#region 阈值法二值化  

        public static Bitmap Threshoding(Bitmap b, byte threshold)
        {
            int width = b.Width;
            int height = b.Height;
            BitmapData data = b.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            unsafe
            {
                byte* p = (byte*)data.Scan0;
                int offset = data.Stride - width * 4;
                byte R, G, B, gray;
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        R = p[2];
                        G = p[1];
                        B = p[0];
                        gray = (byte)((R * 19595 + G * 38469 + B * 7472) >> 16);
                        if (gray >= threshold)
                        {
                            p[0] = p[1] = p[2] = 255;
                        }
                        else
                        {
                            p[0] = p[1] = p[2] = 0;
                        }
                        p += 4;
                    }
                    p += offset;
                }
                b.UnlockBits(data);
                return b;
            }

        }
        #endregion

 4、字符分割

由于密保卡每个小方块大小固定,如果识别A1,那么只需截取一个37* 20的图片块来进行处理。

循环遍历图片Y轴每个像素点,找到字符之间像素全为白色的X坐标集合,从而将图片切割。

public static List<Bitmap> Cut(Bitmap bitmap)
        {

            List<ContentRectangle> lst = new List<ContentRectangle>();
            int width = bitmap.Width;
            int height = bitmap.Height;
            int[] xarray = new int[width];

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    int r = bitmap.GetPixel(x, y).R;
                    if (r == 0)
                        xarray[x] += 1;
                }
            }
            int temp = 0;
            int[] yarray = new int[height];
            for (int i = 0; i < width; i++)
            {

                if (xarray[i] > 0 && i != 0 && xarray[i - 1] <= 0)
                {
                    temp = i;
                }

                if (xarray[i] > 0 && i < width - 1 && xarray[i + 1] <= 0)
                {
                    for (int j = 0; j < height; j++)
                    {
                        for (int x = temp + 1; x < i + 1; x++)
                        {
                            int r = bitmap.GetPixel(x, j).R;
                            if (r == 0)
                                yarray[j] += 1;
                        }
                    }
                }

                int ttmp = 0;
                for (int y = 0; y < height; y++)
                {
                    if (yarray[y] != 0)
                    {
                        ttmp = y;
                        break;
                    }
                }
                for (int x = height - 1; x > -1; x--)
                {
                    if (yarray[x] != 0)
                    {
                        ContentRectangle rectangle = new ContentRectangle();
                        rectangle.X = temp;
                        rectangle.Width = i + 1 - temp;
                        rectangle.Y = ttmp;
                        rectangle.Height = x + 1 - ttmp;
                        lst.Add(rectangle);
                        yarray = new int[height];
                        break;
                    }
                }
            }

            List<Bitmap> lstbmp = new List<Bitmap>();
            foreach (ContentRectangle rect in lst)
            {
                var tempbmp = bitmap.Clone(new System.Drawing.Rectangle(rect.X, rect.Y, rect.Width, rect.Height), bitmap.PixelFormat);
                lstbmp.Add(tempbmp);
            }
            return lstbmp;
        }

 

5、建立特征库

字符切割后得到了类似以下图片。人眼可以直观的辨识出来,但机器却是不认识的。所以需要建立特征库,以便机器比对识别。

    /// <summary>
        /// 获取数字对应的二值化代码
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static string GetCodebybitmap(Bitmap bitmap)
        {
            StringBuilder code = new StringBuilder();
            for (int i = 0; i < bitmap.Width; i++)
            {
                for (int j = 0; j < bitmap.Height; j++)
                {
                    int r = bitmap.GetPixel(i, j).R;
                    code.Append(r > 127 ? "1" : "0");
                }
            }

            return code.ToString();
        }

将图片7像素点逐个扫描转换为0,、1表示的二值化字符串与数字7进行关联存储,建立特征库。

6、识别

按上述步骤进行图片处理后取得图片的0、1表示的二值化代码并与特征库中的代码进行比对,匹配对应代码完成识别。

匹配算法可以直接使用代码相等,但这样使得特征库必须完善,否则容易匹配失败。所以一般都会采用字符串相似度匹配,设置阈值,相似度大于阈值的即为同一个字符。相关算法自行百度。

 

posted @ 2017-09-08 16:38  L`G  阅读(897)  评论(0编辑  收藏  举报