基于Easyocr的文字识别
Published in:2024-12-15 |
Words: 2.4k | Reading time: 11min | reading:

基于Easyocr的文字识别

EasyOCR 是一个开源的 OCR (光学字符识别) 工具,能够快速并高效地从图像中提取文本。与其他OCR工具如 Tesseract 相比,EasyOCR 具有更强的多语言支持,包括对中文、日语、阿拉伯语等复杂文字的支持,并且它的安装和使用非常简便。

主要功能

EasyOCR 是一个 Python 包,用于执行光学字符识别 (OCR)。它旨在易于使用,并支持多种语言的文本识别。其主要特点包括:

  • 简单易用

  • 多语言支持

  • GPU 加速支持

  • 开源

安装 EasyOCR:

可以使用 pip 安装:

1
pip install easyocr

使用 GPU 加速,安装 PyTorch 的 GPU 版本

1
2
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

导入 EasyOCR:

1
2

import easyocr

创建 OCR 读取器 (Reader):

1
2
reader = easyocr.Reader(['ch_sim', 'en'])  # ch_sim 表示简体中文,en 表示英文

使用 GPU加速,需要指定 gpu=True:

1
reader = easyocr.Reader(['ch_sim', 'en'], gpu=True)

demo

1
2
3
# readtext() 方法会返回一个包含识别结果的列表,列表中的每个元素都是一个包含文本框位置坐标和识别文本的元组。

result = reader.readtext('image.jpg') # image.jpg 是你要识别的图像文件路径
  • 处理识别结果:
    1
    2
    3
    4
    5

    for (bbox, text, prob) in result:
    (tl, tr, br, bl) = bbox # 文本框的左上角、右上角、右下角、左下角的坐标
    print(f"文本: {text}, 置信度: {prob}")
    # 在这里可以根据坐标将文本框绘制到图像上,或者进行其他处理

基础功能测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

import easyocr
import cv2

# 创建 OCR Reader, 使用简体中文和英文模型,并启用 GPU 加速
reader = easyocr.Reader(['ch_sim', 'en'], gpu=True)

# 读取图像
image_path = 'test.png' # 替换为你的图像文件路径
image = cv2.imread(image_path)

# 执行 OCR
result = reader.readtext(image)

# 遍历结果并打印
for (bbox, text, prob) in result:
(tl, tr, br, bl) = bbox
tl = (int(tl[0]), int(tl[1]))
tr = (int(tr[0]), int(tr[1]))
br = (int(br[0]), int(br[0]))
bl = (int(bl[0]), int(bl[1]))
print(f"文本: {text}, 置信度: {prob}")
cv2.rectangle(image, tl, br, (0, 255, 0), 2)
cv2.putText(image, text, tl, cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)


# 显示带有文本框的图像
cv2.imshow('OCR Result', image)
cv2.waitKey(0)
cv2.destroyAllWindows()


one more thing

一些其他用法:

  • 识别特定区域: 可以使用 detect() 方法预先检测文本区域,然后传递给 readtext() 方法。

  • 自定义模型: 可以使用自定义模型,并指定路径。

  • 批处理: 可以处理多张图像。

  • 文本方向: EasyOCR 会自动检测文本方向,但也可以手动指定。

使用场景:

  • 文档数字化: 将扫描的纸质文档转化为可编辑的文本。

  • 图像信息提取: 从图像中提取关键文本信息,例如车牌号、验证码等。

  • 自动化数据输入: 自动化从图像中提取文本并输入到系统。

  • 多语言应用: 支持多语言识别,方便国际化应用开发。

总结:

EasyOCR 是一个功能强大且易于使用的 OCR 库,可以帮助你在 Python 应用中快速实现文本识别功能。只需要几行代码,你就可以从图像中提取出文本。希望这个介绍和示例能帮助你快速上手 EasyOCR! 记得根据你的具体需求调整代码。

实际案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

import os
from decimal import Decimal
import numpy as np
import cv2
import easyocr
import json
import shutil
from tqdm import tqdm
from PIL import Image
from pypinyin import pinyin, Style

lan_code = ['ru', 'ind', 'tur', 'deu', 'ita', 'jpn', 'fra', 'tha', 'por', 'spa', 'vie', 'ara', 'kor', 'msa']
language_map = {
'俄语': 'ru',
'印尼': 'ind',
'土耳其': 'tur',
'德语': 'deu',
'意大利语': 'ita',
'日语': 'jpn',
'法语': 'fra',
'泰语': 'tha',
'葡萄牙': 'por',
'西班牙语': 'spa',
'越南语': 'vie',
'阿拉伯语': 'ara',
'韩语': 'kor',
'马来语': 'msa'
}

# 初始化 EasyOCR 阅读器
# reader = easyocr.Reader(['en', 'ch_sim', 'ru', 'ja', 'de', 'fr', 'es', 'it', 'pt', 'tr', 'ar'], gpu=True) # 支持多语言

reader = easyocr.Reader(['ru'], gpu=True)
def convert_to_pinyin(text):
"""
将中文字符转换为拼音。
"""
result = pinyin(text, style=Style.NORMAL)
return ''.join([item[0] for item in result])


def clean_path(path):
"""
将���径中的非法字符替换为拼音。
"""
illegal_chars = r'[\/:*?"<>|]'
path_parts = path.split(os.sep)
cleaned_parts = []

for part in path_parts:
part = convert_to_pinyin(part) # 转换为拼音
cleaned_parts.append(part)

return os.sep.join(cleaned_parts)


def check_language_code_in_directory(directory_path, lan_codes):
"""
检查指定路径中是否包含语言代码列表中的任何一个内容。
"""
found_codes = []

try:
for lan_code in lan_codes:
if lan_code in directory_path:
found_codes.append(lan_code)
return found_codes
except Exception as e:
print(f"发生错误: {e}")
return []


def numpy_encoder(obj):
"""
自定义 JSON 序列化函数。
"""
if isinstance(obj, np.ndarray):
return obj.tolist()
raise TypeError(f"Type {type(obj)} not serializable")


def extract_text_with_coords(image_path, folder, lan_code):
"""
从图像中提取文字及其坐标,并返回格式化的 JSON 数据。
"""
try:
lan_zh = check_language_code_in_directory(image_path, folder)
# if not lan_zh:
# raise ValueError(f"未在路径中找到任何语言代码:{image_path}")

language_codes = "ru"
img = Image.open(image_path)
img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)

if img is None:
return {"error": f"无法读取图像: {image_path}"}

# 使用 EasyOCR 提取文本和坐标
results = reader.readtext(image_path)

formatted_results = []
for result in results:
# result 格式: [bbox, text, confidence]
bbox, text, _ = result
if text.strip():
# 获取坐标,转换为浮动数
x_min, y_min = bbox[0]
x_max, y_max = bbox[2]

# 创建浮动数坐标数组,保留高精度
coords = np.array([
[x_min, y_min],
[x_max, y_min],
[x_max, y_max],
[x_min, y_max]
], dtype=np.float64) # 使用 float64 保证高精度

result_dict = {
"label": text,
"points": numpy_encoder(coords), # 保持高精度坐标
"language": lan_zh[0],
"textType": "Mix" if len(text) > 1 else "Single",
"textDirection": "Horizontal_0",
"assign": "Normal",
"group_id": None,
"shape_type": "polygon",
"flags": {}
}

# 将结果添加到列表
formatted_results.append(result_dict)

# 绘制矩形框时,使用整数坐标,不改变精度
cv2.rectangle(img, (int(x_min), int(y_min)), (int(x_max), int(y_max)), (0, 255, 0), 2)

# 拼音路径
output_image_path = os.path.splitext(image_path)[0] + "_with_boxes.jpg"
output_image_path = clean_path(output_image_path)

# 目标文件夹
output_folder = os.path.dirname(output_image_path)
if not os.path.exists(output_folder):
os.makedirs(output_folder)

# 保存带框图像
result = cv2.imwrite(output_image_path, img)
print(f"已保存带框图像: {output_image_path}, result: {result}")

# 保留原图到拼音化目录
original_image_path = clean_path(image_path)
original_output_folder = os.path.dirname(original_image_path)
if not os.path.exists(original_output_folder):
os.makedirs(original_output_folder)

shutil.copy(image_path, original_image_path) # 复制原图到拼音化目录
print(f"原图已复制到: {original_image_path}")

return formatted_results

except Exception as e:
return {"error": f"发生错误: {str(e)}"}


def save_json_result(image_path, result):
"""
将识别结果保存为 JSON 文件。
"""
try:
image_name = os.path.splitext(os.path.basename(image_path))[0]
json_path = os.path.join(os.path.dirname(image_path), f"{image_name}.json")
json_path = clean_path(json_path)

with open(json_path, 'w', encoding='utf-8') as json_file:
json.dump(result, json_file, ensure_ascii=False, indent=4)

print(f"结果已保存到: {json_path}")
except Exception as e:
print(f"保存 JSON 文件时发生错误: {str(e)}")


def get_all_images_in_directory(directory_path):
"""
递归读取指定目录及其子目录中的所有图像文件。
"""
image_files = []
for root, dirs, files in os.walk(directory_path):
for file in files:
if file.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp')):
image_files.append(os.path.join(root, file))
return image_files


def process_images_in_directory(directory_path, folders, lan_code):
"""
批量处理指定目录中的所有图像文件。
"""
image_paths = get_all_images_in_directory(directory_path)

for image_path in tqdm(image_paths, desc="Processing images"):
try:
print(f"正在处理图像: {image_path}")
# 获取文件夹名作为语言代码
folder_name = os.path.basename(os.path.dirname(image_path))
if folder_name in language_map:
lan_code = language_map[folder_name] # 根据文件夹名获取语言代码
else:
print(f"未找到对应的语言代码: {folder_name}")
continue # 如果没有找到对应的语言代码,跳过该图像

result = extract_text_with_coords(image_path, folders, lan_code)

if isinstance(result, dict) and "error" in result:
print(f"处理 {image_path} 时发生错误: {result['error']}")
elif isinstance(result, list) and result:
save_json_result(image_path, result)
else:
print(f"处理 {image_path} 时没有检测到有效文本。")
except Exception as e:
print(f"处理 {image_path} 时发生错误: {str(e)}")


def get_all_folders_in_directory(directory_path):
"""
获取目录下所有文件夹名。
"""
try:
items = os.listdir(directory_path)
folders = [item for item in items if os.path.isdir(os.path.join(directory_path, item))]
return folders
except Exception as e:
print(f"发生错误: {e}")
return []


def fix_non_ascii_path(path):
"""
修复路径中的非 ASCII 字符问题。
"""
return path.encode('utf-8').decode('utf-8')


# 示例:从指定目录批量处理图像
image_directory = r"C:\Users\DELL\Desktop\CZQ\俄语" # 替换为你的图片目录路径
image_directory = fix_non_ascii_path(image_directory)
folders = get_all_folders_in_directory(image_directory)
print("文件夹列表:", folders) # 打印文件夹列表,确保获取的文件夹正确

process_images_in_directory(image_directory, folders, lan_code)

上述代码批量处理指定目录及其子目录下的图像文件,使用 EasyOCR 提取图像中的文本及其坐标,并将结果保存为 JSON 文件。同时,它还会在原始图像上绘制文本框,并将带框的图像和原始图像复制到以拼音命名的路径下

使用pillow、easyocr、numpy、pypinyin、tqdm、多线程等技术

Prev:
CentOS 系统上安装 Docker
Next:
Appium Debug Bridge