# -*- coding: utf-8 -*- """ 统计合成图的【像素尺寸】, 看有多少张超大(最长边>阈值) → 判断是不是OCR超时的根因。 纯标准库, 不依赖 PIL / cv2 / 项目代码。只读JPEG文件头, 不解码, 很快。 用法: python3 tools/查合成图尺寸.py # 默认扫 ./split/**/composite/, 阈值4000 python3 tools/查合成图尺寸.py --dir ./split --max 4000 """ import argparse import glob import os def jpeg_size(path): """只读 JPEG 文件头拿 (宽,高), 不解码。失败返回 None。""" try: with open(path, 'rb') as f: if f.read(2) != b'\xff\xd8': return None while True: b = f.read(1) while b and b != b'\xff': b = f.read(1) marker = f.read(1) while marker == b'\xff': marker = f.read(1) if not marker: return None m = marker[0] if 0xC0 <= m <= 0xCF and m not in (0xC4, 0xC8, 0xCC): f.read(3) h = int.from_bytes(f.read(2), 'big') w = int.from_bytes(f.read(2), 'big') return w, h seg = int.from_bytes(f.read(2), 'big') if seg < 2: return None f.seek(seg - 2, 1) except Exception: return None def main(): ap = argparse.ArgumentParser() ap.add_argument('--dir', default='./split') ap.add_argument('--max', type=int, default=4000, help='超大阈值(最长边像素)') args = ap.parse_args() pats = [os.path.join(args.dir, '**', 'composite', '*.jpg'), os.path.join(args.dir, '**', '*.jpg')] files = [] for p in pats: files = glob.glob(p, recursive=True) if files: break files = [f for f in files if 'composite' in f] if not files: print(f"在 {args.dir} 下没找到 composite/*.jpg") return tot = over = mx = 0 sizes = [] for f in files: sz = jpeg_size(f) if sz: tot += 1 m = max(sz) mx = max(mx, m) sizes.append((os.path.getsize(f), sz, f)) if m > args.max: over += 1 print("=" * 56) print(f"合成图 {tot} 张 | 最长边>{args.max} 的 {over} 张 " f"({over/tot*100:.0f}%) | 最大最长边 {mx}px") print("=" * 56) print("最大的 8 张:") for fsize, (w, h), f in sorted(sizes, reverse=True)[:8]: flag = ' <== 超大' if max(w, h) > args.max else '' print(f" {fsize//1024:5d}KB {w}x{h} 最长边={max(w,h)}{flag}") print() if over > tot * 0.3: print(f"⚠ {over}/{tot} 张超大 → 实锤: 超大合成图就是OCR超时根因。") print(f" 部署 ocr_max_image_side={args.max} 后, 这些缩到 {args.max}px, OCR 从30s降到几秒。") elif over == 0: print("✓ 没有超大图(尺寸都正常) → 超时不是图大, 是端点问题(共享/波动)。") else: print(f"部分超大({over}张), 部署尺寸上限能缓解这部分。") if __name__ == '__main__': main()