【验证码识别】 图像处理+tesserocr识别

1.tesseract和tesserocr安装

tesseract
tesserocr

注意版本

  • 这里需要注意两者的版本相容问题

首先装 tesseract

安装

  • 一键安装过后可在箭头处添加语言包,但是由于语言包增加多了的话对之后的验证码识别会有影响,(比如本来只有 62个字符 26+26+10,但是增加了语言包会识别出其他的字符),所以我只下了中文包。然后一键安装完毕。

其次装 tesserocr

  • 前面提到要使两者版本相容,版本不一样会装不起。
  • 建议将下好的tesserocr放在用户目录 C:UsersXXX 下,因为terminal打开的时候默认是用户目录,所以比较方便安装,除非你想手动进入其他目录。
  • 进入终端输入如下:pip install tesserocr-2.4.0-cp37-cp37m-win_am.whl(后面的这句根据版本要改你懂的=w=)。
  • 下面进行tesserocr识别测试:把这张图 image.png 保存在用户目录下在这里插入图片描述
    在这里我直接打开终端的python输入验证了…
import tesserocr
from PIL import Image
img = Image.open('image.png')
print(tesserocr.image_to_text(img))

在这里插入图片描述

  • 划重点:因为当时并不知道tesserocr的包已经在电脑里面,pycharm里面没有找到,pycharm也不能下tesserocr。但其实pip install的不在pycharm目录里面,而在电脑里面一个文件夹 例如:D:Anaconda3Libsite-packages里面,所以之后pycharm调用的话必须要复制粘贴进pycharm的包目录: .venvLibsite-packages

2.验证码批量爬取

|- Img_download.py
|- image_from_web 储存爬取后图片

import os  # 创建文件夹需要用
import requests  # http客户端
from PIL import Image
IMAGE_URL = "http://my.cnki.net/elibregister/CheckCode.aspx" # 备用图片网址

def img_download(n, address):
	"""
	获取验证码
	n 获取图片数量
	address 图片保存地址
	"""
    os.makedirs('./' + str(address) + '/', exist_ok=True)
    for a in range(n):
        print('No' + str(a) + 'image is downloading')
        r = requests.get(IMAGE_URL)
        with open('./' + str(address) + '/img' + str(a) + '.png', 'wb') as f:
            f.write(r.content)
        Image.open('./' + str(address) + '/img' + str(a) + '.png').save('./' + str(address) + '/img' + str(a) + '.png')

img_download(1000, 'image_from_web')

3.验证码图像处理并识别

图像处理文件

|- img_manage.py
|- image_done 储存处理后图片

import os  # 创建文件夹需要用
# import pytesseract
# pytesseract.pytesseract.tesseract_cmd = r"D:	esseract_4.0	esseract.exe"
from PIL import Image
import matplotlib.pyplot as plt
import tesserocr

def sum_9_region_new(img, x, y):
    """
    9邻域框,以当前点为中心的田字框,黑点个数
    :param x:
    :param y:
    :return:
    """
    # todo 判断图片的长宽度下限
    cur_pixel = img.getpixel((x, y))  # 当前像素点的值
    width = img.width
    height = img.height

    if cur_pixel == 1:  # 如果当前点为白色区域,则不统计邻域值
        return 0

    if y == 0:  # 第一行
        if x == 0:  # 左上顶点,4邻域
            # 中心点旁边3个点
            sum = cur_pixel 
                  + img.getpixel((x, y + 1)) 
                  + img.getpixel((x + 1, y)) 
                  + img.getpixel((x + 1, y + 1))
            return 4 - sum
        elif x == width - 1:  # 右上顶点
            sum = cur_pixel 
                  + img.getpixel((x, y + 1)) 
                  + img.getpixel((x - 1, y)) 
                  + img.getpixel((x - 1, y + 1))

            return 4 - sum
        else:  # 最上非顶点,6邻域
            sum = img.getpixel((x - 1, y)) 
                  + img.getpixel((x - 1, y + 1)) 
                  + cur_pixel 
                  + img.getpixel((x, y + 1)) 
                  + img.getpixel((x + 1, y)) 
                  + img.getpixel((x + 1, y + 1))
            return 6 - sum
    elif y == height - 1:  # 最下面一行
        if x == 0:  # 左下顶点
            # 中心点旁边3个点
            sum = cur_pixel 
                  + img.getpixel((x + 1, y)) 
                  + img.getpixel((x + 1, y - 1)) 
                  + img.getpixel((x, y - 1))
            return 4 - sum
        elif x == width - 1:  # 右下顶点
            sum = cur_pixel 
                  + img.getpixel((x, y - 1)) 
                  + img.getpixel((x - 1, y)) 
                  + img.getpixel((x - 1, y - 1))

            return 4 - sum
        else:  # 最下非顶点,6邻域
            sum = cur_pixel 
                  + img.getpixel((x - 1, y)) 
                  + img.getpixel((x + 1, y)) 
                  + img.getpixel((x, y - 1)) 
                  + img.getpixel((x - 1, y - 1)) 
                  + img.getpixel((x + 1, y - 1))
            return 6 - sum
    else:  # y不在边界
        if x == 0:  # 左边非顶点
            sum = img.getpixel((x, y - 1)) 
                  + cur_pixel 
                  + img.getpixel((x, y + 1)) 
                  + img.getpixel((x + 1, y - 1)) 
                  + img.getpixel((x + 1, y)) 
                  + img.getpixel((x + 1, y + 1))

            return 6 - sum
        elif x == width - 1:  # 右边非顶点
            # print('%s,%s' % (x, y))
            sum = img.getpixel((x, y - 1)) 
                  + cur_pixel 
                  + img.getpixel((x, y + 1)) 
                  + img.getpixel((x - 1, y - 1)) 
                  + img.getpixel((x - 1, y)) 
                  + img.getpixel((x - 1, y + 1))

            return 6 - sum
        else:  # 具备9领域条件的
            sum = img.getpixel((x - 1, y - 1)) 
                  + img.getpixel((x - 1, y)) 
                  + img.getpixel((x - 1, y + 1)) 
                  + img.getpixel((x, y - 1)) 
                  + cur_pixel 
                  + img.getpixel((x, y + 1)) 
                  + img.getpixel((x + 1, y - 1)) 
                  + img.getpixel((x + 1, y)) 
                  + img.getpixel((x + 1, y + 1))
            return 9 - sum


def collect_noise_point(img, n):
    '''收集所有的噪点'''
    noise_point_list = []
    for x in range(img.width):
        for y in range(img.height):
            res_9 = sum_9_region_new(img, x, y)
            if (0 < res_9 < n) and img.getpixel((x, y)) == 0:  # 找到孤立点
                pos = (x, y)
                noise_point_list.append(pos)
    return noise_point_list


def remove_noise_pixel(img, noise_point_list):
    '''根据噪点的位置信息,消除二值图片的黑点噪声'''
    for item in noise_point_list:
        img.putpixel((item[0], item[1]), 1)


def get_bin_table(threshold):
    '''获取灰度转二值的映射table,0表示黑色,1表示白色'''
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)
    return table


file = open('./result.txt', 'w')
file.write('No.' + '    ResultList' + '    TF' + '  Chance')


def remake(guess_img, much_num, n, i):
	"""
	guess_img:传入图片文件
	much_num: 阈值,控制二值化程度,自行调整(不能超过256)
	n:九宫格法去除像素点周围点的数量(推荐6和7)
	"""
    imgry = guess_img.convert('L')
    table = get_bin_table(much_num)
    binary = imgry.point(table, '1')
    noise_point_list = collect_noise_point(binary, n)
    remove_noise_pixel(binary, noise_point_list)
    binary.save('./image_done/img' + str(i) + '.png')


def guessImg(image, i):
	"""
	image:传入处理识别图片
	i:第i个图片
	"""
	#窗口中查看处理之前图片
    plt.ion()
    plt.imshow(image)
    plt.pause(0.1)
    plt.close()

    image = image.resize((64, 25)) #根据图片长宽改正,实验表明以原图大小处理后识别概率比较高
    remake(image, 145, 6, i)
    #remake(image, 190, 7, i)
    Image.open('./image_done/img' + str(i) + '.png').save('./image_done/img' + str(i) + '.png')
    image = Image.open('./image_done/img' + str(i) + '.png')
    image = image.resize((64, 25)) #根据图片长宽改正,实验表明以原图大小识别概率比较高
    
	#窗口中查看处理之后图片
    plt.ion()
    plt.imshow(image)
    plt.pause(0.1)
    plt.close()

    print("result is ", tesserocr.image_to_text(image))

主函数文件

|- main_demo.py
|- result.txt 储存识别概率

import os  
import requests  
import Img_manage


global true_Num # 正确次数
true_Num = 0
global n
n = int(input('输入测试图片次数:    '))

file = open('./result.txt', 'w')
file.write('No.' + '    TF' + '    Chance')


def guess():
    global true_Num
    for i in range(n):
        Image.open('./image_from_web/img' + str(i) + '.png').save('./image_from_web/img' + str(i) + '.png')
        guess_img = Image.open('./image_from_web/img' + str(i) + '.png')

        guess_img = Img_manage.guessImg(guess_img, i)

        TF = int(input("输入字符正确个数    "))
        if TF == 0:
            true_Num = true_Num + 0
        elif TF == 1:
            true_Num = true_Num + 1
        elif TF == 2:
            true_Num = true_Num + 2
        elif TF == 3:
            true_Num = true_Num + 3
        elif TF == 4:
            true_Num = true_Num + 4

        file.write('
' + str(i) + '    ' +
                   str(TF) + '    ' + str(true_Num / (4 * (i + 1))))


guess()

4.识别结果&概率分析

第一种验证码:http://my.cnki.net/elibregister/CheckCode.aspx

识别精度:单字符识别精度65%左右

    image = image.resize((64, 25))#图片大小
    remake(image, 145, 6, i)#二值化程度:145   去噪程度:6/9

处理前在这里插入图片描述
处理后在这里插入图片描述
识别结果 识别结果

No.    TF(对的个数)    Chance
0    3    0.75
1    2    0.625
2    2    0.5833333333333334
3    4    0.6875
4    4    0.75
5    4    0.7916666666666666
6    3    0.7857142857142857
7    2    0.75
8    4    0.7777777777777778
9    1    0.725
10    2    0.7045454545454546
11    3    0.7083333333333334
12    4    0.7307692307692307
13    3    0.7321428571428571
14    2    0.7166666666666667
15    1    0.6875
16    2    0.6764705882352942
17    4    0.6944444444444444
18    1    0.6710526315789473
19    1    0.65
20    4    0.6666666666666666
21    1    0.6477272727272727
22    1    0.6304347826086957
23    3    0.6354166666666666
24    2    0.63
25    3    0.6346153846153846
26    2    0.6296296296296297
27    4    0.6428571428571429
28    4    0.6551724137931034
29    1    0.6416666666666667
30    3    0.6451612903225806
31    1    0.6328125
32    2    0.6287878787878788
33    3    0.6323529411764706
34    4    0.6428571428571429
35    3    0.6458333333333334
36    2    0.6418918918918919
37    4    0.6513157894736842
38    2    0.6474358974358975
39    2    0.64375
40    4    0.6524390243902439
41    3    0.6547619047619048
42    4    0.6627906976744186
43    2    0.6590909090909091
44    1    0.65
45    2    0.6467391304347826
46    4    0.6542553191489362
47    4    0.6614583333333334
48    4    0.6683673469387755
49    2    0.665

第二种验证码:某教务处登陆网站验证码

    image = image.resize((72, 32))#图片大小
    remake(image, 195, 7, i)#二值化程度:195   去噪程度:7/9

识别精度:单字符识别精度45%左右

处理前在这里插入图片描述
处理后在这里插入图片描述

No.    TF    Chance
0    4    1.0
1    1    0.625
2    1    0.5
3    0    0.375
4    4    0.5
5    3    0.5416666666666666
6    0    0.4642857142857143
7    2    0.46875
8    2    0.4722222222222222
9    0    0.425
10    3    0.45454545454545453
11    1    0.4375
12    2    0.4423076923076923
13    1    0.42857142857142855
14    2    0.43333333333333335
15    1    0.421875
16    0    0.39705882352941174
17    0    0.375
18    2    0.3815789473684211
19    0    0.3625
20    3    0.38095238095238093
21    3    0.3977272727272727
22    4    0.42391304347826086
23    4    0.4479166666666667
24    2    0.45
25    2    0.4519230769230769
26    2    0.4537037037037037
27    3    0.4642857142857143
28    2    0.46551724137931033
29    3    0.475
30    3    0.4838709677419355
31    0    0.46875
32    3    0.4772727272727273
33    2    0.47794117647058826
34    0    0.4642857142857143
35    3    0.4722222222222222
36    2    0.47297297297297297
37    0    0.4605263157894737
38    3    0.46794871794871795
39    2    0.46875
40    3    0.47560975609756095
41    3    0.48214285714285715
42    2    0.48255813953488375
43    0    0.4715909090909091
44    3    0.4777777777777778
45    0    0.4673913043478261
46    4    0.4787234042553192
47    2    0.4791666666666667
48    3    0.4846938775510204
49    3    0.49
    image = image.resize((72, 32))#图片大小
    remake(image, 145, 6, i)#二值化程度:145   去噪程度:6/9

识别精度:单字符识别精度50%左右

处理前在这里插入图片描述
处理后在这里插入图片描述
识别结果 在这里插入图片描述
处理前在这里插入图片描述
处理后在这里插入图片描述
识别结果 在这里插入图片描述
处理前在这里插入图片描述
处理后在这里插入图片描述
识别结果 在这里插入图片描述
处理前在这里插入图片描述
处理后在这里插入图片描述
识别结果在这里插入图片描述
处理前在这里插入图片描述
处理后在这里插入图片描述
识别结果在这里插入图片描述

No.    TF    Chance
0    3    0.75
1    2    0.625
2    3    0.6666666666666666
3    0    0.5
4    3    0.55
5    3    0.5833333333333334
6    0    0.5
7    2    0.5
8    1    0.4722222222222222
9    0    0.425
10    2    0.4318181818181818
11    2    0.4375
12    2    0.4423076923076923
13    0    0.4107142857142857
14    3    0.43333333333333335
15    4    0.46875
16    2    0.47058823529411764
17    1    0.4583333333333333
18    2    0.4605263157894737
19    0    0.4375
20    3    0.4523809523809524
21    2    0.45454545454545453
22    2    0.45652173913043476
23    2    0.4583333333333333
24    3    0.47
25    1    0.46153846153846156
26    2    0.46296296296296297
27    3    0.4732142857142857
28    2    0.47413793103448276
29    4    0.49166666666666664
30    3    0.5
31    2    0.5
32    2    0.5
33    2    0.5
34    2    0.5
35    2    0.5
36    3    0.5067567567567568
37    0    0.4934210526315789
38    3    0.5
39    4    0.5125
40    4    0.524390243902439
41    4    0.5357142857142857
42    1    0.5290697674418605
43    0    0.5170454545454546
44    2    0.5166666666666667
45    0    0.5054347826086957
46    3    0.5106382978723404
47    1    0.5052083333333334
48    3    0.5102040816326531
49    2    0.51
原文地址:https://www.cnblogs.com/SiriusZHT/p/14310805.html