python图形验证码识别

本文介绍了使用Python进行图形验证码识别的全过程,包括图像预处理、8临域法降噪、连通域法切割和机器学习识别。通过灰度化、二值化减少噪声,结合连通域法和K-means聚类处理字符粘连,最终实现高准确率的验证码识别。
摘要由CSDN通过智能技术生成

开发环境

  1. Python2.7
  2. Pillow4.1.1
  3. numpy1.15.2
  4. sklearn0.20.0

思路

  1. 对图像进行灰度化、二值化处理
  2. 根据图像特征进行切割,提取单个字符内容
  3. 针对单个字符进行机器学习
  4. 识别

实践

演示用的原始图片如下
原始图片

图像预处理 - 灰度、二值化

首先用PIL内置的convert方法进行灰度处理,经过灰度后,每个像素点的颜色值从RGB的3维变成了1维,值的范围为0-255,值越大,颜色越倾向于白,或者说颜色更淡。
灰度化图片
观察灰度后的图片,可以发现字符的颜色更深,背景、干扰线的颜色更浅,这一特征是后续二值化操作的关键。
二值化是在灰度图的基础上将所有像素点的颜色二值化,也就是非黑即白,这里遍历像素点,简单地根据一个预设的灰度阈值,将大于阈值的灰度值设为0,即白色,小于阈值的灰度值设为255,即黑色。(这里阈值需要经过多次试验,确定一个合适的值,如果验证码比较复杂,背景、干扰线不能很好地和字符区分,需要一些特殊处理和计算来获得合适的阈值,这点以后有机会再做深入研究)
二值化效果如下:
二值化图片

from PIL import Image

def remove_color(img, threshold=105):
    """
    灰度、二值化
    :param img: Image实例
    :param threshold: 灰度阈值
    :return:
    """
    img_greyed = img.convert('L')  # 灰度化
    table = img_greyed.load()
    width, height = img_greyed.size
    for x in range(width):
        for y in range(height):
            if table[x, y] < threshold:
                table[x, y] = 0
            else:
                table[x, y] = 255
    return img_greyed

图像预处理 - 8临域法降噪

经过灰度、二值化的图片,可以看到干扰线被去得比较干净,但还剩余了零散的噪点,接下来根据8临域法来去除噪点。
8临域指的是一个像素点周围的8个点,如果一个点的周围都是白色背景,那么这个点就一定是噪点。反之,遍历各像素点,统计其8个临近点的值,如果值为255即黑色的数量大于某个阈值,则该点不是噪点,这里阈值取的是6,效果如下:
降噪图片
效果拔群!

def remove_noise(img, threshold=6):
    """8临域法降噪"""
    table = img.load()
    width, height = img.size
    for x in range(1, width-1):
        for y in range(1, height-1):
            count = 0
            if table[x, y-1] == 255:
                count += 1
            if table[x, y+1] == 255:
                count += 1
            if table[x-1, y] == 255:
                count += 1
            if table[x+1, y] == 255:
                count += 1
            if table[x-1, y-1] == 255:
                count += 1
            if table[x-1, y+1] == 255:
                count += 1
            if table[x+1, y+1] == 255:
                count += 1
            if table[x+1, y-1] == 255:
                count += 1
            if count > threshold:
                table[x, y] = 255

注意x与y的遍历范围在[1, width-1]与[1, height-1]之间,这是为了避免取8临域的时候发生下标越界。

图像切割

步骤一:连通域法获取字符图像

对于连通域法的讲解,https://www.cnblogs.com/fireae/p/3723785.html 这篇文章挺不错的。
以下python代码实现了对图像的两次扫描,第一次扫描将相邻像素点进行标号,并记录标号等价关系;第二次扫描将标号替换成最小等价标号,并将像素点分组,用于后续切割。最后根据传入阈值,将面积小于阈值的连通域作为噪点剔除。

def get_domains(img_denoised, threshold=10):
    """
    获取连通域
    """
    table = img_denoised.load()
    width, height = img_denoised.size
    tab_img = Image.new('L', (width, height), 255)
    tab_table = tab_img.load()
    equals = []  # 存储标号等价关系,e.g. [[1, 2, 3], [4, 6], [5]]
    tab = 1  # 下一个标号
    # 第一次扫描
    for y in range(height):
        for x in range(width):
            if table[x, y] == 0:
                tab = set_temp_tab(tab_table, x, y, tab, equals)
    # 第二次扫描
    domains = {
   }
    for y in range(height):
        for x in range(width):
            if tab_table[x, y] != 255:
                min_tab = get_min_tab(tab_table[x, y], equals)
                if min_tab in domains:
                    domains[min_tab].append((x, y))
                else:
                    domains[min_tab] = [(x, y)]
    real_domains = [domains[i] for i in domains if len
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值