You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化Python OCR批量处理截图的循环速度?

问题描述

我用OCR从关注者列表截图提取文本并转换为DataFrame,初始提取的文本是交替的昵称(Screenname)和显示名(name),还存在空行,所以做了对应处理。代码在处理1-30张图片时正常,但处理5-10k张截图时速度明显变慢,求优化循环速度的建议。

原代码:

from PIL import Image
from pytesseract import pytesseract
import os
import pandas as pd
from itertools import chain

list_final = [""]
list_name = [""]
liste_anzeigename = [""]
list_raw = [""]
anzeigename = [""]
name = [""]
sort = [""]
f = r'/Users/PycharmProjects/pythonProject/images'
myconfig = r"--psm 4 --oem 3"

os.listdir(f)
for file in os.listdir(f):
    f_img = f+"/"+file
    img = Image.open(f_img)
    img = img.crop((240, 400, 800, 2400))
    img.save(f_img)

for file in os.listdir(f):
    f_img = f + "/" + file
    test = pytesseract.image_to_string(PIL.Image.open(f_img), config=myconfig)

    lines = test.split("\n")
    list_raw = [line for line in lines if line.strip() != ""]
    sort.append(list_raw)

    name = {list_raw[0], list_raw[2], list_raw[4],
            list_raw[6], list_raw[8], list_raw[10],
            list_raw[12], list_raw[14], list_raw[16]}
    list_name.append(name)

    anzeigename = {list_raw[1], list_raw[3], list_raw[5],
                   list_raw[7], list_raw[9], list_raw[11],
                   list_raw[13], list_raw[15], list_raw[17]}
    liste_anzeigename.append(anzeigename)

reihenfolge_name = list(chain.from_iterable(list_name))
index_anzeigename = list(chain.from_iterable(liste_anzeigename))
sortieren = list(chain.from_iterable(sort))

print(list_raw)
sort_name = sorted(reihenfolge_name, key=sortieren.index)
sort_anzeigename = sorted(index_anzeigename, key=sortieren.index)

final = pd.DataFrame(zip(sort_name, sort_anzeigename), columns=['name', 'anzeigename'])
print(final)
优化建议

1. 合并两次文件遍历,消除重复IO开销

原代码先遍历所有图片裁剪保存,再遍历一次做OCR,两次IO遍历对5-10k文件来说耗时极大。改为一次遍历完成裁剪、OCR处理,无需保存裁剪后的图片,直接用内存中的Image对象传给pytesseract,省去文件写入的IO浪费。

2. 替换集合存储,直接按顺序提取列表

原代码用set存储昵称和显示名,集合是无序的,后续用sorted加sortieren.index排序时,index查找是O(n)时间复杂度,数据量越大越慢。直接按步长提取列表,保持原始顺序,完全不需要后续排序。

3. 初始化空列表,避免冗余元素

原代码初始化列表时带空字符串(比如list_name = [""]),后续append会带入空元素,增加后续处理负担,直接初始化空列表即可。

4. 避免重复打开图片

原代码裁剪时打开一次图片,OCR时又重新打开一次,浪费内存和IO资源,裁剪后直接用内存中的Image对象进行OCR。

5. 用os.path.join()优化路径拼接

代替字符串拼接路径,更安全高效,避免路径分隔符问题。

优化后的代码
from PIL import Image
import pytesseract
import os
import pandas as pd

# 初始化空列表存储结果
all_names = []
all_display_names = []

image_dir = r'/Users/PycharmProjects/pythonProject/images'
ocr_config = r"--psm 4 --oem 3"

# 一次遍历完成所有操作
for filename in os.listdir(image_dir):
    img_path = os.path.join(image_dir, filename)
    # 打开图片并裁剪,用with自动释放资源
    with Image.open(img_path) as img:
        cropped_img = img.crop((240, 400, 800, 2400))
        # 直接用裁剪后的图片做OCR,无需保存
        text = pytesseract.image_to_string(cropped_img, config=ocr_config)
    
    # 过滤空行并去除首尾空格
    lines = [line.strip() for line in text.split("\n") if line.strip()]
    
    # 按步长提取昵称(偶数索引)和显示名(奇数索引),添加长度检查避免索引越界
    if len(lines) >= 18:
        names = lines[0::2]  # 取0,2,4...16
        display_names = lines[1::2]  # 取1,3,5...17
        all_names.extend(names)
        all_display_names.extend(display_names)

# 直接生成DataFrame,无需后续排序
final_df = pd.DataFrame({
    'name': all_names,
    'anzeigename': all_display_names
})

print(final_df)

额外优化方向(可选)

  • 并行处理:OCR是CPU密集型操作,单线程处理5-10k图片很慢,用ProcessPoolExecutor实现多进程并行处理,大幅提升速度:
from concurrent.futures import ProcessPoolExecutor

def process_image(img_path):
    with Image.open(img_path) as img:
        cropped_img = img.crop((240, 400, 800, 2400))
        text = pytesseract.image_to_string(cropped_img, config=ocr_config)
    lines = [line.strip() for line in text.split("\n") if line.strip()]
    if len(lines) >= 18:
        return lines[0::2], lines[1::2]
    return [], []

# 生成所有有效图片路径
image_paths = [
    os.path.join(image_dir, fn) 
    for fn in os.listdir(image_dir) 
    if fn.lower().endswith(('.png', '.jpg', '.jpeg'))
]

# 多进程处理
with ProcessPoolExecutor() as executor:
    results = executor.map(process_image, image_paths)

# 汇总结果
all_names = []
all_display_names = []
for names, display_names in results:
    all_names.extend(names)
    all_display_names.extend(display_names)

final_df = pd.DataFrame({'name': all_names, 'anzeigename': all_display_names})
  • 过滤非图片文件:遍历前筛选出图片格式文件,避免无效处理。
  • 调整OCR参数:如果截图格式固定,尝试调整--psm参数(比如--psm 6假设是单一文本块),可能提升OCR速度和准确性。

内容的提问来源于stack exchange,提问作者Vincenr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 00:25:25