ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 14709|回复: 44

[分享] 浅谈vba识别图片验证码

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2019-3-1 10:23 | 显示全部楼层 |阅读模式
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 我是来讨说法的 于 2019-3-4 17:33 编辑

先看一个动画
1.gif
稍后再楼下讲解相关知识
将图片像素读取到单元格中代码:
  1. '代码写的很随意,不要介意
  2. Sub Text()
  3. Dim chs() As Byte

  4. With Sheet1.Cells.Interior
  5.     .Pattern = xlNone
  6.     .TintAndShade = 0
  7.     .PatternTintAndShade = 0
  8. End With
  9.    
  10. Open ThisWorkbook.Path & "\1.bmp" For Binary As #1
  11.      For i = 0 To LOF(1) - 1 '循环至文件末端
  12.         k = k + 1
  13.         ReDim Preserve chs(1 To k) As Byte '将文件内容存入字节数组
  14.         Get #1, , chs(k) '获取文本内容
  15.      Next i
  16. Close #1
  17. k = 1
  18. X = 20
  19. Y = 1
  20. For i = 55 To UBound(chs) Step 3
  21.     'Debug.Assert i <> 3652
  22.     'Debug.Print i
  23.     Count = Count + 1
  24.     If k > 60 Then
  25.         k = 1
  26.         X = X - 1
  27.         Y = 1
  28.     End If
  29.     'Sheet1.Cells(X, Y).Interior.Color = RGB(chs(i), chs(i + 1), chs(i + 2)) 'BGR  此句输出图片的原色
  30.     '灰阶化
  31.     grayscale = CInt((CInt(chs(i)) + CInt(chs(i + 1)) + CInt(chs(i + 2))) / 3) '颜色转化为灰色,也就是灰阶
  32.     '二值化,也就是转化成黑白色,非黑即白的颜色
  33.     If grayscale > 130 Then '设置一个合适的阈值
  34.         grayscale = 255
  35.     Else
  36.         grayscale = 0
  37.     End If
  38.     Sheet1.Cells(X, Y).Interior.Color = RGB(grayscale, grayscale, grayscale) '输出灰阶图形, 注销此句可现实原色图像
  39.     k = k + 1
  40.     Y = Y + 1
  41. Next
  42. End Sub
复制代码
注意,要将行宽设置为8像素,列宽设置为7像素,不然形成的图片就变形了

至此2019-03-04,写完所有内容。感觉有点乱,不明白的地方可以问我,相互学习
1.gif

验证码图片文件.zip

32.68 KB, 下载次数: 166

验证码识别完整版代码+测试图.zip

73.72 KB, 下载次数: 302

评分

11

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-3-1 10:23 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 我是来讨说法的 于 2019-3-1 11:33 编辑

萌生写验证码识别的想法源于网友们的求助,附件中的图片由吧友提供,具体帖子找不见了。要想识别验证码,需要了解以下知识:一、了解各种图片文件的结构
二、了解RGB色彩模式显色原理
三、提取/识别图片特征码
----------------------------------------------
1、本文只稍微讲解一下bmp图片文件的结构,因为本帖附件中的验证码图片就是bmp格式。
bmp_3.png
我们一般见到的图像以24位图像为主,即R、G、B三种颜色各用8个bit来表示,这样的图像我们称为真彩色,这种情况下是不需要调色板的,也就是说位图信息头后面紧跟的就是位图数据了,其中24位RGB按照BGR的顺序来存储每个像素的各颜色通道的值,一个像素的所有颜色分量值都存完后才存下一个下一个像素,存储的像素点再图片中的顺序是,第一个点在图片左下角,即顺序为从下到上,从左往右。
恰好,我的验证码图片也是24位图,可以从图片的属性中看出:
TIM截图20190301110602.jpg
从图中我还可以看出图片的像素是60 * 20,也就说明图像横向有60个点,竖向有20个点,所以我们需要20行60列“个单元格区域来填装图的颜色”,由上面红色文字可知:一个像素点需要3位来存储数据,分别是B G R的值,那么对于24位的bmp位图来说,他的大小就是 60(宽度) * 20(高度) * 3(BGR) + 54(文件头大小) = 3654KB
说到这里,我们既然知道了bmp的文件结构,那么就可以用二进制打开,直接读取图片的颜色信息,以此颜色为单元格背景色进行填充,代码如下:
  1. Sub Text()
  2. Dim chs() As Byte

  3. With Sheet1.Cells.Interior
  4.     .Pattern = xlNone
  5.     .TintAndShade = 0
  6.     .PatternTintAndShade = 0
  7. End With
  8.    
  9. Open ThisWorkbook.Path & "\1.bmp" For Binary As #1 '二进制打开一个bmp图片文件
  10.      For i = 0 To LOF(1) - 1 '循环至文件末端
  11.         k = k + 1
  12.         ReDim Preserve chs(1 To k) As Byte '将文件内容存入字节数组
  13.         Get #1, , chs(k) '获取文本内容
  14.      Next i
  15. Close #1
  16. k = 1
  17. X = 20
  18. Y = 1
  19. For i = 55 To UBound(chs) Step 3 '因为24位图,颜色信息是从第55位开始,每连续3个数据组成一个像素点的颜色
  20.     'Debug.Assert i <> 3652
  21.     'Debug.Print i
  22.     Count = Count + 1
  23.     If k > 60 Then
  24.         k = 1
  25.         X = X - 1
  26.         Y = 1
  27.     End If
  28.     Sheet1.Cells(X, Y).Interior.Color = RGB(chs(i), chs(i + 1), chs(i + 2)) '3个值分别对应B G R
  29.     k = k + 1
  30.     Y = Y + 1
  31. Next
  32. End Sub
复制代码


TA的精华主题

TA的得分主题

 楼主| 发表于 2019-3-1 10:24 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 我是来讨说法的 于 2019-3-1 13:47 编辑

上面已经将图片按像素填充到单元格中了,接下来要做的就是:将彩色图片转换成黑白图片,也就灰阶(度)图片,跟看黑白电视一样。首先需要了解什么是灰阶(度)?
【任何颜色都有红、绿、蓝三原色组成,假如原来某点的颜色为RGB(R,G,B),那么,我们可以通过下面几种方法,将其转换为灰度:
1.浮点算法:Gray=R*0.3+G*0.59+B*0.11
2.整数方法:Gray=(R*30+G*59+B*11)/100
3.移位方法:Gray =(R*76+G*151+B*28)>>8;
4.平均值法:Gray=(R+G+B)/3;
5.仅取绿色:Gray=G;
通过上述任一种方法求得Gray后,将原来的RGB(R,G,B)中的R,G,B统一用Gray替换,形成新的颜色RGB(Gray,Gray,Gray),用它替换原来的RGB(R,G,B)就是灰度图了。】

那么我就用最简单的平均法,直接上代码:
  1. Sub Test()
  2. Dim chs() As Byte

  3. With Sheet1.Cells.Interior
  4.     .Pattern = xlNone
  5.     .TintAndShade = 0
  6.     .PatternTintAndShade = 0
  7. End With
  8.    
  9. Open ThisWorkbook.Path & "\1.bmp" For Binary As #1 '二进制打开一个bmp图片文件
  10.      For i = 0 To LOF(1) - 1 '循环至文件末端
  11.         k = k + 1
  12.         ReDim Preserve chs(1 To k) As Byte '将文件内容存入字节数组
  13.         Get #1, , chs(k) '获取文本内容
  14.      Next i
  15. Close #1
  16. k = 1
  17. X = 20
  18. Y = 1
  19. For i = 55 To UBound(chs) Step 3 '因为24位图,颜色信息是从第55位开始,每连续3个数据组成一个像素点的颜色
  20.     'Debug.Assert i <> 3652
  21.     'Debug.Print i
  22.     Count = Count + 1
  23.     If k > 60 Then
  24.         k = 1
  25.         X = X - 1
  26.         Y = 1
  27.     End If
  28.     grayscale = CInt((CInt(chs(i)) + CInt(chs(i + 1)) + CInt(chs(i + 2))) / 3) '颜色转化为灰色,也就是灰阶
  29.     Sheet1.Cells(X, Y).Interior.Color = RGB(grayscale, grayscale, grayscale)
  30.     k = k + 1
  31.     Y = Y + 1
  32. Next
  33. End Sub
复制代码
效果图如下:
TIM截图20190301124724.jpg

从图中可以非常明显的看出数字来,但是其他地方还有干扰色块。现在我们就去掉这些干扰色块。
在去掉色块之前,需要说明一点的是:RGB代表的是红绿蓝三色,他们的取值范围都是0到256,那么这三个数的平均值grayscale肯定也在0到256之间,因此,我们先试取一个数200,我们用grayscale和200比较,如果大于20,我们将grayscale的值变为256(白色),否则让grayscale等于0(黑色),让他两极分化,也就是图片的二值化处理,那么刚才的数字200,就叫他阀值。代码如下:
  1. Sub Text()
  2. Dim chs() As Byte
  3. With Sheet1.Cells.Interior
  4.     .Pattern = xlNone
  5.     .TintAndShade = 0
  6.     .PatternTintAndShade = 0
  7. End With
  8. Open ThisWorkbook.Path & "\4.bmp" For Binary As #1
  9.      For i = 0 To LOF(1) - 1 '循环至文件末端
  10.         k = k + 1
  11.         ReDim Preserve chs(1 To k) As Byte '将文件内容存入字节数组
  12.         Get #1, , chs(k) '获取文本内容
  13.      Next i
  14. Close #1
  15. k = 1
  16. X = 20
  17. Y = 1
  18. For i = 55 To UBound(chs) Step 3
  19.     'Debug.Assert i <> 3652
  20.     'Debug.Print i
  21.     count = count + 1
  22.     If k > 60 Then
  23.         k = 1
  24.         X = X - 1
  25.         Y = 1
  26.     End If
  27.     'Sheet1.Cells(X, Y).Interior.Color = RGB(chs(i), chs(i + 1), chs(i + 2)) 'BGR  此句输出图片的原色
  28.     '灰阶化
  29.     grayscale = CInt((CInt(chs(i)) + CInt(chs(i + 1)) + CInt(chs(i + 2))) / 3) '颜色转化为灰色,也就是灰阶
  30.     '二值化,也就是转化成黑白色,非黑即白的颜色
  31.     If grayscale > 130 Then '设置一个合适的阈值
  32.         grayscale = 256
  33.         'Sheet1.Cells(X, Y) = 0
  34.     Else
  35.         grayscale = 0
  36.         'Sheet1.Cells(X, Y) = 1
  37.     End If
  38.     Sheet1.Cells(X, Y).Interior.Color = RGB(grayscale, grayscale, grayscale)
  39.     Sleep 2
  40.     DoEvents
  41.     k = k + 1
  42.     Y = Y + 1
  43. Next
  44. End Sub
复制代码

阀值等于180的图像(下图):
TIM截图20190301130052.jpg
我可以看出,还有很多干扰点,我们继续调整阀值的大小,设为130时的图像,下图:

阀值等于130

阀值等于130


我发现当阀值等于130时,“图像”非常清晰。接下来,我们就可以开始识别图形中的数字啦,请看下楼


TA的精华主题

TA的得分主题

 楼主| 发表于 2019-3-1 10:25 | 显示全部楼层
本帖最后由 我是来讨说法的 于 2019-3-4 17:24 编辑

上面已经讲到如何将图片二值化出来,本节将讲解识别部分。识别方法主要是:制作样本模板,和验证码对比。
图片验证码都是将数字放在一起,我们需要做的是将数字拆开,一个一个的来识别。因此我们需要制作一个模板,此验证码只有数字组成,因此需要制作0到9共10个模板。如下图:

0.jpg 1.jpg
制作模板有如下要求:首先要找到二值化处理后的excel图像的上下左右边界,复制到相应的工作表中。
我们在后续的程序出来中,也需要用程序将二值化处理后的图像进行分割,分割的要求也是必须找到图像的边界。也就是说,一个矩形区域刚好能包围住一个数字,矩形的4条边上的数字不能全为0。这是关键!!
之后我们将动态分割验证码,然后逐一和模板对比,即模板的第一行第一列和分割后的验证码的第一行第一列对比,完全一致则根据工作表名称可知验证码是多少。
完整代码见顶楼

TA的精华主题

TA的得分主题

发表于 2019-3-1 10:43 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2019-3-1 10:46 来自手机 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-3-1 12:38 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册

大坏蛋啊~~~

TA的精华主题

TA的得分主题

发表于 2019-3-1 14:12 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
占楼学习。。。

TA的精华主题

TA的得分主题

发表于 2019-3-1 14:15 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
8楼占用!

TA的精华主题

TA的得分主题

发表于 2019-3-1 14:35 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-11 02:09 , Processed in 1.055999 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表