101 lines
3.4 KiB
Python
101 lines
3.4 KiB
Python
# -*- 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()
|