Python怎么验证码识别

Python爬虫在获取网站验证码时,常会遇到验证码识别难题。当前主流的验证码主要分为以下四类:

1、计算验证码

2、滑块验证码

3、识图验证码

4、语音验证码

本文重点探讨了简单验证码的识别技术。要提高识别准确率,关键在于投入大量精力构建专属字体库并进行充分训练。

识别验证码通常是这几个步骤:

1、灰度处理

2、二值化

3、去除边框(如果有的话)

4、降噪

5、切割字符或者倾斜度矫正

6、训练字体库

7、识别

以下是优化后的内容:

这7个步骤中,前三个是基础操作。步骤4和5可根据实际情况选择是否执行,因为切割验证码并不一定会显著提高识别率,有时反而会降低准确度。

本文不包含字体库训练相关内容,如有需要请自行查阅资料。同时,基础语法知识也不在讲解范围内。

主要使用的Python库包括:

  • Pillow(Python图像处理库)
  • OpenCV(高级图像处理库)
  • pytesseract(识别库)

灰度处理&二值化
  灰度处理,就是把彩色的验证码图片转为灰色的图片。

二值化,是将图片处理为只有黑白两色的图片,利于后面的图像处理和识别

在OpenCV中有现成的方法可以进行灰度处理和二值化,处理后的效果:

在这里插入图片描述

代码:

 1 # 自适应阀值二值化
 2 def _get_dynamic_binary_image(filedir, img_name):
 3   filename =   './out_img/' + img_name.split('.')[0] + '-binary.jpg'
 4   img_name = filedir + '/' + img_name
 5   print('.....' + img_name)
 6   im = cv2.imread(img_name)
 7   im = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) #灰值化
 8   # 二值化
 9   th1 = cv2.adaptiveThreshold(im, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1)
10   cv2.imwrite(filename,th1)
11   return th1

去除边框
  如果验证码有边框,那我们就需要去除边框,去除边框就是遍历像素点,找到四个边框上的所有点,把他们都改为白色,我这里边框是两个像素宽

注意:在用OpenCV时,图片的矩阵点是反的,就是长和宽是颠倒的

代码:

# 去除边框
def clear_border(img,img_name):
  filename = './out_img/' + img_name.split('.')[0] + '-clearBorder.jpg'
  h, w = img.shape[:2]
  for y in range(0, w):
    for x in range(0, h):
      if y < 2 or y > w - 2:
        img[x, y] = 255
      if x < 2 or x > h -2:
        img[x, y] = 255

  cv2.imwrite(filename,img)
  return img

效果:
在这里插入图片描述

降噪
  降噪是验证码处理中比较重要的一个步骤,我这里使用了点降噪和线降噪

在这里插入图片描述

线降噪的思路就是检测这个点相邻的四个点(图中标出的绿色点),判断这四个点中是白点的个数,如果有两个以上的白色像素点,那么就认为这个点是白色的,从而去除整个干扰线,但是这种方法是有限度的,如果干扰线特别粗就没有办法去除,只能去除细的干扰线

代码:

 1 # 干扰线降噪
 2 def interference_line(img, img_name):
 3   filename =  './out_img/' + img_name.split('.')[0] + '-interferenceline.jpg'
 4   h, w = img.shape[:2]
 5   # !!!opencv矩阵点是反的
 6   # img[1,2] 1:图片的高度,2:图片的宽度
 7   for y in range(1, w - 1):
 8     for x in range(1, h - 1):
 9       count = 0
10       if img[x, y - 1] > 245:
11         count = count + 1
12       if img[x, y + 1] > 245:
13         count = count + 1
14       if img[x - 1, y] > 245:
15         count = count + 1
16       if img[x + 1, y] > 245:
17         count = count + 1
18       if count > 2:
19         img[x, y] = 255
20   cv2.imwrite(filename,img)
21   return img

点降噪的思路和线降噪的差不多,只是会针对不同的位置检测的点不一样,注释写的很清楚了

代码:

# 点降噪
def interference_point(img,img_name, x = 0, y = 0):
    """
    9邻域框,以当前点为中心的田字框,黑点个数
    :param x:
    :param y:
    :return:
    """
    filename =  './out_img/' + img_name.split('.')[0] + '-interferencePoint.jpg'
    # todo 判断图片的长宽度下限
    cur_pixel = img[x,y]# 当前像素点的值
    height,width = img.shape[:2]

    for y in range(0, width - 1):
      for x in range(0, height - 1):
        if y == 0:  # 第一行
            if x == 0:  # 左上顶点,4邻域
                # 中心点旁边3个点
                sum = int(cur_pixel) \
                      + int(img[x, y + 1]) \
                      + int(img[x + 1, y]) \
                      + int(img[x + 1, y + 1])
                if sum <= 2 * 245:
                  img[x, y] = 0
            elif x == height - 1:  # 右上顶点
                sum = int(cur_pixel) \
                      + int(img[x, y + 1]) \
                      + int(img[x - 1, y]) \
                      + int(img[x - 1, y + 1])
                if sum <= 2 * 245:
                  img[x, y] = 0
            else:  # 最上非顶点,6邻域
                sum = int(img[x - 1, y]) \
                      + int(img[x - 1, y + 1]) \
                      + int(cur_pixel) \
                      + int(img[x, y + 1]) \
                      + int(img[x + 1, y]) \
                      + int(img[x + 1, y + 1])
                if sum <= 3 * 245:
                  img[x, y] = 0
        elif y == width - 1:  # 最下面一行
            if x == 0:  # 左下顶点
                # 中心点旁边3个点
                sum = int(cur_pixel) \
                      + int(img[x + 1, y]) \
                      + int(img[x + 1, y - 1]) \
                      + int(img[x, y - 1])
                if sum <= 2 * 245:
                  img[x, y] = 0
            elif x == height - 1:  # 右下顶点
                sum = int(cur_pixel) \
                      + int(img[x, y - 1]) \
                      + int(img[x - 1, y]) \
                      + int(img[x - 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大白砌墙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值