字符验证码识别干扰线处理

Python的PIL

python imaging library是Python平台的图像处理标准库,我们在图像处理时不仅可以使用opencvPIL也是可以的。

from PIL import Image

# 打开图片
img = Image.open("123.jpg")
# 获取宽、高
width, height = img.size()
# 获取像素值
r, g, b = img.getpixel((15, 9))
# 保存图片
img.save('456.png')

PIL还可以做图片剪裁,模糊等其他操作,并且PIL还可以打开opencv打不开的图片;

我曾遇到过使用opencv打开为None,而使用PIL可以打开的图片,但是使用PIL保存会提示:cannot write mode P as JPEG

后查资料发现,PIL模块打开图片分为以下模式:

1             1位像素,黑和白,存成8位的像素
L             8位像素,黑白
P             8位像素,使用调色板映射到任何其他模式
RGB           3×8位像素,真彩
RGBA          4×8位像素,真彩+透明通道
CMYK          4×8位像素,颜色隔离
YCbCr         3×8位像素,彩色视频格式
I             32位整型像素
F             32位浮点型像素

可以先将模式为P的图片先转化为RGB模式再保存。

# 查看模式
print(img.mode)
# 转换模式
img = img.convert("RGB")
img.save("456.png")

因为PIL在处理像素方面比较方便,而opencv在模糊处理等方面更为便捷,所以经常可能需要两者联合使用,这里记录一种两种对象互相转换的方式(不用保存文件做中转)

  • PILImage直接读取二进制流

    from PIL import Image
    from io import BytesIO
    
    # image_content是图片的二进制流
    img = Image.open(BytesIO(image_content))
    
  • OpenCV cv2直接读取二进制流

    import cv2
    import numpy as np
    
    img = cv2.imdecode(np.frombuffer(image_content, np.uint8), cv2.IMREAD_COLOR)
    
  • 将Image对象转换为二进制流

    from PIL import Image
    from io import BytesIO 
    
    out = BytesIO()
    # img是Image对象
    img.save(out, format="JPEG")
    image_content = out.getvalue()
    
  • cv2对象转换为二进制流

    import cv2
    
    res, out = cv2.imencode('.jpg', img)
    image_content = out.tobytes()
    

掌握了上面四种技巧,就可以直接将任一种对象转换为二进制流,再以二进制流的形式读取即可。

验证码数据增强

通常在使用神经网络识别图像时,可以对图片进行翻转、平移、缩放、旋转等一系列操作以达到扩充数据集的目的,虽然对于验证码也可以使用类似的方式来扩充数据集,但是具体操作方式与普通图像有一定的区别,一般图像可能是识别一整个物体之类的,而验证码需要识别其中的数个字符(一般为4~6个),首先翻转平移之类的操作就不适合验证码,例如6翻转变成了9,这将会对模型训练起到反作用,平移也可能导致丢失字符;缩放和旋转是可以对验证码进行的操作,但是幅度不宜过大,不同的验证码图片即便字符大小有区别,应该也是很微小的,并且验证码字符常常有倾斜的可能,但是我们也不宜将其倾斜幅度过大,否则也有可能将一个倾斜的6变成一个倾斜的9。

数据增强一般用于训练数据不足的情况,当训练数据比较充足时,使用数据增强提升可能很小。

from keras.preprocessing.image import ImageDataGenerator

# 旋转10度,缩放0.05
train_datagen = ImageDataGenerator(rotation_range=10, zoom_range=0.05)
验证码图片去除干扰线

在这里插入图片描述

像上面这种形式的验证码,有比较明显的干扰线,并且大部分的干扰线有个明显的特征,颜色比验证码字符的颜色更鲜艳一些,所以可以考虑根据像素值分布来去除绝大部分的干扰线,windows自带的画图软件有个很好用的功能叫“颜色选取器”,使用方式如下:

点击箭头指向的选项:

在这里插入图片描述

然后将鼠标放到你选取的图片的某个区域处,再点击颜色编辑,就可以看到这个颜色的RGB

在这里插入图片描述

以下是我简单看了一些颜色的RGB值:

# 干扰线的颜色
# 绿色 [51, 255, 51]
# 嫩绿色 [153, 213, 51]
# 深绿色 [51, 85, 51]
# 黄色 [255, 255, 102]
# 棕色 [102, 43, 51]
# 粉红色(较亮) [255, 0, 153]
# 粉红色(较暗) [204, 85, 102]
# 橙色 [204, 85, 0]
# [51, 85, 204]

# 验证码的颜色
# 深蓝色 [0, 0, 255]
# [51, 0, 204]
# [102, 43, 102]
# [102, 0, 102]
# [102, 0, 51]

经过观察,很容易发现大多数情况下,干扰线的颜色RG的值比较大,而验证码字符的颜色B的值较大(或者至少可以说验证码字符的RG的值比较小),那只要找到这样一个分界值,就可以把干扰线去掉了。我这里找个一个粗略的边界值,展示一下代码实现方式:

def process_img(img_list: list, img_path: str):
    for img in img_list:
        path = f'{img_path}{img}'
        image = Image.open(path)
        for i in range(image.size[0]):
            for j in range(image.size[1]):
                r, g, b = image.getpixel((i, j))
                # 将部分像素值变为纯白色
                if r > 110 or g > 100:
                    image.putpixel((i, j), (255, 255, 255))

        image.save(f'img_new/{img}')

麻瓜库

最近开源了一个白嫖的OCR库,可以用来识别单行的印刷体文字或者验证码字符,具体查看官方文档,我有使用它测试上面那种验证码字符的识别准确率,简单写下过程:

安装:pip install muggle-ocr

使用:

import muggle_ocr

# model_type 可选: [ModelType.OCR, ModelType.Captcha]
sdk = muggle_ocr.SDK(model_type=muggle_ocr.ModelType.Captcha)
# 预测
text = sdk.predict(image_bytes=captcha_bytes)
print(text)

直接使用这个麻瓜库的识别准确率在0.64左右,但是经过我上面的干扰线处理,准确率可以提升至0.85左右。

这篇文章写的比较早了,后来又出现了一个库ddddocr,可以支持字符验证码、滑动验证码甚至一些点选验证码的识别,感兴趣的同学可以自行尝试。

我的gtihub博客地址:https://forchenxi.github.io/

另外,如果对投资理财感兴趣的同学,可以关注我的微信公众号:运气与实力。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值