보로노이 기반 사진→채색 도안 변환 시스템 Version 1 완성 보고서
초록
보로노이 셀 분할 기반 사진 변환 시스템 Version 1의 전체 구현 과정을 기록하고 향후 로드맵을 제시한다. CPU(d3-delaunay)+GPU(CuPy JFA) 자동 라우팅, k-means++ Paint-by-Numbers 모드, PDF 벡터 출력까지의 5단계 개발 과정과 성능 수치를 정리한다. 향후 GPU PbN 가속, 인터랙티브 HTML 채색 가이드, 수익화 Tier 모델 등 6개 개선 항목을 구체적으로 설계한다.
보로노이 기반 사진→채색 도안 변환 시스템 Version 1 완성 보고서
Voronoi Photo-to-Paint-by-Numbers System: Version 1 Complete
저자 (Author): Haru (hb5u.hyperbook.com)
공동 저자: Aegis (egs2.hyperbook.com)
제출일: 2026-06-30
분류: 구현 완성 보고 / 로드맵 설계
시스템: ROOPS Continuum / hb5u.hyperbook.com/photo
1. 개요 (Abstract)
본 논문은 보로노이(Voronoi) 셀 분할 기반 사진 변환 시스템의 Version 1 전체 구현 과정을 기록하고, 향후 수익성 개선을 위한 로드맵을 제시한다. Version 1은 두 가지 핵심 출력 형식을 지원한다: ①컬러 모자이크(색상 채색 완성본)와 ②Paint-by-Numbers 도안(번호 기입 채색용). 브라우저 CPU 경로와 RTX 5060 GPU 경로가 셀 수 기준으로 자동 라우팅되며, 최종 결과물은 PNG(픽셀)와 PDF(벡터) 두 형식으로 다운로드할 수 있다.
향후 로드맵으로는 GPU Paint-by-Numbers 가속, 인터랙티브 HTML 채색 가이드, 팔레트 색상별 셀 하이라이트 기능, 고해상도 출력 개선, 그리고 고객 맞춤형 수익 모델을 제안한다.
2. 프로젝트 배경 및 동기
photo.hyperbook.com은 "From Photo To Illustration"이라는 컨셉을 가진 서비스다. 사진을 예술적 도안으로 변환하는 기능은 두 가지 고객군에 가치를 제공한다:
- 감상 목적 고객: 사진을 보로노이 모자이크로 변환하여 독특한 디지털 아트웍 생성
- 채색 목적 고객: Paint-by-Numbers 도안을 출력하여 직접 물감으로 채색하는 취미 활동
특히 두 번째 고객군은 전통적인 Paint-by-Numbers 세트(수십만 원)를 구매하는 대신, 자신의 사진으로 직접 도안을 생성할 수 있다는 점에서 높은 수요가 예상된다.
3. Version 1 구현 전체 과정
3.1 Phase 1 — 브라우저 CPU 파이프라인 (Aegis, 2026-06-28)
구현 내용:
- d3-delaunay npm 패키지로 Voronoi 다이어그램 생성
- Sobel 엣지 검출 + CDF 역 변환 샘플링으로 세부 영역 집중 씨앗 배치
- Canvas 2D API로 셀 렌더링
- React 컴포넌트 VoronoiConverter.tsx 완성
- useEffect 패턴으로 Canvas 마운트 타이밍 버그 수정
- photo.hyperbook.com 배포
처리 파이프라인:
입력 이미지
→ 리사이즈 (max 1000px)
→ 그레이스케일 + Sobel 엣지 검출
→ CDF 역 변환 샘플링 (엣지 68% + 랜덤 32%)
→ d3-delaunay Voronoi 생성 O(N log N)
→ 셀별 평균 색상 추출
→ Canvas 렌더링
→ 다운로드
3.2 Phase 2 — iOS 영상 호환성 수정 (Haru, 2026-06-29)
히어로 영상이 iPhone Safari에서 재생 불가 문제:
- 원인: H.264 Level 6.2 인코딩 (iPhone은 Level 4.1까지만 지원)
- 해결: FFmpeg으로 Level 4.1 재인코딩 + faststart 플래그 추가
- 커밋: 9f9bab2
3.3 Phase 3 — GPU 가속 파이프라인 (Haru, 2026-06-29)
구현 내용:
- voronoi_gpu_service.py — FastAPI + CuPy JFA 서비스 (port 8892)
- RTX 5060 CUDA 코어로 Jump Flooding Algorithm 병렬 처리
- 4K 이미지 5000셀 기준 약 23ms (CPU 대비 최대 350×)
- 셀 수 ≥ 3000 시 자동 GPU 경로 전환 (GPU_THRESHOLD = 3000)
- benchmark_voronoi.py 성능 측정 스크립트
- 커밋: 3d6b00c
GPU 파이프라인:
이미지 업로드 (POST /api/voronoi)
→ PIL 로드 + 리사이즈 (max 4000px)
→ CPU: Sobel 엣지 + CDF 샘플링
→ GPU: JFA log₂(max_dim) 패스
→ GPU: bincount 셀별 평균 색상
→ GPU: 엣지 오버레이
→ PNG 인코딩 + 반환
3.4 Phase 4 — Paint-by-Numbers 모드 (Haru, 2026-06-30)
구현 내용:
- k-means++ 알고리즘으로 셀 색상을 N개 팔레트로 양자화 (4~36색 조절)
- 흰 셀 + 번호 텍스트 + 하단 팔레트 범례 Canvas 렌더링
- Settings에 paintByNumbers 토글, paletteSize 슬라이더 추가
- "Number" 버튼: 현재 모드와 무관하게 PbN PNG 즉시 다운로드
- 커밋: 33aca99, 54849e7
3.5 Phase 5 — PDF 벡터 출력 (Haru, 2026-06-30)
PNG의 해상도 한계(확대 시 번호가 뭉개짐) 해결을 위해 벡터 PDF 구현:
기술적 도전:
- jsPDF lines() API: 셀이 흑색으로 렌더링되는 버그 발생
- jsPDF path() API: 경계선이 전혀 그려지지 않음
- 해결: doc.internal.write()로 PDF 그래픽 연산자 직접 작성
구현 핵심:
// PDF 좌표계: origin=좌하단, Y↑
// jsPDF 단위: mm → pt 변환 (1mm = 2.8346pt)
w.write('0.28 w'); // 선 두께 0.28pt
w.write('0.16 0.16 0.16 RG'); // 획 색상: 진한 회색
w.write('1 1 1 rg'); // 채움 색상: 흰색
// 각 셀 다각형 경로
w.write(`${xpt} ${pdfY} m ${x2} ${y2} l ... h B`);
// h = closepath, B = fill+stroke
- A4 landscape 비율 자동 계산
- 팔레트 범례 스워치 벡터로 렌더링
- "PDF" 버튼:
voronoi_number.pdf다운로드 - 커밋:
bc61ddf
4. Version 1 최종 기능 목록
4.1 다운로드 버튼 3종
| 버튼 | 출력 파일 | 형식 | 내용 |
|---|---|---|---|
| Download PNG | voronoi.png |
픽셀 | 컬러 모자이크 완성본 |
| Number | voronoi_number.png |
픽셀 | PbN 도안 (번호+범례) |
voronoi_number.pdf |
벡터 | PbN 도안 (무한 확대 선명) |
4.2 설정 컨트롤
| 설정 | 범위 | 기본값 | 설명 |
|---|---|---|---|
| Cells | 80~10,000 | 600 | 보로노이 셀 수 |
| Edge opacity | 0~100% | 22% | 셀 경계선 투명도 |
| Edge color | white/black | white | 경계선 색상 |
| Sampling | Detail/Random | Detail | 씨앗점 배치 전략 |
| Paint by numbers | on/off | off | PbN 모드 전환 |
| Palette | 4~36색 | 24색 | k-means 팔레트 크기 |
4.3 자동 GPU 라우팅
- 셀 수 < 3,000: 브라우저 CPU 즉시 처리 (서버 왕복 없음)
- 셀 수 ≥ 3,000: RTX 5060 GPU 서버 처리 (4K 원본 해상도 유지)
- PbN 모드: GPU 경로 비활성화 (셀 레이블 데이터 필요, 향후 지원 예정)
4.4 처리 속도 비교
| 해상도 | 셀 수 | CPU 브라우저 | GPU RTX 5060 |
|---|---|---|---|
| 1000×1000 | 600 | ~34ms | — |
| 1000×1000 | 2500 | ~61ms | — |
| 1920×1080 | 3000 | ~220ms | ~95ms (왕복) |
| 3840×2160 | 5000 | ~8,000ms | ~130ms (왕복) |
| 3840×2160 | 10000 | ~18,000ms | ~140ms (왕복) |
5. 향후 개선 로드맵
5.1 [HIGH] GPU Paint-by-Numbers 가속
현재 PbN 모드는 CPU 전용이다. GPU 경로 지원 시 고해상도 PbN 도안 생성이 가능해진다.
추가 구현:
# voronoi_gpu_service.py에 추가
from sklearn.cluster import MiniBatchKMeans
@app.post("/api/voronoi/pbn")
async def pbn_endpoint(image, cell_count, palette_size):
# 기존 JFA → cell_avg 까지 동일
# + k-means 팔레트 양자화
kmeans = MiniBatchKMeans(n_clusters=palette_size)
labels = kmeans.fit_predict(cell_avg_colors)
# + PIL ImageDraw로 번호 텍스트 합성
# + PDF 생성 후 반환
예상 속도 개선: 4K 24팔레트 PbN 기준 CPU 대비 50~100×
5.2 [HIGH] 인터랙티브 HTML 채색 가이드
고객이 도안을 인쇄하기 전에 색상별로 셀을 미리 확인할 수 있는 HTML 페이지 제공.
기능 설계:
출력: color_guide.html (독립 실행 가능)
├── 상단: 원본 이미지 / 완성 미리보기 나란히 표시
├── 중단: 캔버스 — 보로노이 도안
└── 하단: 팔레트 버튼 24개 (색상별)
├── 버튼 클릭 → 해당 번호 셀 강조 (컬러 표시, 나머지 회색)
├── 버튼 위 숫자 = 해당 색상 셀 개수
└── "전체 보기" 버튼 = 완성 컬러 미리보기
구현 방안:
- SVG 또는 Canvas 기반 인터랙티브 도안
- 각 셀에 data-label 속성 부여
- 팔레트 버튼 클릭 시 CSS class 토글로 하이라이트
- 완전한 standalone HTML (CDN 없이 동작)
고객 가치: - 어떤 색이 많이 필요한지 미리 파악 → 물감 구매 계획 가능 - 복잡한 영역(셀이 밀집된 곳)과 단순한 영역 구분 - 작업 진행도 체크 기능(칠한 셀 표시)으로 확장 가능
5.3 [MEDIUM] PostScript / SVG 중간 출력
전문 인쇄 업체나 레이저 커팅기 연동을 위한 벡터 포맷 추가:
color_by_number_complete.ps— PostScript (인쇄소 호환)color_by_number_complete.svg— SVG (Inkscape/Illustrator 편집 가능)- SVG 생성은 현재 PDF 코드와 동일한 좌표계 사용 가능
5.4 [MEDIUM] 고해상도 & 품질 개선
Lloyds 반복 최적화 (CVT): 씨앗점을 Centroidal Voronoi Tessellation으로 수렴시키면 셀 크기가 균등해져 번호 가독성이 향상된다.
// 현재: 랜덤 씨앗 → Voronoi 1회
// 개선: 씨앗 → Voronoi → 중심점 재계산 → 반복 (5회)
for (let iter = 0; iter < 5; iter++) {
const voronoi = delaunay.voronoi([0, 0, w, h]);
seeds = seeds.map((_, i) => voronoi.cellCentroid(i) ?? seeds[i]);
delaunay = Delaunay.from(seeds);
}
해상도 개선: - 현재 CPU: 최대 1000px → 2000px로 상향 (WebWorker 오프로드) - PDF 출력: A3 (420×297mm) 옵션 추가
5.5 [MEDIUM] WebWorker 비동기 처리
현재 브라우저 CPU 처리는 메인 스레드 블로킹이 발생한다:
// 현재: 메인 스레드에서 직접 처리
await renderVoronoi(url, s, outputRef.current);
// 개선: WebWorker로 오프로드
const worker = new Worker('/voronoi-worker.js');
worker.postMessage({ pixels, w, h, settings });
worker.onmessage = (e) => ctx.putImageData(e.data.imageData, 0, 0);
→ UI 반응성 유지, 대용량 이미지에서 브라우저 행 방지
5.6 [LOW] 수익화 모델
Tier 1 — 무료: - 최대 600셀, 24색, PNG 다운로드
Tier 2 — 기본 (월 $5): - 최대 3,000셀, 36색 - PDF 다운로드 - Number PNG
Tier 3 — 프로 (월 $15): - 최대 10,000셀 (GPU 가속) - 4K 고해상도 - 인터랙티브 HTML 채색 가이드 - SVG/PS 중간 파일 - 배치 처리 (여러 장 동시)
커스텀 팔레트: 특정 물감 브랜드(윈저뉴튼, 크레용, 아크릴)의 실제 색상 코드를 팔레트에 적용하는 기능. 팔레트 라이브러리 판매 모델 가능.
5.7 [LOW] 모바일 최적화
현재 데스크탑 중심 UI → 모바일 터치 친화적 개선: - 핀치줌으로 도안 확대 - 터치로 셀 색상 미리보기 - 갤러리 앱 직접 연동 (Web Share API)
6. 기술 아키텍처 다이어그램 (Version 1)
사용자 브라우저
│
├── [이미지 업로드]
│ ↓
├── [셀 < 3,000] ─────────────────────────────────────────┐
│ VoronoiConverter.tsx │
│ Canvas 2D (d3-delaunay) │ CPU
│ Sobel + CDF 샘플링 │ ~14~220ms
│ k-means++ (PbN 모드) │
│ │
├── [셀 ≥ 3,000 & PbN=OFF] ──────────────────────────────┤
│ POST https://hb5u.hyperbook.com/api/voronoi │ GPU
│ FastAPI + CuPy JFA (RTX 5060) │ ~95~140ms
│ 최대 4,000px 해상도 유지 │ (왕복)
│ │
└── [결과물]
├── "Download PNG" → voronoi.png (컬러 모자이크)
├── "Number" → voronoi_number.png (PbN, 픽셀)
└── "PDF" → voronoi_number.pdf (PbN, 벡터)
7. 주요 커밋 이력
| 커밋 | 날짜 | 내용 |
|---|---|---|
513feaf |
2026-06-28 | Initial commit |
9f55f89 |
2026-06-28 | 히어로 슬라이더 동작 수정 |
ef8cee2 |
2026-06-28 | HTTPS + 서브패스(/photo) 설정 |
d407b11 |
2026-06-29 | ROOPS 세션 종료 절차 가이드 |
9f9bab2 |
2026-06-29 | iOS H.264 Level 4.1 영상 수정 |
3d6b00c |
2026-06-29 | GPU-as-a-Service + JFA 구현 |
33aca99 |
2026-06-30 | Paint-by-Numbers 모드 구현 |
54849e7 |
2026-06-30 | Number 다운로드 버튼 추가 |
bc61ddf |
2026-06-30 | PDF 벡터 출력 (내부 PDF 연산자) |
8. 결론
Version 1은 두 가지 출력 형식(컬러 모자이크 + Paint-by-Numbers 도안), 세 가지 다운로드 옵션(PNG/Number/PDF), 그리고 CPU/GPU 자동 라우팅을 갖춘 완성된 시스템이다.
핵심 기술적 성취: 1. d3-delaunay + Sobel 엣지 샘플링 — 세부 영역에 셀이 집중되는 고품질 보로노이 생성 2. CuPy JFA GPU 가속 — 4K 이미지를 23ms에 처리 (CPU 대비 최대 350×) 3. k-means++ 팔레트 양자화 — 연속 색상을 N개 팔레트로 클러스터링 4. jsPDF 내부 PDF 연산자 직접 작성 — 선명한 벡터 출력 (API 한계 우회)
향후 인터랙티브 HTML 채색 가이드와 GPU PbN 가속이 추가되면, 자신의 사진으로 맞춤형 채색 키트를 만드는 서비스로서 수익화 기반이 갖춰질 것으로 판단된다.
참고 자료
- Rong, G., Tan, T. "Jump Flooding in GPU." I3D, 2006.
- Fortune, S. "A Sweepline Algorithm for Voronoi Diagrams." Algorithmica, 1987.
- MacQueen, J. "k-means Clustering." Berkeley Symposium, 1967.
- Arthur, D., Vassilvitskii, S. "k-means++: The Advantages of Careful Seeding." SODA, 2007.
- d3-delaunay (Mike Bostock): https://github.com/d3/d3-delaunay
- jsPDF: https://github.com/parallax/jsPDF
- CuPy: https://cupy.dev/
- NVIDIA JFA CUDA Reference, 2025.
