简单的验证码识别

这是我尝试写的第一篇技术博客,借鉴了很多博客和教程,写出了自己的代码,代码较为冗杂而且程序十分耗时。所以本文主要提供验证码识别的一个简单的思路,代码实现的部分还望各位大佬指点。

看了好几篇验证码图片识别的博文,不难归纳出验证码识别的大概思路是收集训练集——>图像处理——>得到图片特征值——>训练——>识别,其中图像处理部分又包括了灰度化、二值化、去噪、分割等过程。本文将尽量有详有略地讲述整个过程,以及本菜鸡在开发过程中遇到的问题。

话不多说,现在开始。


一、训练集的收集

要收集足够多的验证码,只需要写一个简单的爬虫,去一些各大网站的登录系统爬取就好。本菜鸡爬的是自己学校教务系统的登录网站,所以不太方便附上代码。本菜鸡总共爬取了500张验证码作为训练集,以及200张验证码用于测试,并已将自己得到的验证码放到了github上,github地址在文末给出。

这一过程需要注意,必须要手动输入这些验证码的答案,并将这些答案保存下来。而且为了提高识别的正确率,需要检查自己输入的验证码内容是否有误

接下来我们就要对收集到的训练集进行处理。


二、图像处理

以下用到了Python3的PIL(Pillow)库:

1、干扰线的处理

让我们先来看看得到验证码图片:

Captcha1 Captcha2 Captcha3
我们可以看到,每一张验证码图片上,都有很多的干扰线,虽然这些干扰线不会影响到我们自己识别验证码,但它们会极大地干扰到机器对验证码识别的正确率。本菜鸡曾经测试过,若不去掉这些干扰线,无论怎么优化算法,最终的识别正确率都在40%左右徘徊,所以这些干扰线是一定要尽量去消除的。当然,我们可以选择将图片灰度化、二值化后再去尝试去除干扰线,但本菜鸡试过很多次后,发现在原图片消除干扰线的效果是最好的。

那么问题来了,我们要怎么去掉这些干扰线呢?

其实大家可以通过目测发现:这些干扰线都是黑色的!

那我们是不是把图片上的所有黑色去掉就好了呢?其实也并不完全是如此。我们都知道,每一种颜色都有它的RGB值,本菜鸡在看了一遍收集到的验证码之后,就开始猜想:这些干扰线颜色的RGB值是不是都在一个范围内?

我们假定两种颜色的RGB的红黄蓝三个值相差均小于10,则认为这两种颜色是同一种颜色,例如,假定(0,0,0)和(10,10,10)是同一种颜色,基于这个假定,我们可以将一张验证码图片所有像素点的颜色分类,并存储不同种类颜色的相应点的坐标。例如:红色:(1,1),(1,2)……

from PIL import Image
from PIL import ImageDraw
import os

now_path = str(os.getcwd()).replace('\\','/') + "/" #得到当前目录

# 判断是否为同一种类的颜色
def isSameColor(a,b):
    return abs(a[0]-b[0])<10 and abs(a[1]-b[1])<10 and abs(a[2]-b[2])<10 

# 得到不同种类颜色的坐标
def divideColor(image):
    color_map = {}
    for i in range(image.size[0]):
        for j in range(image.size[1]):
            now_color = image.getpixel((i,j)) #得到该点的RGB值,注意参数是一个元组
            flag = 1
            for key in color_map:
                if isSameColor(key,now_color):
                    flag = 0
                    color_map[key].append((i,j)) #若是相同种类的颜色,记录当前坐标
            if flag:
                color_map[now_color] = [(i,j)] #否则添加一种新的颜色
    return color_map

得到了各种颜色对应的坐标,接下来我们可以用这些颜色和坐标在空白图上画点,找出干扰线所对应的颜色

# 在空白图上画点
def divideDraw(color_map):
    save_path = now_path + "pixel/" # 新图的存储目录
    for key in color_map:
        now_image = Image.new('RGB',(90,32),(255,255,255)) # 新建一张图,它是RGB类型(第一个参数为类型)的、
                                                           # 尺寸为90*32(第二个参数为尺寸)、背景为白色(第三个参数为背景色)
        drawer = ImageDraw.Draw(now_image)# 新建画笔
        for x in color_map[key]:
            drawer.point(x,key)# 描点画图
        now_image.save(save_path + str(key) + ".png")# 将得到的图存起来

test_image = Image.open(now_path + "captcha/0001.png")# 打开一张验证码
divideDraw(divideColor(test_image))

Captcha
Captcha_pixel
对第一张图处理后,我们得到了很多张图,根据截图里的三张图,我们可以知道干扰线的RGB的三个值在0~21之间。对多张图处理后,本菜鸡发现干扰线的RGB值大概在0~15之间,我们可以看看RGB值和颜色的对应表来证实我们的猜测 (注意,如果RGB范围设置的过大,会导致验证码也被清除)。
这里写图片描述
于是,我们可以根据得到的干扰线的RGB范围,来去除验证码中的干扰线。

# 清除所有黑色点,after_table_b是用于描点画图的
def clear_black(image, x, y, after_table_b):
    now = image.getpixel((x,y)) 
    if now[0]<=15 and now[1]<=15 and now[2]<=15:
        after_table_b[y][x] = (255,255,255) #如果是该像素点是黑色的,则直接将它暴力设置为白色
    else: 
        after_table_b[y][x] = now #否则就设置成它原来的颜色

前面三张验证码去除了干扰线后的效果如下:

  • 27
    点赞
  • 100
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值