使用PaddleOCR从图像和扫描文档中提取文本,支持100多种语言。
Smart OCR STell.是一项面向实际任务的技能,主要用于Overview. 此技能可以使用 PaddleOCR - 支持100+语言的 OCR 引擎从图像和扫描文档中提取智能文本;extract text from pho。
从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;
若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
本技能基于领先的 OCR 引擎 PaddleOCR,支持 100 多种语言,可实现图像与扫描文档的智能化文本提取。支持从照片、截图、扫描版 PDF 及手写文档中高精度提取文本。
示例提示语:
from paddleocr import PaddleOCR
# 初始化 OCR 引擎
ocr = PaddleOCR(use_angle_cls=True, lang='en')
# 对图像执行 OCR
result = ocr.ocr('image.png', cls=True)
# 结果结构:[[box, (text, confidence)], ...]
for line in result[0]:
box = line[0] # [[x1,y1], [x2,y2], [x3,y3], [x4,y4]]
text = line[1][0] # 提取的文本
conf = line[1][1] # 置信度分数
print(f"{text} ({conf:.2f})")
# 常用语言代码
languages = {
'en': 'English',
'ch': 'Chinese (Simplified)',
'cht': 'Chinese (Traditional)',
'japan': 'Japanese',
'korean': 'Korean',
'french': 'French',
'german': 'German',
'spanish': 'Spanish',
'russian': 'Russian',
'arabic': 'Arabic',
'hindi': 'Hindi',
'vi': 'Vietnamese',
'th': 'Thai',
# ... 支持 100+ 种语言
}
# 指定特定语言
ocr = PaddleOCR(lang='ch') # 中文
ocr = PaddleOCR(lang='japan') # 日文
ocr = PaddleOCR(lang='multilingual') # 自动检测多语言
from paddleocr import PaddleOCR
ocr = PaddleOCR(
# 检测设置
det_model_dir=None, # 自定义检测模型路径
det_limit_side_len=960, # 检测时图像最大边长
det_db_thresh=0.3, # 二值化阈值
det_db_box_thresh=0.5, # 检测框得分阈值
# 识别设置
rec_model_dir=None, # 自定义识别模型路径
rec_char_dict_path=None, # 自定义字符字典路径
# 角度分类
use_angle_cls=True, # 启用角度分类
cls_model_dir=None, # 自定义分类模型路径
# 语言
lang='en', # 语言代码
# 性能
use_gpu=True, # 若可用则启用 GPU
gpu_mem=500, # GPU 显存限制(MB)
enable_mkldnn=True, # CPU 优化(Intel MKL-DNN)
# 输出
show_log=False, # 屏蔽日志输出
)
# 单张图像
result = ocr.ocr('image.png')
# 多张图像
images = ['img1.png', 'img2.png', 'img3.png']
for img in images:
result = ocr.ocr(img)
process_result(result)
from pdf2image import convert_from_path
def ocr_pdf(pdf_path):
"""OCR 扫描版 PDF 文档。"""
# 将 PDF 页面转换为图像
images = convert_from_path(pdf_path)
all_text = []
for i, img in enumerate(images):
# 保存临时图像
temp_path = f'temp_page_{i}.png'
img.save(temp_path)
# 对图像执行 OCR
result = ocr.ocr(temp_path)
# 提取文本
page_text = '\n'.join([line[1][0] for line in result[0]])
all_text.append(f"--- Page {i+1} ---\n{page_text}")
os.remove(temp_path)
return '\n\n'.join(all_text)
import requests
from io import BytesIO
# 从 URL 加载
response = requests.get('https://example.com/image.png')
result = ocr.ocr(BytesIO(response.content))
# 从字节流加载
with open('image.png', 'rb') as f:
img_bytes = f.read()
result = ocr.ocr(BytesIO(img_bytes))
def process_ocr_result(result):
"""将 OCR 结果处理为结构化数据。"""
lines = []
for line in result[0]:
box = line[0]
text = line[1][0]
confidence = line[1][1]
# 计算包围框坐标
x_coords = [p[0] for p in box]
y_coords = [p[1] for p in box]
lines.append({
'text': text,
'confidence': confidence,
'bbox': {
'left': min(x_coords),
'top': min(y_coords),
'right': max(x_coords),
'bottom': max(y_coords),
},
'raw_box': box
})
return lines
# 按位置排序(从上到下、从左到右)
def sort_by_position(lines):
return sorted(lines, key=lambda x: (x['bbox']['top'], x['bbox']['left']))
def reconstruct_layout(result, line_threshold=10):
"""根据 OCR 结果重建文本版式。"""
lines = process_ocr_result(result)
lines = sort_by_position(lines)
# 按逻辑行分组
text_lines = []
current_line = []
current_y = None
for line in lines:
y = line['bbox']['top']
if current_y is None or abs(y - current_y) < line_threshold:
current_line.append(line)
current_y = y
else:
# 新起一行
text_lines.append(' '.join([l['text'] for l in current_line]))
current_line = [line]
current_y = y
# 添加最后一行
if current_line:
text_lines.append(' '.join([l['text'] for l in current_line]))
return '\n'.join(text_lines)
from PIL import Image, ImageEnhance, ImageFilter
def preprocess_image(image_path):
"""对图像进行预处理以提升 OCR 效果。"""
img = Image.open(image_path)
# 转为灰度图
img = img.convert('L')
# 增强对比度
enhancer = ImageEnhance.Contrast(img)
img = enhancer.enhance(2.0)
# 锐化
img = img.filter(ImageFilter.SHARPEN)
# 保存预处理后的图像
preprocessed_path = 'preprocessed.png'
img.save(preprocessed_path)
return preprocessed_path
from tqdm import tqdm
from concurrent.futures import ThreadPoolExecutor
def batch_ocr(image_paths, max_workers=4):
"""并行处理多张图像的 OCR。"""
results = {}
def process_single(img_path):
result = ocr.ocr(img_path)
return img_path, result
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = [executor.submit(process_single, p) for p in image_paths]
for future in tqdm(futures, desc="Processing OCR"):
path, result = future.result()
results[path] = result
return results
from paddleocr import PaddleOCR
import re
def read_business_card(image_path):
"""从名片中提取联系人信息。"""
ocr = PaddleOCR(use_angle_cls=True, lang='en')
result = ocr.ocr(image_path)
# 提取所有文本
all_text = []
for line in result[0]:
all_text.append(line[1][0])
full_text = '\n'.join(all_text)
# 解析联系人信息
contact = {
'name': None,
'email': None,
'phone': None,
'company': None,
'title': None,
'raw_text': full_text
}
# 邮箱匹配
email_match = re.search(r'[\w.-]+@[\w.-]+\.\w+', full_text)
if email_match:
contact['email'] = email_match.group()
# 电话号码匹配
phone_match = re.search(r'[+\d][\d\s\-()]{8,}', full_text)
if phone_match:
contact['phone'] = phone_match.group().strip()
# 姓名通常为字号最大或位于最上方的文本
if all_text:
contact['name'] = all_text[0]
return contact
card_info = read_business_card('business_card.jpg')
print(f"Name: {card_info['name']}")
print(f"Email: {card_info['email']}")
print(f"Phone: {card_info['phone']}")
from paddleocr import PaddleOCR
import re
def scan_receipt(image_path):
"""从收据中提取商品明细与总金额。"""
ocr = PaddleOCR(use_angle_cls=True, lang='en')
result = ocr.ocr(image_path)
lines = []
for line in result[0]:
text = line[1][0]
y_pos = line[0][0][1]
lines.append({'text': text, 'y': y_pos})
# 按垂直位置排序
lines.sort(key=lambda x: x['y'])
receipt = {
'items': [],
'subtotal': None,
'tax': None,
'total': None
}
for line in lines:
text = line['text']
# 查找总金额
if 'total' in text.lower():
amount = re.search(r'\$?([\d,]+\.?\d*)', text)
if amount:
if 'sub' in text.lower():
receipt['subtotal'] = float(amount.group(1).replace(',', ''))
else:
receipt['total'] = float(amount.group(1).replace(',', ''))
# 查找税额
elif 'tax' in text.lower():
amount = re.search(r'\$?([\d,]+\.?\d*)', text)
if amount:
receipt['tax'] = float(amount.group(1).replace(',', ''))
# 查找商品项(含价格的行)
else:
item_match = re.search(r'(.+?)\s+\$?([\d,]+\.?\d+)$', text)
if item_match:
receipt['items'].append({
'name': item_match.group(1).strip(),
'price': float(item_match.group(2).replace(',', ''))
})
return receipt
receipt_data = scan_receipt('receipt.jpg')
print(f"Items: {len(receipt_data['items'])}")
print(f"Total: ${receipt_data['total']}")
from paddleocr import PaddleOCR
def ocr_multilingual(image_path, languages=['en', 'ch']):
"""OCR 多语言混合文档。"""
all_results = {}
for lang in languages:
ocr = PaddleOCR(use_angle_cls=True, lang=lang)
result = ocr.ocr(image_path)
texts = []
for line in result[0]:
texts.append({
'text': line[1][0],
'confidence': line[1][1]
})
all_results[lang] = texts
# 合并结果,保留每段文本的最高置信度
merged = {}
for lang, texts in all_results.items():
for item in texts:
text = item['text']
conf = item['confidence']
if text not in merged or merged[text]['confidence'] < conf:
merged[text] = {'confidence': conf, 'language': lang}
return merged
result = ocr_multilingual('bilingual_document.png')
for text, info in result.items():
print(f"[{info['language']}] {text} ({info['confidence']:.2f})")
# CPU 版本 pip install paddlepaddle paddleocr # GPU 版本(CUDA 11.x) pip install paddlepaddle-gpu paddleocr # 额外依赖 pip install pdf2image Pillow
相关专题
热门下载
相关下载
精品课程
共6课时 | 54.7万人学习
共89课时 | 134.1万人学习
共49课时 | 82.5万人学习
最新文章