一次简单粗暴的验证码识别经历

  最近爬取一个网站时,遇到了验证码的情况。验证码形式是计算题,10以内的数字(可能有少量十以上),加减乘计算。

  开始懒得搞,第一批需要的数据量并不大,想着直接平台打码。

  原因是以前登录新浪微博的时候也是直接打码的,比较熟练,也简便。但打码成本比较高,后续需求量大,所以最好自己能识别。

  看了几篇识别验证码的文章,基本处理流程如下:

    1.去掉颜色;灰度处理,二值化等

    2.去掉干扰,降噪;噪点,线等的处理

    3.切割字符,单独识别

    4.训练字体

    5.自动识别

  我需要识别的验证码形式如下:

  

  经过反复试验,定了以下几个步骤:

    1.去除干扰,将图片中的干扰点线等删除

    2.识别图片,使用pytesseract识别图片

    3.计算结果,使用识别出来的字符数字计算结果

  以上是代码的流程,实际操作中还需要训练字体,这里留在最后说明。

  使用这张图片为例,简要介绍一下流程:

  以上几个步骤的基本操作思想:

    1.去噪。通常的思想是根据像素点的相邻关系等去除,我在识别的过程中发现,这里的图片像素值比较单一,

                  噪点的颜色比数字的颜色要浅。简单打印一下RGB值,可以发现除了(255,255,255)表示的白色以外,大致颜色值有以下几种:

      (140,140,140)

      (112,112,112)

         (117,117,117)

                   于是,我通过判断像素点的RGB值,把以上几种点用白色替换(即去掉该点),示例图片转换后得到图像如下

         

                   可以看到这个结果,基本上就可以拿去识别了。这也是为什么我称这次验证码识别为简单粗暴。

    2.识别。识别使用的是tesseract直接识别,没什么好讲的,贴几个链接自己看。

             关于数据训练,也是直接照着教程做的,连文件名都没改,所幸过程中并未出错。

from pytesseract import image_to_string
im = Image.open("1_no_noise.png")
str_img = image_to_string(im, lang='eng', config='-psm 6')
print('识别为:%s' % str_img)

                   使用原装英文库识别结果如下:

识别为:7x3:?

              使用训练过的库识别:

from pytesseract import image_to_string
im = Image.open("1_no_noise.png")
str_img = image_to_string(im, lang='fontyp', config='-psm 70')
print('识别为:%s' % str_img)

# 识别为:7x3=?

                  ※在使用过程中,尝试修改config的配置,可以帮助更准确地识别。

    3.计算结果。计算结果就是拿识别出来的字符串,简单拆分,分析操作符,做出对应计算,因为识别的时候没有切图,所以直接切割字符串。

               在切割字符串之后的数字转换做了简单的矫正。

  整体代码如下:

# encoding=utf-8
__author__ = 'Masako'

from PIL import Image
from io import BytesIO
from pytesseract import image_to_string

NOISE_RGB_LIST = [117, 140, 112]    # 噪点像素值列表
OPERATE_LIST = ['+', 'x', 'X',  '-', '']

# 去除噪点 def del_point(img): pix = img.load() width = img.size[0] height = img.size[1] for x in range(width): for y in range(height): r, g, b = pix[x, y] # print(r, g, b) if r in NOISE_RGB_LIST: pix[x, y] = 255, 255, 255 return img # 数字识别 def data_ident(data_str): num = None if data_str == 'q': num = 9 elif data_str == 'z' or data_str == 'Z': num = 2 elif data_str == 'G': num = 6 else: try: num = int(data_str) except Exception as e: print("can't identify:" + data_str) return num # 计算结果 def deal_img_str(img_str): # str_list = img_str.split(' ') # print(str_list) calculate_result = None try: data_str = img_str[:img_str.rindex('=')] except Exception as e: print(img_str) return # print(data_str) for operate in OPERATE_LIST: if operate in data_str: # 判断操作符 data_list = data_str.split(operate) if len(data_list) == 2: # 正确分割时的处理 data_left = data_ident(data_list[0]) data_right = data_ident(data_list[1]) if data_left and data_right: if operate == '+': calculate_result = data_left + data_right elif operate == 'x' or operate == 'X': calculate_result = data_left * data_right else: calculate_result = data_left - data_right if calculate_result != None: break return calculate_result def img_to_captcha_code(img_content): image_data = BytesIO(img_content) im = Image.open(image_data) im = del_point(im) str_img = image_to_string(im, lang='fontyp', config='-psm 70') result = deal_img_str(str_img) return result if __name__ == "__main__": im = Image.open("a.jpg") im = del_point(im) im.save('a_no.jpg') str_img = image_to_string(im, lang='fontyp', config='-psm 70') print('识别为:%s' % str_img)

  参考文章链接:

    https://www.cnblogs.com/qqandfqr/p/7866650.html

    http://www.cnblogs.com/cnlian/p/5765871.html

原文地址:https://www.cnblogs.com/masako/p/9319109.html