惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Microsoft Azure Blog
Microsoft Azure Blog
大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
V
V2EX
PCI Perspectives
PCI Perspectives
Latest news
Latest news
博客园 - 三生石上(FineUI控件)
C
CERT Recently Published Vulnerability Notes
W
WeLiveSecurity
Last Week in AI
Last Week in AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Palo Alto Networks Blog
T
The Exploit Database - CXSecurity.com
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
WordPress大学
WordPress大学
V
Vulnerabilities – Threatpost
H
Heimdal Security Blog
Attack and Defense Labs
Attack and Defense Labs
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hacker News: Ask HN
Hacker News: Ask HN
博客园 - 叶小钗
V
Visual Studio Blog
Jina AI
Jina AI
P
Proofpoint News Feed
罗磊的独立博客
SecWiki News
SecWiki News
J
Java Code Geeks
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LINUX DO - 热门话题
Security Archives - TechRepublic
Security Archives - TechRepublic
The Hacker News
The Hacker News
Hugging Face - Blog
Hugging Face - Blog
N
News and Events Feed by Topic
NISL@THU
NISL@THU
T
Tailwind CSS Blog
T
Tenable Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Recent Announcements
Recent Announcements
H
Hacker News: Front Page
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Tor Project blog
宝玉的分享
宝玉的分享
Help Net Security
Help Net Security
S
Security Affairs
Microsoft Security Blog
Microsoft Security Blog
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
G
GRAHAM CLULEY

f2h2h1's blog

使用yii3实现一个微框架 claw养殖技术 计算机网络基础知识 定时任务 ACME的使用经验 magento2加上varnish缓存 开发Magento2的模块 在magento2中使用persisted-query socket编程 一些开发笔记 一段CSDN文章主要内容的油猴脚本 电子邮件的不完整总结 git的笔记 在Windows下配置PHP服务器 终端,控制台和外壳 PHP各种运行方式的不完整总结 把网页导出成PDF 和颜色相关的笔记 HTTP认证方式的不完整总结 SEO的经验 密码学入门简明指南 文件的上传和下载 用纯CSS3实现的滑动按钮 在VSCode里调试PHP Linux的GUI 关于字符编码的一些坑 nc的使用和原理 在Windows下安装Magento2 对JS原型链的理解 使用docker-compose部署magento2 浏览器和服务器通讯方式的不完整总结 观察网站性能 一些关于Linux的笔记 telnet的不完整总结 在Windows下安装pear MySQL的时间类型和时间相关的函数 Windows下通过PEB读取进程的环境变量 关于 在VSCode里使用Xdebug远程调试PHP 在Windows下搭建git服务 关于环境变量的不完整总结 使用shell实现的kv数据库 如何完成以xx管理系统为选题的毕业设计 数字号码资源 各种标记语言 使用PowerShell实现的http服务器 kind相关经验 DNSSEC简介 nginx+ffmpeg+websocket实现的直播例子 使用docker部署nuxt FirstData后台的设置 paypal,firtdata,支付宝的不完整接入指南 微信支付的不完整接入指南 用docker-compose部署lnmp环境 mongodb分片 练习
使用Tesseract识别字符验证码
2021-10-15 · via f2h2h1's blog

这篇文章最后更新的时间在六个月之前,文章所叙述的内容可能已经失效,请谨慎参考!

依赖

  • tesseract v5.0.0-alpha.20210811
  • python 3.9
  • pillow 8.3

依赖的安装

  • tesseract 和 python 直接在官网下载即可
  • pillow 的安装 pip install pillow

字符验证码识别的一般套路

  • 载入图片
  • 灰度
  • 二值化
  • 降噪
  • 分割字符
  • 归一化
  • 识别

使用 python 进行预处理

引入 pillow

from PIL import Image

载入图片

image = Image.open('CAPTCHA.png')

灰度

imgry = image.convert('L')

二值化

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

降噪

def sum_9_region_new(img, x, y):
    '''确定噪点 '''
    cur_pixel = img.getpixel((x, y)) # 当前像素点的值
    width = img.width
    height = img.height
  
    if cur_pixel == 1: # 如果当前点为白色区域,则不统计邻域值
        return 0
  
    # 因当前图片的四周都有黑点,所以周围的黑点可以去除
    if y < 3: # 本例中,前两行的黑点都可以去除
        return 1
    elif y > height - 3: # 最下面两行
        return 1
    else: # y不在边界
        if x < 3: # 前两列
            return 1
        elif x == width - 1: # 右边非顶点
            return 1
        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):
    '''收集所有的噪点'''
    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 < 3) 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)

noise_point_list = collect_noise_point(binary)
remove_noise_pixel(binary, noise_point_list)

分割字符 和 归一化 都是为了方便识别,大多数情况下 分割字符 和 归一化 都是难点, 这里就直接交给 tesseract 识别了。

使用 tesseract 识别

保存预处理的图片

image_path = 'pre.png'
binary.save(image_path)

调用 tesseract 命令识别

cmd = 'tesseract ' + image_path  + ' stdout -l osd --psm 7 digits'
res = os.popen(cmd)
print(res.buffer.read().decode('utf-8'))

命令参数解释

这是上文出现的 tesseract 命令

tesseract image_path stdout -l osd --psm 7 digits
  • image_path 图片路径

  • stdout 把结果输出到标准输出

  • -l osd 识别语言为 osd

  • --psm 7 识别模式为 psm 7

  • digits 识别数字和英文字母

  • osd = Orientation and script detection (方向 和 脚本 检测) 其实笔者并不理解,为什么 osd 会作为一种语言的选项

  • psm = Page segmentation modes (页面 分割 模式)

    • psm 有很多种,对于识别字符验证码,比较常用的是 6 7 10 13
    • 6 Assume a single uniform block of text. 6 假设一个统一的文本块。
    • 7 Treat the image as a single text line. 7 将图像视为单个文本行。
    • 10 Treat the image as a single character. 10 将图像视为单个字符。
    • 13 Raw line. Treat the image as a single text line. 13 原始行,将图像视为单个文本行。

可以通过这两个命令来查看命令行的帮助

tesseract --help
tesseract --help-extra

限定要识别的文字

  1. 找到 tesseract 的安装目录
  2. 找到 安装目录\tessdata\configs
  3. 在这里新建一个名为 digits_new 的文件,并写入以下内容
    tessedit_char_whitelist 0123456789abcdefghijklnmopqrstuvwsyz
    
  4. 表示只识别 0-9 a-z 这 36 个字符,可以参考这个目录 安装目录\tessdata\configs 下的其它文件的写法
    • 例如上文提及的命令里的 digits
  5. 在命令行里这样使用
    tesseract image_path stdout -l osd --psm 7 digits_new
    

限定要识别的文字 能有效提高识别的准确率。

字库训练

完整的 python 代码

from PIL import Image

image = Image.open('CAPTCHA.png')

imgry = image.convert('L')

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

def sum_9_region_new(img, x, y):
    '''确定噪点 '''
    cur_pixel = img.getpixel((x, y)) # 当前像素点的值
    width = img.width
    height = img.height
  
    if cur_pixel == 1: # 如果当前点为白色区域,则不统计邻域值
        return 0
  
    # 因当前图片的四周都有黑点,所以周围的黑点可以去除
    if y < 3: # 本例中,前两行的黑点都可以去除
        return 1
    elif y > height - 3: # 最下面两行
        return 1
    else: # y不在边界
        if x < 3: # 前两列
            return 1
        elif x == width - 1: # 右边非顶点
            return 1
        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):
    '''收集所有的噪点'''
    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 < 3) 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)

noise_point_list = collect_noise_point(binary)
remove_noise_pixel(binary, noise_point_list)

cmd = 'tesseract ' + image_path  + ' stdout -l osd --psm 7 digits'
res = os.popen(cmd)
print(res.buffer.read().decode('utf-8'))