游戏密保卡图片识别
識別主要步驟
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表示的二值化代碼并與特征庫中的代碼進行比對,匹配對應代碼完成識別。
匹配算法可以直接使用代碼相等,但這樣使得特征庫必須完善,否則容易匹配失敗。所以一般都會采用字符串相似度匹配,設置閾值,相似度大于閾值的即為同一個字符。相關算法自行百度。
?
轉載于:https://www.cnblogs.com/guozhongxiang/p/7495338.html
總結
- 上一篇: 梦到一只狗狗一直跟着我什么意思
- 下一篇: 梦到踩一脚大便什么意思