Python实现验证码识别


Posted in Python onJune 15, 2020

大致介绍  

在python爬虫爬取某些网站的验证码的时候可能会遇到验证码识别的问题,现在的验证码大多分为四类:

1、计算验证码

 

      2、滑块验证码

3、识图验证码

4、语音验证码

这篇博客主要写的就是识图验证码,识别的是简单的验证码,要想让识别率更高,识别的更加准确就需要花很多的精力去训练自己的字体库。

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

1、灰度处理

2、二值化

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

4、降噪

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

6、训练字体库

7、识别

这6个步骤中前三个步骤是基本的,4或者5可根据实际情况选择是否需要,并不一定切割验证码,识别率就会上升很多有时候还会下降

这篇博客不涉及训练字体库的内容,请自行搜索。同样也不讲解基础的语法。

用到的几个主要的python库: Pillow(python图像处理库)、OpenCV(高级图像处理库)、pytesseract(识别库)

灰度处理&二值化

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

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

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

代码:

# 自适应阀值二值化
def _get_dynamic_binary_image(filedir, img_name):
 filename = './out_img/' + img_name.split('.')[0] + '-binary.jpg'
 img_name = filedir + '/' + img_name
 print('.....' + img_name)
 im = cv2.imread(img_name)
 im = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) #灰值化
 # 二值化
 th1 = cv2.adaptiveThreshold(im, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1)
 cv2.imwrite(filename,th1)
 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

降噪

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

Python实现验证码识别

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

代码:

# 干扰线降噪
def interference_line(img, img_name):
 filename = './out_img/' + img_name.split('.')[0] + '-interferenceline.jpg'
 h, w = img.shape[:2]
 # !!!opencv矩阵点是反的
 # img[1,2] 1:图片的高度,2:图片的宽度
 for y in range(1, w - 1):
 for x in range(1, h - 1):
 count = 0
 if img[x, y - 1] > 245:
 count = count + 1
 if img[x, y + 1] > 245:
 count = count + 1
 if img[x - 1, y] > 245:
 count = count + 1
 if img[x + 1, y] > 245:
 count = count + 1
 if count > 2:
 img[x, y] = 255
 cv2.imwrite(filename,img)
 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, y - 1])

  if sum <= 2 * 245:
   img[x, y] = 0
  else: # 最下非顶点,6邻域
  sum = int(cur_pixel) \
   + int(img[x - 1, y]) \
   + int(img[x + 1, y]) \
   + int(img[x, y - 1]) \
   + int(img[x - 1, y - 1]) \
   + int(img[x + 1, y - 1])
  if sum <= 3 * 245:
   img[x, y] = 0
 else: # y不在边界
  if x == 0: # 左边非顶点
  sum = int(img[x, y - 1]) \
   + int(cur_pixel) \
   + int(img[x, y + 1]) \
   + int(img[x + 1, y - 1]) \
   + int(img[x + 1, y]) \
   + int(img[x + 1, y + 1])

  if sum <= 3 * 245:
   img[x, y] = 0
  elif x == height - 1: # 右边非顶点
  sum = int(img[x, y - 1]) \
   + int(cur_pixel) \
   + int(img[x, y + 1]) \
   + int(img[x - 1, y - 1]) \
   + int(img[x - 1, y]) \
   + int(img[x - 1, y + 1])

  if sum <= 3 * 245:
   img[x, y] = 0
  else: # 具备9领域条件的
  sum = int(img[x - 1, y - 1]) \
   + int(img[x - 1, y]) \
   + int(img[x - 1, y + 1]) \
   + int(img[x, y - 1]) \
   + int(cur_pixel) \
   + int(img[x, y + 1]) \
   + int(img[x + 1, y - 1]) \
   + int(img[x + 1, y]) \
   + int(img[x + 1, y + 1])
  if sum <= 4 * 245:
   img[x, y] = 0
 cv2.imwrite(filename,img)
 return img

效果:

Python实现验证码识别

其实到了这一步,这些字符就可以识别了,没必要进行字符切割了,现在这三种类型的验证码识别率已经达到50%以上了

字符切割   

       字符切割通常用于验证码中有粘连的字符,粘连的字符不好识别,所以我们需要将粘连的字符切割为单个的字符,在进行识别

字符切割的思路就是找到一个黑色的点,然后在遍历与他相邻的黑色的点,直到遍历完所有的连接起来的黑色的点,找出这些点中的最高的点、最低的点、最右边的点、最左边的点,记录下这四个点,认为这是一个字符,然后在向后遍历点,直至找到黑色的点,继续以上的步骤。最后通过每个字符的四个点进行切割

图中红色的点就是代码执行完后,标识出的每个字符的四个点,然后就会根据这四个点进行切割(图中画的有些误差,懂就好)

但是也可以看到,m2是粘连的,代码认为他是一个字符,所以我们需要对每个字符的宽度进行检测,如果他的宽度过宽,我们就认为他是两个粘连在一起的字符,并将它在从中间切割

确定每个字符的四个点代码:

def cfs(im,x_fd,y_fd):
 '''用队列和集合记录遍历过的像素坐标代替单纯递归以解决cfs访问过深问题
 '''

 # print('**********')

 xaxis=[]
 yaxis=[]
 visited =set()
 q = Queue()
 q.put((x_fd, y_fd))
 visited.add((x_fd, y_fd))
 offsets=[(1, 0), (0, 1), (-1, 0), (0, -1)]#四邻域

 while not q.empty():
 x,y=q.get()

 for xoffset,yoffset in offsets:
  x_neighbor,y_neighbor = x+xoffset,y+yoffset

  if (x_neighbor,y_neighbor) in (visited):
  continue # 已经访问过了

  visited.add((x_neighbor, y_neighbor))

  try:
  if im[x_neighbor, y_neighbor] == 0:
   xaxis.append(x_neighbor)
   yaxis.append(y_neighbor)
   q.put((x_neighbor,y_neighbor))

  except IndexError:
  pass
 # print(xaxis)
 if (len(xaxis) == 0 | len(yaxis) == 0):
 xmax = x_fd + 1
 xmin = x_fd
 ymax = y_fd + 1
 ymin = y_fd

 else:
 xmax = max(xaxis)
 xmin = min(xaxis)
 ymax = max(yaxis)
 ymin = min(yaxis)
 #ymin,ymax=sort(yaxis)

 return ymax,ymin,xmax,xmin

def detectFgPix(im,xmax):
 '''搜索区块起点
 '''

 h,w = im.shape[:2]
 for y_fd in range(xmax+1,w):
 for x_fd in range(h):
  if im[x_fd,y_fd] == 0:
  return x_fd,y_fd

def CFS(im):
 '''切割字符位置
 '''

 zoneL=[]#各区块长度L列表
 zoneWB=[]#各区块的X轴[起始,终点]列表
 zoneHB=[]#各区块的Y轴[起始,终点]列表

 xmax=0#上一区块结束黑点横坐标,这里是初始化
 for i in range(10):

 try:
  x_fd,y_fd = detectFgPix(im,xmax)
  # print(y_fd,x_fd)
  xmax,xmin,ymax,ymin=cfs(im,x_fd,y_fd)
  L = xmax - xmin
  H = ymax - ymin
  zoneL.append(L)
  zoneWB.append([xmin,xmax])
  zoneHB.append([ymin,ymax])

 except TypeError:
  return zoneL,zoneWB,zoneHB

 return zoneL,zoneWB,zoneHB

分割粘连字符代码:

# 切割的位置
 im_position = CFS(im)

 maxL = max(im_position[0])
 minL = min(im_position[0])

 # 如果有粘连字符,如果一个字符的长度过长就认为是粘连字符,并从中间进行切割
 if(maxL > minL + minL * 0.7):
 maxL_index = im_position[0].index(maxL)
 minL_index = im_position[0].index(minL)
 # 设置字符的宽度
 im_position[0][maxL_index] = maxL // 2
 im_position[0].insert(maxL_index + 1, maxL // 2)
 # 设置字符X轴[起始,终点]位置
 im_position[1][maxL_index][1] = im_position[1][maxL_index][0] + maxL // 2
 im_position[1].insert(maxL_index + 1, [im_position[1][maxL_index][1] + 1, im_position[1][maxL_index][1] + 1 + maxL // 2])
 # 设置字符的Y轴[起始,终点]位置
 im_position[2].insert(maxL_index + 1, im_position[2][maxL_index])

 # 切割字符,要想切得好就得配置参数,通常 1 or 2 就可以
 cutting_img(im,im_position,img_name,1,1)

切割粘连字符代码:

def cutting_img(im,im_position,img,xoffset = 1,yoffset = 1):
 filename = './out_img/' + img.split('.')[0]
 # 识别出的字符个数
 im_number = len(im_position[1])
 # 切割字符
 for i in range(im_number):
 im_start_X = im_position[1][i][0] - xoffset
 im_end_X = im_position[1][i][1] + xoffset
 im_start_Y = im_position[2][i][0] - yoffset
 im_end_Y = im_position[2][i][1] + yoffset
 cropped = im[im_start_Y:im_end_Y, im_start_X:im_end_X]
 cv2.imwrite(filename + '-cutting-' + str(i) + '.jpg',cropped)

识别

识别用的是typesseract库,主要识别一行字符和单个字符时的参数设置,识别中英文的参数设置,代码很简单就一行,我这里大多是filter文件的操作

代码:

# 识别验证码
 cutting_img_num = 0
 for file in os.listdir('./out_img'):
 str_img = ''
 if fnmatch(file, '%s-cutting-*.jpg' % img_name.split('.')[0]):
  cutting_img_num += 1
 for i in range(cutting_img_num):
 try:
  file = './out_img/%s-cutting-%s.jpg' % (img_name.split('.')[0], i)
  # 识别字符
  str_img = str_img + image_to_string(Image.open(file),lang = 'eng', config='-psm 10') #单个字符是10,一行文本是7
 except Exception as err:
  pass
 print('切图:%s' % cutting_img_num)
 print('识别为:%s' % str_img)

最后这种粘连字符的识别率是在30%左右,而且这种只是处理两个字符粘连,如果有两个以上的字符粘连还不能识别,但是根据字符宽度判别的话也不难,有兴趣的可以试一下

无需切割字符识别的效果:

Python实现验证码识别

 Python实现验证码识别

需要切割字符的识别效果:

Python实现验证码识别

Python实现验证码识别

这种只是能够识别简单验证码,复杂的验证码还要靠大家了

参考资料:

1、https://3water.com/article/141621.htm

本来参考了挺多的资料,但是时间长了就找不到了,如果有人发现了,可以告诉我,我再添加

使用方法:

 1、将要识别的验证码图片放入与脚本同级的img文件夹中,创建out_img文件夹

 2、python3 filename

   3、二值化、降噪等各个阶段的图片将存储在out_img文件夹中,最终识别结果会打印到屏幕上

最后附上源码(带切割,不想要切割的就自己修改吧):

from PIL import Image
from pytesseract import *
from fnmatch import fnmatch
from queue import Queue
import matplotlib.pyplot as plt
import cv2
import time
import os





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 ==0 or y == w -1 or y == w - 2:
 if y < 4 or y > w -4:
 img[x, y] = 255
 # if x == 0 or x == h - 1 or x == h - 2:
 if x < 4 or x > h - 4:
 img[x, y] = 255

 cv2.imwrite(filename,img)
 return img


def interference_line(img, img_name):
 '''
 干扰线降噪
 '''

 filename = './out_img/' + img_name.split('.')[0] + '-interferenceline.jpg'
 h, w = img.shape[:2]
 # !!!opencv矩阵点是反的
 # img[1,2] 1:图片的高度,2:图片的宽度
 for y in range(1, w - 1):
 for x in range(1, h - 1):
 count = 0
 if img[x, y - 1] > 245:
 count = count + 1
 if img[x, y + 1] > 245:
 count = count + 1
 if img[x - 1, y] > 245:
 count = count + 1
 if img[x + 1, y] > 245:
 count = count + 1
 if count > 2:
 img[x, y] = 255
 cv2.imwrite(filename,img)
 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, y - 1])

  if sum <= 2 * 245:
   img[x, y] = 0
  else: # 最下非顶点,6邻域
  sum = int(cur_pixel) \
   + int(img[x - 1, y]) \
   + int(img[x + 1, y]) \
   + int(img[x, y - 1]) \
   + int(img[x - 1, y - 1]) \
   + int(img[x + 1, y - 1])
  if sum <= 3 * 245:
   img[x, y] = 0
 else: # y不在边界
  if x == 0: # 左边非顶点
  sum = int(img[x, y - 1]) \
   + int(cur_pixel) \
   + int(img[x, y + 1]) \
   + int(img[x + 1, y - 1]) \
   + int(img[x + 1, y]) \
   + int(img[x + 1, y + 1])

  if sum <= 3 * 245:
   img[x, y] = 0
  elif x == height - 1: # 右边非顶点
  sum = int(img[x, y - 1]) \
   + int(cur_pixel) \
   + int(img[x, y + 1]) \
   + int(img[x - 1, y - 1]) \
   + int(img[x - 1, y]) \
   + int(img[x - 1, y + 1])

  if sum <= 3 * 245:
   img[x, y] = 0
  else: # 具备9领域条件的
  sum = int(img[x - 1, y - 1]) \
   + int(img[x - 1, y]) \
   + int(img[x - 1, y + 1]) \
   + int(img[x, y - 1]) \
   + int(cur_pixel) \
   + int(img[x, y + 1]) \
   + int(img[x + 1, y - 1]) \
   + int(img[x + 1, y]) \
   + int(img[x + 1, y + 1])
  if sum <= 4 * 245:
   img[x, y] = 0
 cv2.imwrite(filename,img)
 return img

def _get_dynamic_binary_image(filedir, img_name):
 '''
 自适应阀值二值化
 '''

 filename = './out_img/' + img_name.split('.')[0] + '-binary.jpg'
 img_name = filedir + '/' + img_name
 print('.....' + img_name)
 im = cv2.imread(img_name)
 im = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)

 th1 = cv2.adaptiveThreshold(im, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1)
 cv2.imwrite(filename,th1)
 return th1

def _get_static_binary_image(img, threshold = 140):
 '''
 手动二值化
 '''

 img = Image.open(img)
 img = img.convert('L')
 pixdata = img.load()
 w, h = img.size
 for y in range(h):
 for x in range(w):
 if pixdata[x, y] < threshold:
 pixdata[x, y] = 0
 else:
 pixdata[x, y] = 255

 return img


def cfs(im,x_fd,y_fd):
 '''用队列和集合记录遍历过的像素坐标代替单纯递归以解决cfs访问过深问题
 '''

 # print('**********')

 xaxis=[]
 yaxis=[]
 visited =set()
 q = Queue()
 q.put((x_fd, y_fd))
 visited.add((x_fd, y_fd))
 offsets=[(1, 0), (0, 1), (-1, 0), (0, -1)]#四邻域

 while not q.empty():
 x,y=q.get()

 for xoffset,yoffset in offsets:
  x_neighbor,y_neighbor = x+xoffset,y+yoffset

  if (x_neighbor,y_neighbor) in (visited):
  continue # 已经访问过了

  visited.add((x_neighbor, y_neighbor))

  try:
  if im[x_neighbor, y_neighbor] == 0:
   xaxis.append(x_neighbor)
   yaxis.append(y_neighbor)
   q.put((x_neighbor,y_neighbor))

  except IndexError:
  pass
 # print(xaxis)
 if (len(xaxis) == 0 | len(yaxis) == 0):
 xmax = x_fd + 1
 xmin = x_fd
 ymax = y_fd + 1
 ymin = y_fd

 else:
 xmax = max(xaxis)
 xmin = min(xaxis)
 ymax = max(yaxis)
 ymin = min(yaxis)
 #ymin,ymax=sort(yaxis)

 return ymax,ymin,xmax,xmin

def detectFgPix(im,xmax):
 '''搜索区块起点
 '''

 h,w = im.shape[:2]
 for y_fd in range(xmax+1,w):
 for x_fd in range(h):
  if im[x_fd,y_fd] == 0:
  return x_fd,y_fd

def CFS(im):
 '''切割字符位置
 '''

 zoneL=[]#各区块长度L列表
 zoneWB=[]#各区块的X轴[起始,终点]列表
 zoneHB=[]#各区块的Y轴[起始,终点]列表

 xmax=0#上一区块结束黑点横坐标,这里是初始化
 for i in range(10):

 try:
  x_fd,y_fd = detectFgPix(im,xmax)
  # print(y_fd,x_fd)
  xmax,xmin,ymax,ymin=cfs(im,x_fd,y_fd)
  L = xmax - xmin
  H = ymax - ymin
  zoneL.append(L)
  zoneWB.append([xmin,xmax])
  zoneHB.append([ymin,ymax])

 except TypeError:
  return zoneL,zoneWB,zoneHB

 return zoneL,zoneWB,zoneHB


def cutting_img(im,im_position,img,xoffset = 1,yoffset = 1):
 filename = './out_img/' + img.split('.')[0]
 # 识别出的字符个数
 im_number = len(im_position[1])
 # 切割字符
 for i in range(im_number):
 im_start_X = im_position[1][i][0] - xoffset
 im_end_X = im_position[1][i][1] + xoffset
 im_start_Y = im_position[2][i][0] - yoffset
 im_end_Y = im_position[2][i][1] + yoffset
 cropped = im[im_start_Y:im_end_Y, im_start_X:im_end_X]
 cv2.imwrite(filename + '-cutting-' + str(i) + '.jpg',cropped)



def main():
 filedir = './easy_img'

 for file in os.listdir(filedir):
 if fnmatch(file, '*.jpeg'):
 img_name = file

 # 自适应阈值二值化
 im = _get_dynamic_binary_image(filedir, img_name)

 # 去除边框
 im = clear_border(im,img_name)

 # 对图片进行干扰线降噪
 im = interference_line(im,img_name)

 # 对图片进行点降噪
 im = interference_point(im,img_name)

 # 切割的位置
 im_position = CFS(im)

 maxL = max(im_position[0])
 minL = min(im_position[0])

 # 如果有粘连字符,如果一个字符的长度过长就认为是粘连字符,并从中间进行切割
 if(maxL > minL + minL * 0.7):
 maxL_index = im_position[0].index(maxL)
 minL_index = im_position[0].index(minL)
 # 设置字符的宽度
 im_position[0][maxL_index] = maxL // 2
 im_position[0].insert(maxL_index + 1, maxL // 2)
 # 设置字符X轴[起始,终点]位置
 im_position[1][maxL_index][1] = im_position[1][maxL_index][0] + maxL // 2
 im_position[1].insert(maxL_index + 1, [im_position[1][maxL_index][1] + 1, im_position[1][maxL_index][1] + 1 + maxL // 2])
 # 设置字符的Y轴[起始,终点]位置
 im_position[2].insert(maxL_index + 1, im_position[2][maxL_index])

 # 切割字符,要想切得好就得配置参数,通常 1 or 2 就可以
 cutting_img(im,im_position,img_name,1,1)

 # 识别验证码
 cutting_img_num = 0
 for file in os.listdir('./out_img'):
 str_img = ''
 if fnmatch(file, '%s-cutting-*.jpg' % img_name.split('.')[0]):
  cutting_img_num += 1
 for i in range(cutting_img_num):
 try:
  file = './out_img/%s-cutting-%s.jpg' % (img_name.split('.')[0], i)
  # 识别验证码
  str_img = str_img + image_to_string(Image.open(file),lang = 'eng', config='-psm 10') #单个字符是10,一行文本是7
 except Exception as err:
  pass
 print('切图:%s' % cutting_img_num)
 print('识别为:%s' % str_img)

if __name__ == '__main__':
 main()

以上就是Python实现验证码识别的详细内容,更多关于Python验证码识别的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
让 python 命令行也可以自动补全
Nov 30 Python
Python本地与全局命名空间用法实例
Jun 16 Python
使用httplib模块来制作Python下HTTP客户端的方法
Jun 19 Python
在Django的form中使用CSS进行设计的方法
Jul 18 Python
浅谈Python数据类型之间的转换
Jun 08 Python
Python判断某个用户对某个文件的权限
Oct 13 Python
Python构建网页爬虫原理分析
Dec 19 Python
纯python实现机器学习之kNN算法示例
Mar 01 Python
django用户登录和注销的实现方法
Jul 16 Python
使用python itchat包爬取微信好友头像形成矩形头像集的方法
Feb 21 Python
使用Python脚本zabbix自定义key监控oracle连接状态
Aug 28 Python
Python面向对象之多态原理与用法案例分析
Dec 30 Python
Python Tkinter图形工具使用方法及实例解析
Jun 15 #Python
使用Keras画神经网络准确性图教程
Jun 15 #Python
在tensorflow下利用plt画论文中loss,acc等曲线图实例
Jun 15 #Python
python中元组的用法整理
Jun 15 #Python
详解Python设计模式之策略模式
Jun 15 #Python
python能做哪方面的工作
Jun 15 #Python
python实现二分类和多分类的ROC曲线教程
Jun 15 #Python
You might like
全国FM电台频率大全 - 25 云南省
2020/03/11 无线电
开启CURL扩展,让服务器支持PHP curl函数(远程采集)
2011/03/19 PHP
PHP中empty和isset对于参数结构的判断及empty()和isset()的区别
2015/11/15 PHP
phalcon model在插入或更新时会自动验证非空字段的解决办法
2016/12/29 PHP
Laravel中获取路由参数Route Parameters的五种方法示例
2017/09/29 PHP
List the Codec Files on a Computer
2007/06/18 Javascript
原生js和jquery实现图片轮播淡入淡出效果
2015/04/23 Javascript
javascript运动效果实例总结(放大缩小、滑动淡入、滚动)
2016/01/08 Javascript
jQuery通过ajax请求php遍历json数组到table中的代码(推荐)
2016/06/12 Javascript
vuex实现简易计数器
2016/10/27 Javascript
关于JavaScript中高阶函数的魅力详解
2018/09/07 Javascript
Angular Material Icon使用详解
2018/11/07 Javascript
详解如何使用node.js的开发框架express创建一个web应用
2018/12/20 Javascript
vue-父子组件和ref实例详解
2019/11/10 Javascript
JS前端模块化原理与实现方法详解
2020/03/17 Javascript
Node.js中出现未捕获异常的处理方法
2020/06/29 Javascript
uniapp实现可以左右滑动导航栏
2020/10/21 Javascript
vue实现动态表格提交参数动态生成控件的操作
2020/11/09 Javascript
PyQt弹出式对话框的常用方法及标准按钮类型
2019/02/27 Python
python与字符编码问题
2019/05/24 Python
Python中的正则表达式与JSON数据交换格式
2019/07/03 Python
详解Python实现进度条的4种方式
2020/01/15 Python
解决jupyter notebook 出现In[*]的问题
2020/04/13 Python
Python几种常见算法汇总
2020/06/02 Python
HTML5语音识别标签写法附图
2013/11/18 HTML / CSS
详解html5 shiv.js和respond.min.js
2018/01/24 HTML / CSS
AmazeUI中模态框的实现
2020/08/19 HTML / CSS
AC Lens:购买隐形眼镜
2017/02/26 全球购物
英国顶级家庭折扣店:The Works
2017/09/06 全球购物
企划主管岗位职责
2013/12/12 职场文书
旅游管理专业个人求职信范文
2013/12/24 职场文书
小学生获奖感言范文
2014/02/02 职场文书
硕士研究生就业推荐信
2014/05/18 职场文书
2014年个人业务工作总结
2014/11/17 职场文书
乡镇干部学习心得体会
2016/01/23 职场文书
大学生暑期社会实践的个人总结!
2019/07/17 职场文书