| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- 마이그레이션
- Kotlin
- javascript
- python
- php
- contextBridge
- github actions
- 백엔드
- electron
- next.js
- 도메인설계
- Vite
- 보안
- 소셜로그인
- React
- 온디바이스AI
- Android
- 프론트엔드
- 아키텍처
- 인증
- 배포
- sqlite
- 크롤링
- JWT
- REST API
- playwright
- 메일자동화
- FastAPI
- 상태관리
- typescript
- Today
- Total
HM소프트
OCR + 오버레이 렌더링 엔진 만들기 — 이미지 텍스트 교체 도구 (1) 본문
브라우저 OCR 엔진을 인식과 렌더링 두 단계로 분리하고, 로컬 모델·클라우드·경량 엔진 폴백 사슬과 다중 전처리 앙상블로 한글 인식 정확도를 높인 과정을 정리한다. 픽셀에서 글자색·획 두께를 추정하고 원본을 깎지 않는 비파괴 오버레이로 새 글자를 덮어 PNG로 내보내는 이미지 텍스트 교체 도구 설계를 다룬다.
OCR과 오버레이 렌더링 엔진을 만든 과정을 정리한다.

시리즈를 시작하며
이미지 안에 박혀 있는 글자를, 원본 디자인은 그대로 둔 채 다른 내용으로 바꿔주는 웹 도구를 만들었다. 이미지를 올리면 OCR로 글자를 읽어 위치를 잡고, 그 자리에 새 텍스트를 덮어 그린 다음, 결과를 PNG로 내보낸다.
세 편으로 나눠 기록한다.
- (이 글) OCR + 오버레이 텍스트 교체 엔진
- 스텝 위저드 UX와 전역 상태 설계
- 실시간 미리보기와 html2canvas 내보내기
스택은 Vite + React + TypeScript, 별도 백엔드 없이 브라우저 안에서 도는 클라이언트 앱이다.
방향 전환: 핵심은 "텍스트 교체 엔진"
원래는 다른 용도의 페이지 에디터로 시작했다. 그런데 만들다 보니 진짜 가치 있는 부분은 "이미지 위 텍스트를 자연스럽게 갈아끼우는 엔진"에 있었다. 그래서 도구의 정체성을 이미지 텍스트 교체 도구로 전면 전환했다. 군더더기 기능을 걷어내고 엔진에 집중했다.
엔진의 두 단계: 인식과 렌더링
텍스트 교체를 두 단계로 나눴다.
- 인식(OCR): 이미지에서 글자와 그 위치(바운딩 박스)를 찾는다.
- 오버레이 렌더링: 원본 픽셀을 직접 고치는 대신, 인식된 글자 영역 위에 새 텍스트를 덮어 그린다.
핵심 결정: 원본을 깎지 않는다 (오버레이 방식)
가장 중요한 설계 선택이었다. 이미지 속 글자를 바꾸는 순진한 방법은 "원본에서 글자를 지우고 새 글자를 그리는" 것이다. 하지만 이러면 글자 뒤의 배경·그라데이션·질감이 망가진다. 글자를 지운 자리를 완벽히 복원하는 건 어렵다.
그래서 픽셀을 수정하는 대신 오버레이로 갔다. 원본 이미지는 건드리지 않고, 그 위에 레이어를 얹어 새 텍스트를 배치한다.
[원본 이미지] ← 절대 수정 안 함 (배경·질감 보존)
└─[오버레이 레이어] ← 인식된 위치에 새 텍스트를 덮어 그림
이 방식의 장점이 명확했다.
- 배경 보존: 원본을 안 깎으니 질감·그라데이션이 그대로 산다.
- 되돌리기/수정이 쉬움: 오버레이만 바꾸면 되니, 원본은 언제나 깨끗하다.
- 비파괴 편집: 몇 번을 고쳐도 원본 품질이 떨어지지 않는다.
엔진을 전면 개선하면서 OCR 인식 정확도를 끌어올리고, 렌더링을 이 오버레이 방식으로 굳혔다.
OCR 결과를 오버레이로 옮기기
OCR은 글자와 함께 위치(박스)를 준다. 이 박스 정보를 그대로 오버레이의 텍스트 박스 위치로 쓴다.
interface OcrBox {
text: string;
x: number; y: number; width: number; height: number;
}
// 인식 결과 → 편집 가능한 오버레이 노드로
function toOverlayNodes(boxes: OcrBox[]): OverlayNode[] {
return boxes.map((b, i) => ({
id: `node-${i}`,
x: b.x, y: b.y, width: b.width, height: b.height,
original: b.text,
replacement: b.text, // 처음엔 원문과 동일, 사용자가 수정
}));
}
사용자가 replacement만 바꾸면, 원래 글자 위치에 새 글자가 덮인다. 원문(original)은 그대로 들고 있어, 무엇을 무엇으로 바꿨는지 추적할 수 있다.
정리하며
1편의 핵심은 비파괴 오버레이 방식이라는 한 가지 결정이다.
- 원본 픽셀을 수정하지 않고 그 위에 덮어 그린다 → 배경·질감 보존, 되돌리기 자유.
- OCR은 글자+위치를 주고, 그 위치를 오버레이 노드로 옮긴다.
- 인식(OCR)과 렌더링(오버레이)을 분리해두면, 둘을 각각 교체·개선하기 쉽다.
다음 2편에서는 이 엔진을 감싸는 스텝 위저드 UX와 전역 상태 설계를 다룬다.
'기술 개발일지' 카테고리의 다른 글
| 실시간 미리보기 + html2canvas 이미지 내보내기 — 텍스트 교체 도구 (3) (0) | 2026.06.12 |
|---|---|
| 스텝 위저드 UX와 전역 상태 설계 — 이미지 텍스트 교체 도구 (2) (0) | 2026.06.12 |
| Vite + React 빌드·배포 트러블슈팅 — 장부 관리 앱 (2) (0) | 2026.06.12 |
| 에디토리얼 스타일 UI와 브랜드 아이덴티티 설계 — 장부 관리 앱 (1) (0) | 2026.06.12 |
| 프론트/백 경계 정리와 Docker 배포 — 대량 메일 자동화 (3) (0) | 2026.06.11 |