如何优化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
相关产品推荐
相关产品推荐

