Loading... 问题描述 正在尝试从 GIF 图片中提取每一帧并进行 OCR 识别,当前代码在多线程环境下可能会出现图片重合的情况,导致识别失败。用户希望解决这个问题,避免图片重合,并且考虑是否可以不保存图片到本地,直接进行识别。 ``` import requests from PIL import Image import os import re import ddddocr def down_gif(url): # url = "https://d11x481pn35wh6.cloudfront.net/TMdgfxyd/1dBdijbBPsWY.gif" res = requests.get(url).content open("hhh.gif", "wb").write(res) def split_gif(): # 打开GIF文件 gif_path = 'hhh.gif' # 替换为你的GIF文件路径 gif = Image.open(gif_path) # 创建输出目录 output_dir = 'output_frames' if not os.path.exists(output_dir): os.makedirs(output_dir) # 遍历每一帧并保存 frame = 0 while True: gif.seek(frame) frame_image = gif.copy() frame_image.save(f"{output_dir}/frame_{frame}.png") # 保存为PNG格式 frame += 1 try: gif.seek(frame) except EOFError: break print(f"GIF分解完成,共保存了{frame}张图片") # 合并字符串 def merge_strings(str1, str2): # 将输入的字符串转换为小写,找到第一个字符串的后缀和第二个字符串的前缀公共部分 lower_str1 = str1.lower() lower_str2 = str2.lower() for i in range(min(len(lower_str1), len(lower_str2)), 0, -1): if lower_str1.endswith(lower_str2[:i]): return (str1 + str2[i:]).lower() # 如果没有公共部分,直接合并并转换为小写 return (str1 + str2).lower() def dddocr(): # 定义图片文件夹路径 # output_dir = 'output_frames' output_dir = 'output_frames' # 提取文件名中的数字,并返回排序后的文件列表 def sort_key(filename): match = re.search(r'_(\d+)\.png', filename) # 提取文件名中的数字部分 if match: return int(match.group(1)) # 返回数字部分作为排序依据 return float('inf') # 如果没有数字,则将该文件放在最后 # 获取所有 .png 文件,并按数字顺序排序 sorted_files = sorted([f for f in os.listdir(output_dir) if f.endswith('.png')], key=sort_key) results = [] sorted_file = [sorted_files[0]] + [sorted_files[-1]] # 遍历排序后的文件列表 for filename in sorted_file: file_path = os.path.join(output_dir, filename) print(f"找到图片文件: {file_path}") file = open(file_path, "rb").read() ocr = ddddocr.DdddOcr(show_ad=False, beta=True) result = ocr.classification(file) print(result) results.append(result) return merge_strings(results[1], results[0]) down_gif("https://d11x481pn35wh6.cloudfront.net/QKuHUNze/WxGVbJDfXYls.gif") split_gif() print(dddocr()) ``` **** 在多线程使用时,图片会重合,导致识别失败。想请教如何修改,避免保存到本地,直接进行识别,或者使用其他方式,确保在多线程环境下图片不会重合。 解决方案 为了避免多线程环境中图片重合的问题,建议不保存图片到本地,而是直接在内存中处理 GIF 的每一帧并进行 OCR 识别。可以使用 io.BytesIO 来处理图片数据,避免文件系统的读写操作,并使用 ThreadPoolExecutor 来并发处理多个帧。 优化后的代码 ```python import requests from PIL import Image import io import re import ddddocr from concurrent.futures import ThreadPoolExecutor def down_gif(url): res = requests.get(url).content return res # 直接返回GIF二进制内容 def extract_frames(gif_content): # 通过io.BytesIO在内存中处理GIF内容 gif = Image.open(io.BytesIO(gif_content)) frames = [] try: while True: frame_image = gif.copy() # 复制当前帧 frames.append(frame_image) gif.seek(gif.tell() + 1) # 移动到下一帧 except EOFError: pass print(f"GIF分解完成,共提取了{len(frames)}张图片") return frames # 合并字符串 def merge_strings(str1, str2): lower_str1 = str1.lower() lower_str2 = str2.lower() for i in range(min(len(lower_str1), len(lower_str2)), 0, -1): if lower_str1.endswith(lower_str2[:i]): return (str1 + str2[i:]).lower() return (str1 + str2).lower() def process_frame(frame, ocr_engine): with io.BytesIO() as output: frame.save(output, format="PNG") image_data = output.getvalue() # 获取内存中的图片数据 result = ocr_engine.classification(image_data) return result def dddocr(frames): ocr_engine = ddddocr.DdddOcr(show_ad=False, beta=True) # 仅选择第一个和最后一个帧进行OCR识别 selected_frames = [frames[0], frames[-1]] results = [] # 使用多线程处理帧 with ThreadPoolExecutor() as executor: future_to_frame = {executor.submit(process_frame, frame, ocr_engine): frame for frame in selected_frames} for future in future_to_frame: try: result = future.result() print(result) results.append(result) except Exception as e: print(f"处理帧时发生错误: {e}") # 合并识别结果 return merge_strings(results[1], results[0]) # 入口 def get_code(url): gif_content = down_gif(url) frames = extract_frames(gif_content) return dddocr(frames) ``` 改进点: 1. 内存处理 GIF 图片:使用 io.BytesIO 处理 GIF 文件的内容,避免读写本地文件。 2. 多线程处理帧:使用 ThreadPoolExecutor 来并行处理多个帧的 OCR 识别。 3. 直接传递内存中的帧:每一帧直接传递给 OCR 引擎进行识别,减少磁盘 I/O 操作。 这种方式不仅避免了多线程导致的图片重合问题,也提升了处理效率。 最后修改:2024 年 09 月 12 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏