游戏密保卡图片识别

识别主要步骤

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399886.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于visual Studio2013解决C语言竞赛题之0505选数

&#xfeff;&#xfeff;题目解决代码及点评/************************************************************************/ /* 5&#xff0e; 输入N个数到数组中&#xff0c;选出其中最大的数和最小的数&#xff0c;并分别将它们与最前面和最后面的数互换 */ /*************…

TP5:缩短访问路径和路由的使用——2

一、缩短访问路径 1、如图访问该文件路径 没有缩短之前&#xff0c;访问的路径是 http://localhost/zerg_new/public/index.php/api/v1/banner/1 缩短后&#xff0c;访问的路径是 http://z_new.cn/api/v1/banner/1 2、缩短路径步骤 本机apache配置&#xff0c;小编使用的…

10个加速Table Views开发的Tips

2019独角兽企业重金招聘Python工程师标准>>> 本文由CocoaChina译者yake_099&#xff08;博客&#xff09;翻译&#xff0c;作者&#xff1a;David McGraw 原文&#xff1a;10 Actionable Performance Tips To Speed Up Your Table View 在我们开始之前&#xff0c;…

TP5:验证器的封装——5

TP5的独立验证器如图所示&#xff1a; $validate new Validate([name > require|max:25,email > email ]); $data [name > thinkphp,email > thinkphpqq.com ]; if (!$validate->check($data)) {dump($validate->getError()); } 现在我们把验证器的封装…

flask蓝图的使用

flask蓝图的使用 首先&#xff0c;我对蓝图的理解相对通俗&#xff0c;就是觉得蓝图对于视图方法模块化、大项目协同开发过程中的一个很好的工具. 1.下图是我们通常情况下使用的项目组织结构 看一下视图方法: #views.py1 from app import app2 3 4 app.route(/user/index)5 d…

TP5:异常处理封装——3

如果不进过异常封装&#xff0c;如果抛出一异常只会只会上图所示&#xff0c;大部分时候&#xff0c;用户只需要知道Division by zero就够了。 1、首先先建一个类BaseException并继承Exception&#xff0c;这里有三个参数 $code 400; $msg ; $errorCode ;并处理当抛出异常时的…

接口测试(java+testng+ant+jenkins)第三篇ant

1、ant是什么&#xff1f; 是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具 2、下载安装 http://www.cnblogs.com/yuzhongwusan/archive/2013/03/26/2982411.html 3、在eclipce中的使用 准备工作&#xff1a; 项目右键——new——folder——folder name: li…

KVM虚拟机IO处理过程(二) ----QEMU/KVM I/O 处理过程

接着KVM虚拟机IO处理过程中Guest Vm IO处理过程(http://blog.csdn.net/dashulu/article/details/16820281),本篇文章主要描述IO从guest vm跳转到kvm和qemu后的处理过程. 首先回顾一下kvm的启动过程(http://blog.csdn.net/dashulu/article/details/17074675).qemu通过调用kvm提供…

如何利用echarts图表获取条状图点击名称和值

如何利用echarts图表获取条状图点击名称和值 听语音 |浏览&#xff1a;1505|更新&#xff1a;2017-06-13 10:20|标签&#xff1a;软件 1 2 3 4 5 6 7 分步阅读 echarts图表插件工具&#xff0c;包含了各种不同类型的图形&#xff0c;有圆饼图、折线图、圆环图、柱状图…

TP5: 日志记录改造——4

TP5的日志如果没有特别设置的话&#xff0c;只要出现错误就会记录在日志文件中。这种是没有做必要的&#xff0c;因为这样的话&#xff0c;LOG文件会特别大&#xff0c;而且有好多都是没有用的信息。下面我们对LOG日志进行改造只记录我们需要的信息。 还记得上一章中&#xff…

.NET使用免费开源类库操作Excel

2019独角兽企业重金招聘Python工程师标准>>> 自从上次找到NPOI之后&#xff0c;根据园友提供的线索以及Google&#xff0c;又找到了一些开源免费的类库&#xff0c;所以都简单体验了一遍。 主要找到以下类库&#xff1a; MyXls(http://sourceforge.net/projects/m…

JMS 消息处理

转载于:https://www.cnblogs.com/luswei/p/7504781.html

设计模式(单例)

单例模式是最简单的设计模式&#xff0c; 意图&#xff1a; 保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。 适用性&#xff1a; 只能有一个实例而且客户可以从一个众所周知的访问点访问它时。 当这个唯一实例应该是通过子类化可扩展的&#xff0c;并且客户…

牛刀小试、用SharePoint 实现请假管理功能

转&#xff1a;http://www.cr173.com/html/15518_1.html “请假管理”应用&#xff0c;应该算是 SharePoint 的“Hello World&#xff01;”、川菜里面的鱼香肉丝、粤菜里面的蛋炒饭 。。。吧&#xff1f; 怎么样才能做出简易、实用的请假管理&#xff0c;一直都是都是一个问题…

django时区设置问题

2019独角兽企业重金招聘Python工程师标准>>> 最近用Django开发项目&#xff0c;在使用datetime类获取.now()时&#xff0c;获取的时间比实际时间相差8小时左右&#xff08;感觉是UTC时间&#xff09;&#xff0c;服务器使用的时区是“Asia/Shanghai”&#xff08;08…

Objective-C模版方法(TemplateMethod)

什么是模版方法&#xff1f; 官方&#xff1a;定义一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中。模版方法使子类可以重新定义算法的某些步骤而不改变算法的结构。 个人理解&#xff1a;模版方法没必要刻意去理解&#xff0c;平时的编码过程中不知不觉就会用到…

微信小程序+TP5——token令牌生成

token令牌的作用&#xff1a;客户端每次登录服务器端都会生成一个唯一的token令牌值&#xff0c;并返回到客户端&#xff0c;而服务器端会默认将token令牌值作为key, 用户信息作为value&#xff0c;一一对应存入缓存中&#xff0c;当用户每一次发送请求时&#xff0c;都要携带这…

基于live555实现的RTSPServer对底层进行性能优化的方法

在博客《EasyIPCamera高性能摄像机RTSP服务器RTSPServer解决方案》我介绍了基于live555实现的一套RTSPServer功能组件&#xff0c;当时开发者经过几个月的调试&#xff0c;已经将底层的性能调试到了一个业界非常优秀的程度&#xff0c;主要优化的几点&#xff1a; 发送优化调度…

sqlite 字符串 转 整型 cast 函数 (强制类型转换 )

sqlite 字符串 转 整型使用 cast 函数 语法&#xff1a; cast(col_name as type) 例子&#xff1a; 表&#xff1a;JobInfo 表内字段&#xff1a;Salary 薪水 select * from JobInfo where cast(substr(Salary,1,5)as int)>10000 结果集&#xff1a; 转载于:https://www.cn…