批量处理图片:高效OCR识别方案与最佳实践
学习如何批量处理多张图片进行OCR识别,包含循环调用、并发请求、错误处理和性能优化等完整方案。
阅读时间 13 分钟
为什么需要批量处理?
在实际业务场景中,您可能需要一次性处理大量图片:
- 扫描归档的历史文档(几百到几千页)
- 批量识别发票、收据进行财务录入
- 处理用户上传的多张图片
- 定时任务自动处理新增文件
单张图片逐个手动处理效率太低,需要自动化的批量处理方案。
方案一:顺序循环调用
最简单的方式是使用循环依次处理每张图片。这种方式实现简单,适合图片数量不多或对速度要求不高的场景。
JavaScript/Node.js 示例
async function batchOCR(images) {
const results = [];
for (const image of images) {
const formData = new FormData();
formData.append('file', image);
try {
const response = await fetch('https://api.easyocr.org/ocr', {
method: 'POST',
body: formData
});
const result = await response.json();
results.push({
filename: image.name,
success: true,
data: result
});
} catch (error) {
results.push({
filename: image.name,
success: false,
error: error.message
});
}
// 添加延迟,避免请求过于频繁
await new Promise(resolve => setTimeout(resolve, 200));
}
return results;
}
Python 示例
import requests
import time
def batch_ocr(image_paths):
results = []
for path in image_paths:
try:
with open(path, 'rb') as f:
files = {'file': f}
response = requests.post(
'https://api.easyocr.org/ocr',
files=files
)
result = response.json()
results.append({
'filename': path,
'success': True,
'data': result
})
except Exception as e:
results.append({
'filename': path,
'success': False,
'error': str(e)
})
# 添加延迟
time.sleep(0.2)
return results
方案二:并发请求处理
如果需要更快的处理速度,可以使用并发请求同时处理多张图片。但需要注意控制并发数量,避免触发 API 限流。
JavaScript 并发示例
async function batchOCRConcurrent(images, concurrency = 3) {
const results = [];
// 将图片分成多个批次
for (let i = 0; i < images.length; i += concurrency) {
const batch = images.slice(i, i + concurrency);
const promises = batch.map(async (image) => {
const formData = new FormData();
formData.append('file', image);
try {
const response = await fetch('https://api.easyocr.org/ocr', {
method: 'POST',
body: formData
});
return {
filename: image.name,
success: true,
data: await response.json()
};
} catch (error) {
return {
filename: image.name,
success: false,
error: error.message
};
}
});
const batchResults = await Promise.all(promises);
results.push(...batchResults);
// 批次之间添加延迟
if (i + concurrency < images.length) {
await new Promise(resolve => setTimeout(resolve, 500));
}
}
return results;
}
Python 异步并发示例
import asyncio
import aiohttp
async def ocr_single(session, image_path):
try:
with open(image_path, 'rb') as f:
data = aiohttp.FormData()
data.add_field('file', f, filename=image_path)
async with session.post(
'https://api.easyocr.org/ocr',
data=data
) as response:
result = await response.json()
return {
'filename': image_path,
'success': True,
'data': result
}
except Exception as e:
return {
'filename': image_path,
'success': False,
'error': str(e)
}
async def batch_ocr_async(image_paths, concurrency=3):
semaphore = asyncio.Semaphore(concurrency)
async def limited_ocr(session, path):
async with semaphore:
result = await ocr_single(session, path)
await asyncio.sleep(0.2) # 请求间隔
return result
async with aiohttp.ClientSession() as session:
tasks = [limited_ocr(session, path) for path in image_paths]
return await asyncio.gather(*tasks)
# 使用示例
# results = asyncio.run(batch_ocr_async(image_list))
错误处理与重试机制
批量处理时,部分请求可能因网络问题或临时错误而失败。实现重试机制可以提高整体成功率。
async function ocrWithRetry(image, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const formData = new FormData();
formData.append('file', image);
const response = await fetch('https://api.easyocr.org/ocr', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
console.log(`尝试 ${attempt}/${maxRetries} 失败: ${error.message}`);
if (attempt === maxRetries) {
throw error;
}
// 指数退避:每次重试等待时间翻倍
await new Promise(resolve =>
setTimeout(resolve, 1000 * Math.pow(2, attempt - 1))
);
}
}
}
进度跟踪与回调
处理大量图片时,提供进度反馈可以改善用户体验。
async function batchOCRWithProgress(images, onProgress) {
const results = [];
const total = images.length;
for (let i = 0; i < images.length; i++) {
const image = images[i];
// 调用进度回调
onProgress({
current: i + 1,
total: total,
percentage: Math.round(((i + 1) / total) * 100),
currentFile: image.name
});
// 处理图片...
const result = await processImage(image);
results.push(result);
}
return results;
}
// 使用示例
batchOCRWithProgress(images, (progress) => {
console.log(`处理进度: ${progress.percentage}% (${progress.current}/${progress.total})`);
console.log(`当前文件: ${progress.currentFile}`);
});
性能优化建议
1. 图片预处理
在上传前对图片进行压缩和优化,可以减少传输时间:
- 将大图片压缩到合适尺寸(建议宽度不超过 2000px)
- 使用 JPEG 格式并适当降低质量(80-90%)
- 裁剪掉不需要识别的区域
2. 合理设置并发数
- 并发数过低:处理速度慢
- 并发数过高:可能触发限流或导致服务器压力
- 建议值:3-5 个并发请求
3. 实现断点续传
对于大批量任务,保存处理进度,支持中断后继续:
// 保存进度到本地存储
function saveProgress(processedIds) {
localStorage.setItem('ocr_progress', JSON.stringify(processedIds));
}
// 恢复进度
function loadProgress() {
const saved = localStorage.getItem('ocr_progress');
return saved ? JSON.parse(saved) : [];
}
4. 结果缓存
对于相同的图片,缓存识别结果避免重复请求。
注意事项
- 遵守 API 使用规范:不要发送过于频繁的请求
- 添加适当延迟:建议请求间隔 200ms 以上
- 实现错误处理:网络请求可能失败,需要妥善处理
- 监控处理状态:记录成功和失败的数量,便于排查问题
- 考虑内存占用:大量图片同时加载可能导致内存不足
相关资源
了解更多 OCR 使用技巧: