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

推荐订阅源

博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
月光博客
月光博客
AI
AI
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
CXSECURITY Database RSS Feed - CXSecurity.com
WordPress大学
WordPress大学
GbyAI
GbyAI
L
Lohrmann on Cybersecurity
O
OpenAI News
Schneier on Security
Schneier on Security
P
Palo Alto Networks Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Troy Hunt's Blog
V2EX - 技术
V2EX - 技术
W
WeLiveSecurity
L
LINUX DO - 最新话题
人人都是产品经理
人人都是产品经理
S
Security Affairs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
A
Arctic Wolf
Recorded Future
Recorded Future
Microsoft Security Blog
Microsoft Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
GRAHAM CLULEY
N
Netflix TechBlog - Medium
TaoSecurity Blog
TaoSecurity Blog
C
Check Point Blog
Scott Helme
Scott Helme
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Apple Machine Learning Research
Apple Machine Learning Research
PCI Perspectives
PCI Perspectives
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Vercel News
Vercel News
The Hacker News
The Hacker News
Y
Y Combinator Blog
Latest news
Latest news
SecWiki News
SecWiki News
Hugging Face - Blog
Hugging Face - Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
Webroot Blog
Webroot Blog
Google DeepMind News
Google DeepMind News
Recent Commits to openclaw:main
Recent Commits to openclaw:main
C
Cisco Blogs
博客园_首页
H
Hackread – Cybersecurity News, Data Breaches, AI and More
宝玉的分享
宝玉的分享
L
LINUX DO - 热门话题

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'))