[置顶] c#验证码识别、图片二值化、分割、分类、识别
c# 验证码的识别主要分为预处理、分割、识别三个步骤
首先我从网站上下载验证码
处理结果如下:
1.图片预处理,即二值化图片
*就是将图像上的像素点的灰度值设置为0或255。
原理如下:
代码如下:
#region 二值化图片 /// <summary> /// 二值化图片 /// 就是将图像上的像素点的灰度值设置为0或255 /// </summary> /// <returns>处理后的验证码</returns> public Bitmap BinaryZaTion() { for (int x = 0; x < img.Width; x++) { for (int y = 0; y < img.Height; y++) { __c = img.GetPixel(x, y); //灰度值 int __tc = (__c.R + __c.G + __c.B) / 3; //大于阙值 黑色 if (__tc > t) { img.SetPixel(x, y, Color.FromArgb(__c.A, b, b, b)); //黑色点个数自加 __blackNum++; } //大于阙值 白色 else { img.SetPixel(x, y, Color.FromArgb(__c.A, w, w, w)); } } } return img; } #endregion
二值化过后需要判断图片的黑白比列,若果黑色比白色多,需要对图片反色处理。
代码如下:
#region 是否需要反色 /// <summary> /// 是否需要反色 /// </summary> /// <returns>是否需要反色</returns> public bool IsNeedInverseColor() { if ((__blackNum * 1.0 / (img.Width * img.Height)) > 0.5) { return true; } else { return false; } } #endregion #region 反色 /// <summary> /// 反色 /// </summary> /// <returns>处理后的验证码</returns> public Bitmap InverseColor() { for (int x = 0; x < img.Width; x++) { for (int y = 0; y < img.Height; y++) { __c = img.GetPixel(x, y); img.SetPixel(x, y, Color.FromArgb(__c.A, w - __c.R, w - __c.G, w - __c.B)); } } return img; } #endregion
处理结果如下:
2.图片分割
我的做法是先每一竖行判断是否是纯白色行,不是的话记录当前x坐标,然后没以横行判断是否纯白色行,这样就能的到每一个数字的区域,然后将区域画出来。
代码如下:
#region 分割图片 /// <summary> /// 分割图片 /// </summary> /// <returns>处理后的验证码</returns> public Bitmap CutImg() { //Y轴分割 CutY(); //区域个数 __count = 0; if (XList.Count > 1) { //x起始值 int __start = XList[0]; //x结束值 int __end = XList[XList.Count - 1]; //x索引 int __idx = 0; while (__start != __end) { //区域宽度 int __w = __start; //区域个数自加 __count++; while (XList.Contains(__w) && __idx < XList.Count) { //区域宽度自加 __w++; //x索引自加 __idx++; } //区域X轴坐标 int x = __start; //区域Y轴坐标 int y = 0; //区域宽度 int width = __w - __start; //区域高度 int height = img.Height; /* * X轴分割当前区域 */ CutX(img.Clone(new Rectangle(x, y, width, height), img.PixelFormat)); if (YList.Count > 1 && YList.Count != img.Height) { int y1 = YList[0]; int y2 = YList[YList.Count - 1]; if (y1 != 1) { y = y1 - 1; } height = y2 - y1 + 1; } //GDI+绘图对象 Graphics g = Graphics.FromImage(img); g.SmoothingMode = SmoothingMode.HighQuality; g.CompositingMode = CompositingMode.SourceOver; g.PixelOffsetMode = PixelOffsetMode.HighSpeed; g.InterpolationMode = InterpolationMode.HighQualityBicubic; //画出验证码区域 g.DrawRectangle(new Pen(Brushes.Green), new Rectangle(x, y, width, height)); g.Dispose(); //起始值指向下一组 if (__idx < XList.Count) { __start = XList[__idx]; } else { __start = __end; } } } return img; } #endregion #region Y轴字符分割图片 /// <summary> /// 得到Y轴分割点 /// 判断每一竖行是否有黑色 /// 有则添加 /// </summary> /// <param name="img">要验证的图片</param> private void CutY() { XList.Clear(); for (int x = 0; x < img.Width; x++) { isWhilteLine = false; for (int y = 0; y < img.Height; y++) { __c = img.GetPixel(x, y); if (__c.R == w) { isWhilteLine = true; } else { isWhilteLine = false; break; } } if (!isWhilteLine) { XList.Add(x); } } } #endregion #region X轴字符分割图片 /// <summary> /// 得到X轴分割点 /// 判断每一横行是否有黑色 /// 有则添加 /// </summary> /// <param name="tempImg">临时区域</param> private void CutX(Bitmap tempImg) { YList.Clear(); for (int x = 0; x < tempImg.Height; x++) { isWhilteLine = false; for (int y = 0; y < tempImg.Width; y++) { __c = tempImg.GetPixel(y, x); if (__c.R == w) { isWhilteLine = true; } else { isWhilteLine = false; break; } } if (!isWhilteLine) { YList.Add(x); } } tempImg.Dispose(); } #endregion
效果如下:
3.识别
识别呢就是提取出图片的特征
我的做法是将图片数字区域逐一分成4*4的区域,计算出各个区域的黑色点所占的百分比,然后将计算出来的结果和以前计算的特征进行比较,求出欧氏距离 d = sqrt( (x1-x2)^2+(y1-y2)^2 )最小的一个作为结果。
部分代码如下:
#region 黑色像素比列 /// <summary> /// 计算黑色像素比列 /// </summary> /// <param name="tempimg"></param> /// <returns></returns> private double PixlPercent(Bitmap tempimg) { int temp = 0; int w_h = tempimg.Width * tempimg.Height; for (int x = 0; x < tempimg.Width; x++) { for (int y = 0; y < tempimg.Height; y++) { __c = tempimg.GetPixel(x, y); if (__c.R == b) { temp++; } } } tempimg.Dispose(); double result = temp * 1.0 / w_h; result = result.ToString().Length > 3 ? Convert.ToDouble(result.ToString().Substring(0, 3)) : result; return result; } #endregion
效果如下:
本代码只做研究学习之用。
新手上路,有任何建议、意见联系 pigkeli@qq.com 。
posted on 2013-12-13 16:22 love so much 阅读(3975) 评论(2) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架