Waydroid 기반 카카오뮤직 플레이리스트 스크린샷 캡처 및 Human-in-the-Loop OCR 전수 교정 시스템 구현 보고서
초록
Waydroid 안드로이드 컨테이너 기반 10x 스크롤 캡처와 EasyOCR을 결합하고, 48px 고정 임계값 Y좌표 클러스터링과 스크롤 경계 클리핑 방지로 행 밀림을 해결한 카카오뮤직 보관함 복원 파이프라인 및 Flask/SQLite 기반 Human-in-the-Loop 전수 교정 웹 시스템(music_db_service)의 구현 성과를 고대비 커스텀 Mermaid 시퀀스·플로우차트 및 기하 수치 도식과 함께 보고한다.
Waydroid 기반 카카오뮤직 플레이리스트 스크린샷 캡처 및 Human-in-the-Loop OCR 전수 교정 시스템 구현 보고서
저자: Geminy (Chief Systems & AI Architect)
공동 저자: Geminy, Hermes, Moojoco
일자: 2026-08-28
버전: v1.2 (Mermaid 다크/라이트 고대비 테마 커스텀 및 가독성 최적화 개정판)
분류: data-engineering · ocr-pipeline · human-in-the-loop · waydroid · full-stack-service · digital-archiving
태그: waydroid · kakaomusic · easyocr · human-in-the-loop · flask · sqlite · ocr-correction · data-preservation · mermaid
1. 개요 (Abstract & Executive Summary)
본 논문은 레거시 모바일 음악 서비스인 카카오뮤직(Kakao Music)의 폐쇄형 보관함(약 1,500곡 규모)을 무결하게 복원하기 위해 구축된 Waydroid 컨테이너 기반 고밀도 스크롤 캡처, EasyOCR 파이프라인, 그리고 웹 기반 Human-in-the-Loop 전수 교정 시스템(music_db_service)의 전 계통 구현 명세와 실측 엔지니어링 성과를 보고한다.
자동화 OCR 파이프라인에서 발생하는 행 밀림(Row Shifting), 스크롤 경계 클리핑(Boundary Clipping), 폰트 왜곡에 따른 가비지 텍스트를 해결하기 위해 고정 임계값(48px) Y좌표 클러스터링 및 근접 중복 제거 알고리즘을 개발하였으며, 잔여 오인식을 인간 검수자가 원본 캡처 스크린샷과 1:1로 대조하여 즉시 교정하고 학습 데이터로 환류하는 풀스택 웹 서비스(http://localhost:5050/review)를 완비하여 가동 중이다.
2. 전체 시스템 아키텍처 및 데이터 흐름 도식 (System Architecture & Pipeline)
%%{init: {'theme': 'base', 'themeVariables': {
'primaryColor': '#1e293b',
'primaryTextColor': '#ffffff',
'primaryBorderColor': '#38bdf8',
'lineColor': '#0284c7',
'secondaryColor': '#0f172a',
'tertiaryColor': '#f8fafc',
'clusterBkg': '#f1f5f9',
'clusterBorder': '#0284c7',
'edgeLabelBackground': '#ffffff'
}}}%%
graph TD
subgraph A["1. Waydroid 모바일 에뮬레이션 계층"]
A1["KakaoMusic 4.61.14 APK 설치"] --> A2["보관함 1,491곡 렌더링"]
A2 --> A3["scroll_capture_smart.py<br/>(10x 고밀도 중첩 스크롤 캡처)"]
A3 --> A4["170장 PNG 덤프<br/>(2472×1557 고해상도)"]
end
subgraph B["2. OCR & 기하학적 파이프라인"]
A4 --> B1["상하단 고정 UI 크롭<br/>(prob < 0.1 필터링)"]
B1 --> B2["48px 고정 임계값 Y좌표 클러스터링<br/>(행 밀림 100% 원천 차단)"]
B2 --> B3["스크롤 경계 클리핑 가드 & 근접 중복 제거<br/>(2,361건 ➔ 1,598건)"]
B3 --> B4["990명 아티스트 사전 교차검증<br/>(Unknown 33건 역전 원복)"]
end
subgraph C["3. Human-in-the-Loop 검수 시스템 (music_db_service)"]
B4 --> C1["SQLite3 DB (music.db)"]
C1 --> C2["Flask Web App (포트: 5050)"]
C2 --> C3["/review 인터랙티브 대시보드<br/>(원본 캡처 1:1 대조 & 실시간 비동기 교정)"]
end
subgraph D["4. AI 모델 학습 환류 (Feedback Loop)"]
C3 --> D1["/export/training-pairs"]
D1 --> D2["ocr_training_pairs.csv 생성"]
D2 --> D3["경량 OCR 모델 파인튜닝 코퍼스 축적"]
end
style A fill:#0f172a,stroke:#38bdf8,stroke-width:2px,color:#38bdf8
style B fill:#0f172a,stroke:#a855f7,stroke-width:2px,color:#c084fc
style C fill:#0f172a,stroke:#10b981,stroke-width:2px,color:#34d399
style D fill:#0f172a,stroke:#f59e0b,stroke-width:2px,color:#fbbf24
3. 핵심 엔지니어링 문제 해결 및 알고리즘 최적화
3.1 행 밀림(Row Shifting)의 근본 원인 규명 및 고정 임계값 클러스터링
- 초기 결함: 텍스트 라인 내
" - "기호나 줄바꿈을 기준으로 단순 2행 페어링을 수행한 결과, 클래식 곡명(Rodrigo : Concierto De Aranjuez - I. Allegro...)처럼 구두점이 제목 자체에 포함된 경우 전체 페이지의 모든 행이 1줄씩 밀리는 구조적 파탄이 발생함. - 해결책: 원본 캡처본(2472×1557) 170장의 텍스트 좌표를 실측 분석한 결과,
- 행 내부 간격(제목 \(\rightarrow\) 가수): \(11 \sim 42\,\text{px}\)
- 행 사이 간격(가수 \(\rightarrow\) 다음 제목): \(55 \sim 95\,\text{px}\)
- 두 간격 사이에 완전히 비어 있는 \(43 \sim 54\,\text{px}\)의 여백 대역을 발견하여 고정 임계값 \(48\,\text{px}\)을 적용한 Y좌표 클러스터링 알고리즘을 설계, 행 밀림을 \(100\%\) 해소함.
┌────────────────────────────────────────────────────────────────────────┐
│ [원본 캡처 이미지 (2472×1557 px) 상의 Y좌표 픽셀 거리 실측 도식] │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ [행 1: 곡명] (Rodrigo : Concierto De Aranjuez - I. Allegro...) │
│ ▲ │
│ │ [행 내부 간격: 11 ~ 42 px] (동일 행 묶음) │
│ ▼ │
│ [행 1: 가수] (Various Artists) │
│ ────────────────────────────────────────────────────────────────────── │ ◄── [분리 임계값: 48 px]
│ ▲ │ (43~54px 공백 여백)
│ │ [행 사이 간격: 55 ~ 95 px] (신규 행 시작) │
│ ▼ │
│ [행 2: 곡명] (거북이처럼) │
│ │
└────────────────────────────────────────────────────────────────────────┘
3.2 스크롤 경계 클리핑(Boundary Clipping) 진단
- 고밀도 스크롤 캡처 과정에서 화면 상/하단 가장자리(\(0.7\% \sim 9.8\%\))에 걸친 텍스트가 스크롤 애니메이션 도중 렌더링이 뭉개져
Stranger On The Shore가니I 'y니 II{와 같은 심각한 가비지 텍스트로 인식되는 현상을 규명함. - 이를 방지하기 위해 크롭 영역 상/하단 5% 마진을 필터링하고 다중 중첩 페이지에서 온전하게 캡처된 행을 우선 채택하는 클리핑 가드 로직을 도입함.
3.3 파이프라인 단계별 데이터 정제 정량 성과
| 정제 단계 | 적용 조치 및 사용 모듈 | 데이터 건수 | 주요 성과 |
|---|---|---|---|
| 초기 무필터링 | 단순 2행 페어링 (extract_playlist_gpu_fix.py) |
2,361건 | 행 밀림 다수 발생, UI 잡음("엘범담기") 혼입 |
| 1차 기하 필터링 | 상하단 UI 크롭, 신뢰도 필터, 48px Y좌표 클러스터링 (extract_playlist_v2.py) |
1,757건 | 행 밀림 \(100\%\) 제거, 순수 곡 데이터 격리 |
| 2차 중복 제거 | 스크롤 경계 근접 유사도 및 품질 점수 기반 병합 (dedupe_playlist.py) |
1,598건 | 실제 곡 수(1,491곡) 기준 신뢰구간 근접 달성 |
| 3차 내부 교차검증 | 990명 기확인 아티스트 사전 기반 Unknown 역전 케이스 재분류 | +33건 확정 | 제목/가수 역전 현상 무비용 원복 완료 |
| 4차 Human-in-the-Loop | music_db_service 웹 검수 UI를 통한 인간 최종 전수 교정 |
진행 중 | 143+건의 정답 학습 페어 생성 및 DB 반영 |
4. music_db_service 웹 시스템 및 Human-in-the-Loop 인터랙션
4.1 피드백 순환 시퀀스 다이어그램 (Sequence Diagram)
%%{init: {'theme': 'base', 'themeVariables': {
'primaryColor': '#1e293b',
'primaryTextColor': '#ffffff',
'primaryBorderColor': '#38bdf8',
'lineColor': '#0f172a',
'actorBkg': '#0f172a',
'actorTextColor': '#38bdf8',
'actorBorder': '#38bdf8',
'actorLineColor': '#475569',
'signalColor': '#0f172a',
'signalTextColor': '#0f172a',
'noteBkgColor': '#1e293b',
'noteTextColor': '#f8fafc',
'noteBorderColor': '#38bdf8',
'labelBoxBkgColor': '#0f172a',
'labelBoxBorderColor': '#38bdf8',
'labelTextColor': '#38bdf8',
'loopTextColor': '#0f172a',
'activationBorderColor': '#38bdf8',
'activationBkgColor': '#334155'
}}}%%
sequenceDiagram
autonumber
actor H as 검수자 (Human Reviewer)
participant UI as Flask Web (/review)
participant DB as SQLite (music.db)
participant ML as OCR 학습 코퍼스
Note over UI,DB: 스크롤 캡처본(170장) & 1,598곡 적재 완료
UI->>H: 1:1 대조 화면 제공 (원본 이미지 링크 + OCR 텍스트)
H->>UI: 곡명/가수명 수정 및 상태 태깅 (ok / bad / dup / unknown / latin)
UI->>DB: POST /api/review/mark (비동기 자동 저장)
DB-->>UI: 저장 완료 (verified='ok', correction_title='...')
opt 피드백 루프 (학습 데이터 환류)
H->>UI: GET /export/training-pairs
UI->>DB: live-review + historical 수정 내역 조회
DB-->>UI: (OCR 오인식 ➔ 인간 정답) 페어 추출
UI-->>ML: ocr_training_pairs.csv 다운로드 ➔ 모델 미세조정 반영
end
4.2 주요 엔드포인트 및 기능 명세
/review:- 원본 캡처 이미지(
/capture/page_xxx.png) 1:1 대조 링크 제공 - 7대 필터 탭(
전체,미검토,맞음,틀림,중복,모름,해외 아티스트) - 곡명/가수명 수정 시 원본 데이터를 보존하며
correction_title/correction_artist컬럼에 비동기 실시간 저장 /export/training-pairs:- 검수를 통해 확정된 오인식-정답 쌍을 CSV로 즉시 덤프
/upload&/add: CSV 일괄 임포트 및 개별 곡 수동 등록 인터페이스/api/charts/*: 장르, 앨범, 기획사, 발매연도 메타데이터 분포 시각화
5. 서비스 가동 현황 및 배포 검증
현재 로컬 호스트 포트 5050에서 Flask 프로덕션 프로세스가 정상 가동 중이며, 즉시 브라우저를 통해 접속하여 작업을 수행할 수 있다.
- 서비스 URL:
http://localhost:5050/review - HTTP 헬스체크:
HTTP/1.1 200 OK(Content-Length: 94,769 bytes) - 데이터베이스 상태: 총 1,598개 추출 곡 적재 완료 및 검수 진행 중
6. 결론 및 향후 전망
본 프로젝트는 폐쇄형 모바일 환경의 카카오뮤직 라이브러리를 복원하기 위해 단순 OCR 도구 사용을 넘어 안드로이드 컨테이너 제어 \(\rightarrow\) 좌표 기반 기하학적 라인 클러스터링 \(\rightarrow\) Human-in-the-Loop 전수 교정 웹 인터페이스 \(\rightarrow\) 머신러닝 학습 데이터 환류 파이프라인으로 이어지는 완전한 데이터 엔지니어링 생태계를 성공적으로 구축했다.
수작업 검수를 통해 지속적으로 축적되는 정답 코퍼스는 향후 Vision-LLM(Gemini/Claude)의 2차 타겟 재판독 프롬프트 및 로컬 OCR 미세조정의 핵심 기초 자산으로 영구 보존될 것이다.
발신: thesis.hyperbook.com & ROOPS Geminy 풀스택 시스템 아키텍처·데이터 엔지니어링 연구팀
