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如何调用C/C++底层库与互相传值
Aug 10 Python
Python 字符串与二进制串的相互转换示例
Jul 23 Python
解决Django一个表单对应多个按钮的问题
Jul 18 Python
Python搭建代理IP池实现存储IP的方法
Oct 27 Python
pygame实现俄罗斯方块游戏(对战篇1)
Oct 29 Python
python中的itertools的使用详解
Jan 13 Python
Flask和pyecharts实现动态数据可视化
Feb 26 Python
Python matplotlib 绘制双Y轴曲线图的示例代码
Jun 12 Python
Python闭包及装饰器运行原理解析
Jun 17 Python
opencv 图像轮廓的实现示例
Jul 08 Python
python3从网络摄像机解析mjpeg http流的示例
Nov 13 Python
python 爬取英雄联盟皮肤并下载的示例
Dec 04 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
“不能执行已释放的Script代码”错误的原因及解决办法
2007/09/09 Javascript
js 目录列举函数
2008/11/06 Javascript
js自定义事件代码说明
2011/01/31 Javascript
精通Javascript系列之数值计算
2011/06/07 Javascript
轻松创建nodejs服务器(8):非阻塞是如何实现的
2014/12/18 NodeJs
理解js回收机制通俗易懂版
2016/02/29 Javascript
浅析JSONP技术原理及实现
2016/06/08 Javascript
js编写一个简单的产品放大效果代码
2016/06/27 Javascript
AngularJS ng-bind-template 指令详解
2016/07/30 Javascript
jQuery实现的图片轮播效果完整示例
2016/09/12 Javascript
Bootstrap Table使用心得总结
2016/11/29 Javascript
JS中this的指向以及call、apply的作用
2018/05/06 Javascript
react-native动态切换tab组件的方法
2018/07/07 Javascript
详解vuex commit保存数据技巧
2018/12/25 Javascript
简谈创建React Component的几种方式
2019/06/15 Javascript
微信小程序错误this.setData报错及解决过程
2019/09/18 Javascript
卸载vue2.0并升级vue_cli3.0的实例讲解
2020/02/16 Javascript
通过js实现压缩图片上传功能
2020/02/25 Javascript
小程序自定义圆形进度条
2020/11/17 Javascript
pygame 精灵的行走及二段跳的实现方法(必看篇)
2017/07/10 Python
Python初学者需要注意的事项小结(python2与python3)
2018/09/26 Python
Python操作json的方法实例分析
2018/12/06 Python
python调用其他文件函数或类的示例
2019/07/16 Python
如何基于python操作json文件获取内容
2019/12/24 Python
通过实例简单了解Python sys.argv[]使用方法
2020/08/04 Python
美国钻石商店:Zales
2016/11/20 全球购物
“型”走纽约上东区:Sam Edelman
2017/04/02 全球购物
Kusmi茶美国官网:优质散叶茶和茶包
2019/10/13 全球购物
薪酬专员岗位职责
2014/02/18 职场文书
员工生日会策划方案
2014/06/14 职场文书
国庆宣传标语
2014/06/30 职场文书
少先队中队工作总结
2015/08/14 职场文书
学校标语口号大全
2015/12/26 职场文书
导游词之无锡丝业博物馆
2019/11/12 职场文书
仅用几行Python代码就能复制她的U盘文件?
2021/06/26 Python
MySQL数据库必备之条件查询语句
2021/10/15 MySQL