zoukankan      html  css  js  c++  java
  • 【验证码识别】 图像处理+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
    
  • 相关阅读:
    全国各地DNS(电信,移动,联通,教育网)
    全国各地电信DNS服务器地址
    免费公共 DNS 大全
    免费公共DNS服务器 全球DNS服务器 国内DNS服务器
    AT指令发送短信
    OpenWrt 定期检测进程是否存在并重启
    OpenWrt 计划任务使用方法
    openwrt-mt7688 修改默认的WIFI SSID
    在MT7628实现wan、wwan与4G动态切换
    Unix常用命令之修改密码
  • 原文地址:https://www.cnblogs.com/SiriusZHT/p/14310805.html
Copyright © 2011-2022 走看看