Maison  >  Article  >  développement back-end  >  Comment Python reconnaît le code de vérification

Comment Python reconnaît le code de vérification

anonymity
anonymityoriginal
2019-06-17 16:09:415510parcourir

Lorsque le robot d'exploration Python explore le code de vérification de certains sites Web, vous pouvez rencontrer le problème de reconnaissance du code de vérification. La plupart des codes de vérification actuels sont divisés en quatre catégories : 1. Calculer le code de vérification 2. Code de vérification du curseur 3. Image de reconnaissance. code de vérification 4, code de vérification vocale

Comment Python reconnaît le code de vérification

L'objectif principal ici est d'identifier le code de vérification. Ce qui est reconnu est un simple code de vérification si vous souhaitez effectuer le taux de reconnaissance. plus haut, la reconnaissance sera plus précise. Il faut beaucoup d'efforts pour former votre propre bibliothèque de polices.

La reconnaissance des codes de vérification implique généralement ces étapes :

1. Traitement des niveaux de gris

2. Binarisation

3. >

4. Réduction du bruit

5. Coupe de caractères ou correction d'inclinaison

6. Bibliothèque de polices de formation

7. Les étapes de ces 6 étapes sont basiques. Vous pouvez choisir si 4 ou 5 sont nécessaires en fonction de la situation réelle. Cela ne coupe pas nécessairement le code de vérification. Le taux de reconnaissance augmentera beaucoup et parfois il diminuera

.

Plusieurs bibliothèques python principales utilisées : Pillow (bibliothèque de traitement d'image python), OpenCV (bibliothèque de traitement d'image avancée), pytesseract (bibliothèque de reconnaissance)


Le cas suivant Utilisation :

1. Placez l'image du code de vérification à reconnaître dans le dossier img au même niveau que le script, et créez le dossier out_img

2. python3 filename

3. . Les images à différentes étapes telles que la binarisation et la réduction du bruit seront stockées dans le dossier out_img, et le résultat final de la reconnaissance sera imprimé à l'écran

Code de reconnaissance complet du code QR :

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):
  &#39;&#39;&#39;
  干扰线降噪
  &#39;&#39;&#39;
  filename =  &#39;./out_img/&#39; + img_name.split(&#39;.&#39;)[0] + &#39;-interferenceline.jpg&#39;
  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 =  &#39;./out_img/&#39; + img_name.split(&#39;.&#39;)[0] + &#39;-interferencePoint.jpg&#39;
    # 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):
  &#39;&#39;&#39;
  自适应阀值二值化
  &#39;&#39;&#39;
  filename =   &#39;./out_img/&#39; + img_name.split(&#39;.&#39;)[0] + &#39;-binary.jpg&#39;
  img_name = filedir + &#39;/&#39; + img_name
  print(&#39;.....&#39; + 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):
  &#39;&#39;&#39;
  手动二值化
  &#39;&#39;&#39;
  img = Image.open(img)
  img = img.convert(&#39;L&#39;)
  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):
  &#39;&#39;&#39;用队列和集合记录遍历过的像素坐标代替单纯递归以解决cfs访问过深问题
  &#39;&#39;&#39;
  # print(&#39;**********&#39;)
  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):
  &#39;&#39;&#39;搜索区块起点
  &#39;&#39;&#39;
  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):
  &#39;&#39;&#39;切割字符位置
  &#39;&#39;&#39;
  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 =  &#39;./out_img/&#39; + img.split(&#39;.&#39;)[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 + &#39;-cutting-&#39; + str(i) + &#39;.jpg&#39;,cropped)
def main():
  filedir = &#39;./easy_img&#39;
  for file in os.listdir(filedir):
    if fnmatch(file, &#39;*.jpeg&#39;):
      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(&#39;./out_img&#39;):
        str_img = &#39;&#39;
        if fnmatch(file, &#39;%s-cutting-*.jpg&#39; % img_name.split(&#39;.&#39;)[0]):
          cutting_img_num += 1
      for i in range(cutting_img_num):
        try:
          file = &#39;./out_img/%s-cutting-%s.jpg&#39; % (img_name.split(&#39;.&#39;)[0], i)
          # 识别验证码
          str_img = str_img + image_to_string(Image.open(file),lang = &#39;eng&#39;, config=&#39;-psm 10&#39;) #单个字符是10,一行文本是7
        except Exception as err:
          pass
      print(&#39;切图:%s&#39; % cutting_img_num)
      print(&#39;识别为:%s&#39; % str_img)
if __name__ == &#39;__main__&#39;:
  main()

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn