当前位置: 首页 > news >正文

探索OCR的第二个方案:EasyOCR

一、EasyOCR简介

1.1 框架定位

EasyOCR是由Jaided AI团队开发的开源OCR引擎,基于PyTorch深度学习框架构建,支持80+种语言的文本识别,包含简体中文(ch_sim)、繁体中文(ch_tra)、英语(en)等主流语言。其核心优势在于:

  • 多场景适应:支持自然场景文本、文档密集文本、手写体等多种类型
  • 端到端流程:集成CRAFT检测模型+CRNN识别模型的完整解决方案
  • 硬件加速:支持GPU加速推理(CUDA/MPS)与CPU模式
  • 灵活扩展:允许用户自定义识别网络和模型存储路径

最新版本(v1.7.2)在中文识别场景下,对复杂排版和低分辨率图像的识别准确率提升至92.3%(ICDAR2019测试集)

1.2 技术架构演进

采用模块化设计,核心组件包括:
在这里插入图片描述

关键改进:

  • 2023版引入动态分辨率适配,优化小文本检测
  • 2024版新增光栅字符分割算法,提升粘连字符处理能力
  • 2025版支持ONNX导出(期待狗头)

二、环境部署与基础使用

2.1 安装指南

推荐使用Python 3.8+环境:

# 安装PyTorch(根据CUDA版本选择)
pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu121

# 安装EasyOCR核心包
pip install easyocr

# 验证安装
python -c "import easyocr; print(easyocr.__version__)"

2.2 中文识别基础示例

import easyocr
import numpy as np
import cv2


# 读取测试图像
img = cv2.imread('pic002.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 执行OCR识别
results = reader.readtext(img,
                          detail=1,
                          paragraph=True,
                          contrast_ths=0.3)
print(f"识别结果:{results}")

for item in results:
    if len(item) < 3:  # 处理置信度缺失情况
        bbox, text = item[:2]
        prob = 0.0
    else:
        bbox, text, prob = item

    # 可视化(绘制多边形框)
    pts = np.array(bbox, np.int32).reshape((-1, 1, 2))
    cv2.polylines(img, [pts], True, (0, 255, 0), 2)
    print(f"检测到文本: {text} | 置信度: {prob:.2f}")
    
cv2.imshow('result', img)
cv2.waitKey(0)

在这里插入图片描述

参数说明:
detail=1 返回完整元数据(坐标、置信度)
paragraph=True 自动合并段落文本
contrast_ths=0.3 增强低对比度文本处理
结果:
detail=0:识别结果:[‘五。中文识别’, ‘高级应用场景 5.1 结构化数据提取’]
detail=1:识别结果:[[[[0, 6], [110, 6], [110, 32], [0, 32]], ‘五。中文识别’], [[[9, 54], [176, 54], [176, 102], [9, 102]], ‘高级应用场景 5.1 结构化数据提取’]]
小结:几乎全对,就这已经比Tesseract强很多,但是速度较慢。
模型下载
运行中如果没有模型是会自动下载的,如果网络不行,可以单独下载后,放入easyOCR的目录下。
官网下载
点我下载
Windows放置在:C:\Users\YOURUSERNAME.EasyOCR\model

三、高级功能与参数调优

3.1 分阶段处理流程

3.1.1 独立文本检测(detect方法)

仅执行文本检测(不进行识别),返回文本区域的坐标信息。
它的作用:

  • 需要获取文本位置但无需识别内容
  • 多阶段处理中的前置步骤(如区域过滤)
  • 训练数据标注工具开发
# 仅执行文本检测
horizontal_boxes, free_boxes = reader.detect(img,
                                            text_threshold=0.7,
                                            low_text=0.4,
                                            canvas_size=2560)

输出格式:

horizontal_boxes: [x_min, x_max, y_min, y_max]
free_boxes: [[x1,y1],[x2,y2],…] 多边形坐标
detect方法参数

参数类型默认值作用描述
imgndarray必填输入图像(RGB格式)
text_thresholdfloat0.7文本区域置信度阈值(0-1)
low_textfloat0.4低置信度文本保留阈值
canvas_sizeint2560图像缩放的最大边长(像素单位)

格式说明

  1. 表格采用标准的Markdown表格语法
  2. 表头与内容通过分隔线|---|明确区分
  3. 各列保持左对齐,确保可读性
  4. 默认值列突出显示关键数值参数
  5. 作用描述列使用中文说明并保持简洁

特殊符号说明

  • ndarray:表示NumPy数组类型
  • float/int:标注参数数值类型
  • “必填”:强调该参数无默认值,必须显式传递

3.2 性能优化策略

参数推荐值作用
batch_size8-16增大批处理规模加速推理
workers4多线程数据加载
model_storageSSD路径加速模型加载
optimal_num_chars根据场景优先处理指定字符数的区域
典型GPU加速配置:
reader = easyocr.Reader(
    ['ch_sim'],
    gpu=True,
    model_storage_directory='/nvme_ssd/models',
    download_enabled=False
)

3.3 车牌识别

在这里插入图片描述

1:车牌识别最简单方法
最简单做法

import cv2
import easyocr


reader = easyocr.Reader(
    ['ch_sim', 'en'],
    gpu=False,
    download_enabled=False
)
img = cv2.imread('pic005.jpg')
text_results = reader.readtext(
    img,
    allowlist='京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使警港澳0123456789ABCDEFGHJKLMNPQRSTUVWXYZ',
)
print("识别结果:", text_results)

2:车牌识别较复杂方案
为了让其称得上方案,增加了图片预处理、基于颜色特征检测候选区域、识别后处理清洗以及简单校验逻辑。
注意:基于颜色特征检测候选区域尚不完善,权当抛砖引玉。

import cv2
import numpy as np
import easyocr
import re


class CPUPlateRecognizer:
    def __init__(self, model_dir="./models"):
        self.reader = easyocr.Reader(
            ['ch_sim', 'en'],
            gpu=False,
            download_enabled=False,
            model_storage_directory=model_dir,
            user_network_directory=model_dir
        )

        # 车牌颜色阈值(HSV空间)
        self.color_ranges = {
            'green': ([35, 50, 50], [90, 255, 255]),  # 新能源绿牌
            'blue': ([100, 80, 50], [130, 255, 200])  # 传统蓝牌
        }

    def detect_color_region(self, img):
        """基于颜色特征检测候选区域"""
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        candidates = []

        # 遍历颜色阈值
        for color, (lower, upper) in self.color_ranges.items():
            mask = cv2.inRange(hsv, np.array(lower), np.array(upper))

            # 形态学处理
            kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
            mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2)

            # 查找轮廓
            contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

            for cnt in contours:
                x, y, w, h = cv2.boundingRect(cnt)
                aspect_ratio = w / h

                # 根据颜色筛选长宽比
                if color == 'green' and 3.2 < aspect_ratio < 4.5:
                    # 对高做个补偿,需要动态修改
                    candidates.append((x, y - 50, x + w, y + h, color))
                elif color == 'blue' and 3.5 < aspect_ratio < 4.8:
                    candidates.append((x, y, x + w, y + h, color))

        return candidates

    def preprocess_plate(self, plate_img):
        """车牌图像预处理"""
        # 灰度化 + CLAHE增强
        gray = cv2.cvtColor(plate_img, cv2.COLOR_BGR2GRAY)
        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
        return clahe.apply(gray)

    def recognize_plate(self, img_path):
        """车牌识别主流程"""
        img = cv2.imread(img_path)
        if img is None:
            raise ValueError(f"图片加载失败: {img_path}")

        # 检测候选区域
        candidates = self.detect_color_region(img)
        results = []

        for (x1, y1, x2, y2, color) in candidates:
            # 裁剪车牌区域
            plate_roi = img[y1:y2, x1:x2]

            # 预处理
            processed = self.preprocess_plate(plate_roi)
            cv2.imshow('processed', processed)
            cv2.waitKey(0)
            # OCR识别
            text_results = self.reader.readtext(
                processed,
                decoder='beamsearch',
                beamWidth=5,
                batch_size=4,
                contrast_ths=0.5,
                text_threshold=0.7
            )
            print(text_results)
            # 合并识别结果
            plate_text = ' '.join([res[1] for res in text_results])
            clean_text = self.post_process(plate_text, color)

            if self.validate_plate(clean_text, color):
                results.append({
                    'location': (x1, y1, x2, y2),
                    'color': color,
                    'text': clean_text
                })

                # 可视化标注
                cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
                cv2.putText(img, clean_text, (x1, y1 - 10),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)

        cv2.imwrite('result.jpg', img)
        return results


    def post_process(self, text, color):
        """后处理清洗"""
        # 保留有效字符
        cleaned = re.sub(r'[^A-Z0-9\u4e00-\u9fa5]', '', text.upper())

        # 根据车牌类型调整长度
        if color == 'green' and len(cleaned) > 8:
            return cleaned[:8]
        elif color == 'blue' and len(cleaned) > 7:
            return cleaned[:7]
        return cleaned


    def validate_plate(self, text, color):
        """简单校验逻辑"""
        patterns = {
            'green': r'^[\u4e00-\u9fa5][A-Z][A-Z0-9]{6}$',  # 例:粤A123456
            'blue': r'^[\u4e00-\u9fa5][A-Z][A-Z0-9]{5}$'  # 例:京A12345
        }
        return re.match(patterns.get(color, ''), text) is not None


if __name__ == "__main__":
    recognizer = CPUPlateRecognizer(model_dir="./models")

    # 执行识别
    result = recognizer.recognize_plate("pic005.jpg")
    print("识别结果:", result)

文章转载自:
http://breastsummer.sxnf.com.cn
http://bharat.sxnf.com.cn
http://aiee.sxnf.com.cn
http://chainsaw.sxnf.com.cn
http://apochromat.sxnf.com.cn
http://absenteeism.sxnf.com.cn
http://alarming.sxnf.com.cn
http://borderism.sxnf.com.cn
http://afterbirth.sxnf.com.cn
http://baddeleyite.sxnf.com.cn
http://callop.sxnf.com.cn
http://boilover.sxnf.com.cn
http://bomblike.sxnf.com.cn
http://addenda.sxnf.com.cn
http://cannibalise.sxnf.com.cn
http://assheaded.sxnf.com.cn
http://caaba.sxnf.com.cn
http://chattily.sxnf.com.cn
http://anthropophilic.sxnf.com.cn
http://admass.sxnf.com.cn
http://antiadministration.sxnf.com.cn
http://cadi.sxnf.com.cn
http://bulwark.sxnf.com.cn
http://bechamel.sxnf.com.cn
http://chameleon.sxnf.com.cn
http://admission.sxnf.com.cn
http://apparatus.sxnf.com.cn
http://boswell.sxnf.com.cn
http://acceptant.sxnf.com.cn
http://allies.sxnf.com.cn
http://www.dtcms.com/a/100287.html

相关文章:

  • 小智机器人关键函数解析,Application::MainLoop() 用于持续监听事件组中的事件,并根据不同的事件触发相应的操作
  • Android在KSP中简单使用Room
  • Vue.js的多个组件过渡:实现组件的动态切换
  • 互联网的组成
  • C语言信号量使用案例
  • 每日小积累day1
  • TDengine tar.gz和docker两种方式安装和卸载
  • 【蓝桥杯速成】| 16.完全背包组合|排序
  • Rollup系列之安装和入门
  • MQTT之重复消息(6、在项目中遇到的问题)
  • Pandas **Series**
  • 传统策略梯度方法的弊端与PPO的改进:稳定性与样本效率的提升
  • 【干货】前端实现文件保存总结
  • rce操作
  • 唤起“堆”的回忆
  • 基于自定义注解+反射+AOP+Redis的通用开关设计:在投行交易与风控系统的落地实践
  • golang 的reflect包的常用方法
  • 低速通信之王:LIN总线工作原理入门
  • 创作领域“<em >彩</em><em>票</em><em>导</em><em>师</em><em>带</em><em>玩</em><em>群
  • SvelteKit 最新中文文档教程(15)—— 链接选项
  • C语言的sprintf函数使用
  • Rust 为什么不适合开发 GUI
  • Java后端开发: 如何安装搭建Java开发环境《安装JDK》和 检测JDK版本
  • 【Tauri2】008——简单说说配置文件
  • QtWebApp使用
  • .Net framework 3.5怎样离线安装
  • Redis-09.Redis常用命令-通用命令
  • Python练习
  • QXmpp入门
  • 前端学习日记--JavaScript