首次提交

This commit is contained in:
2026-09-28 16:09:31 +08:00
commit 4a6839319a
71 changed files with 12144 additions and 0 deletions

100
tools/analyze_ocr_result.py Normal file
View File

@@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
"""
分析一个 ocr_result.jsonl,判断"冗余文字过多"是真冗余还是误杀。
复现过滤逻辑:看文字的垂直位置分布(distinct_bands)、每帧文字框数、有没有稳定字幕行。
用法: python temp/analyze_ocr_result.py "ocr_result (1).jsonl"
"""
import json
import sys
from collections import defaultdict
PATH = sys.argv[1] if len(sys.argv) > 1 else "ocr_result.jsonl"
def parse(path):
"""解析 'pic_path: X' + json 交替格式,返回 [(frame, detections), ...]。"""
pairs = []
cur_frame = None
with open(path, encoding="utf-8") as f:
for line in f:
line = line.rstrip("\n")
if line.startswith("pic_path:"):
cur_frame = line.split("pic_path:", 1)[1].strip()
elif line.strip():
try:
data = json.loads(line)
pairs.append((cur_frame, data.get("TextDetections", [])))
except json.JSONDecodeError:
pass
return pairs
def center_y(det):
poly = det.get("Polygon", [])
ys = [p.get("Y", 0) for p in poly]
return sum(ys) / len(ys) if ys else 0
def main():
try:
pairs = parse(PATH)
except FileNotFoundError:
print(f"找不到文件: {PATH}")
return
if not pairs:
print("没解析到数据(格式不对?)")
return
n_frames = len(pairs)
boxes_per_frame = [len(d) for _, d in pairs]
total_boxes = sum(boxes_per_frame)
frames_with_text = sum(1 for b in boxes_per_frame if b)
# 所有文字框的中心 Y
all_cy = []
for _, dets in pairs:
for det in dets:
all_cy.append(center_y(det))
print(f"文件: {PATH}")
print("=" * 60)
print(f"帧/图数: {n_frames}")
print(f"有文字的: {frames_with_text}")
print(f"文字框总数: {total_boxes}")
print(f"平均每帧框数: {total_boxes / n_frames:.1f}")
print(f"最多一帧框数: {max(boxes_per_frame) if boxes_per_frame else 0}")
# distinct vertical bands(复现 merge.py 的冗余判定:中心Y间隔>80算一个新垂直簇)
cys = sorted(all_cy)
bands = 1 if cys else 0
for i in range(1, len(cys)):
if cys[i] - cys[i - 1] > 80:
bands += 1
print(f"不同垂直位置簇: {bands} (>=8 会被判冗余)")
# Y 分布直方图(每 100px 一档),看文字集中在哪还是散布全屏
hist = defaultdict(int)
for y in all_cy:
hist[int(y // 100) * 100] += 1
print("\n文字垂直分布(Y每100px一档,看文字集中度):")
if hist:
mx = max(hist.values())
for y in sorted(hist):
bar = "#" * int(hist[y] / mx * 40)
print(f" y={y:>5}-{y+99:<5} {hist[y]:>6} {bar}")
# 判定
print("\n" + "=" * 60)
if bands >= 8:
print(f"❌ 真冗余:文字散布在 {bands} 个不同垂直位置(满屏文字/弹幕/文档类)。")
elif total_boxes / n_frames > 10:
print(f"⚠️ 偏冗余:平均每帧 {total_boxes/n_frames:.0f} 个文字框,画面文字很多。")
else:
topy = max(hist, key=hist.get) if hist else 0
print(f"✅ 可能误杀:文字主要集中在 y={topy}~{topy+99},像是有固定字幕行的。")
print(" 若确实有正常字幕,可放宽 merge.py 的 distinct_bands 阈值。")
if __name__ == "__main__":
main()