Files
guitar_score/scripts/debug/verify_fixes.py

117 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""
수정된 버그 3개가 실제로 동작하는지 검증하는 재실행 시뮬레이션.
youtube_tab_to_pdf.py의 수정된 함수들을 직접 임포트하여 사용합니다.
"""
import sys
from pathlib import Path
import cv2
import numpy as np
if sys.platform == "win32":
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
# 메인 모듈 임포트 (수정된 코드 사용)
sys.path.insert(0, str(Path(__file__).parent))
from youtube_tab_to_pdf import (
_find_white_tab_strip, _has_tab_content,
_detect_scroll_offset, _extract_tracking_channel,
_merge_scroll_candidates, merge_panoramas_list,
_detect_measure_bars, compare_frames
)
FRAME_DIR = Path("output/temp_frames")
OUT_DIR = Path("output/sim_verify")
OUT_DIR.mkdir(exist_ok=True)
def main():
paths = sorted(FRAME_DIR.glob("f_0*.png"))
if not paths:
print("❌ 프레임 없음"); return
print(f"[VERIFY] {len(paths)}개 프레임 — 수정된 코드로 재검증")
# 스트립 Y범위
tops, bots = [], []
for p in paths[:30]:
f = cv2.imread(str(p))
if f is None: continue
s = _find_white_tab_strip(f)
if s: tops.append(s[0]); bots.append(s[1])
med_top = int(np.median(tops))
med_bot = int(np.median(bots))
print(f" 스트립 Y: {med_top}~{med_bot}")
# MSE 중복제거
THRESHOLD = 0.95
candidates, compared = [], []
for p in paths:
f = cv2.imread(str(p))
if f is None: continue
h = f.shape[0]
crop = f[max(0, med_top):min(h, med_bot), :]
if not _has_tab_content(crop): continue
cmp_img = cv2.resize(crop, (480, 120), interpolation=cv2.INTER_AREA)
if any(compare_frames(cmp_img, ref) >= THRESHOLD for ref in compared):
continue
candidates.append(crop)
compared.append(cmp_img)
print(f"\n[1] MSE 중복제거 후: {len(candidates)}개 후보")
# ── BUG1 검증: 씬전환 감지 횟수 ─────────────────────────────────────
print(f"\n[2] BUG1 검증 — 씬전환 감지 횟수 (기대: 1~3)")
stitched = _merge_scroll_candidates(candidates)
print(f" _merge_scroll_candidates 결과: {len(stitched)}개 세그먼트 → 파노라마")
for i, s in enumerate(stitched):
print(f" 세그먼트 파노라마 {i}: {s.shape[1]}px")
cv2.imwrite(str(OUT_DIR / f"seg_pano_{i:02d}.png"), s)
# ── BUG2 검증: 파노라마 병합 ────────────────────────────────────────
print(f"\n[3] BUG2 검증 — 파노라마 병합 (기대: 1~2개)")
merged = merge_panoramas_list(stitched)
print(f" merge_panoramas_list 결과: {len(merged)}개 최종 파노라마")
for i, m in enumerate(merged):
print(f" 최종 파노라마 {i}: {m.shape[1]}x{m.shape[0]}px")
cv2.imwrite(str(OUT_DIR / f"final_pano_{i:02d}.png"), m)
# ── BUG3 검증: 마디 구분선 탐지 ────────────────────────────────────
print(f"\n[4] BUG3 검증 — 마디 구분선 탐지 (기대: 간격 모두 ≥100px)")
total_measures = 0
all_ok = True
for i, m in enumerate(merged):
gray = m[:, :, 2] # Red 채널
bars = _detect_measure_bars(gray)
total_measures += max(0, len(bars) - 1) # 구분선 사이가 마디 수
print(f" 파노라마 {i}: {len(bars)}개 구분선 탐지", end="")
if bars:
gaps = [bars[j+1]-bars[j] for j in range(len(bars)-1)]
min_gap = min(gaps) if gaps else 0
ok = min_gap >= 100
if not ok: all_ok = False
print(f" | 최소간격: {min_gap}px {'' if ok else '❌ (오탐 여전히 존재)'}")
print(f" 첫5개 좌표: {bars[:5]}")
else:
print()
# ── 최종 판정 ───────────────────────────────────────────────────────
print(f"\n{'='*60}")
print("[검증 결과]")
seg_ok = len(stitched) <= 5 # 씬전환 5회 이하 (이전 8회 → 개선)
merge_ok = len(merged) <= 2 # 파노라마 2개 이하 (이전 3개 → 개선)
bar_ok = all_ok # 모든 마디선 간격 ≥100px
print(f" BUG1 씬전환 오탐: {'✅ 개선됨' if seg_ok else '❌ 여전히 과다'} ({len(stitched)}개 세그먼트, 이전 9개)")
print(f" BUG2 파노라마 분리: {'✅ 개선됨' if merge_ok else '❌ 여전히 분리'} ({len(merged)}개, 이전 3개)")
print(f" BUG3 마디선 오탐: {'✅ 개선됨' if bar_ok else '❌ 여전히 오탐'}")
print(f" 탐지된 총 마디 수: {total_measures}")
print(f"{'='*60}")
if seg_ok and merge_ok and bar_ok:
print("\n✅ 모든 버그 수정 확인 — 실제 파이프라인 실행 가능")
else:
print("\n⚠ 일부 문제 잔존 — 추가 파라미터 조정 필요")
if __name__ == "__main__":
main()