이 노트에 대하여

이 노트는 전자책이 없는 노학자들의 책을 직접 잘라 스캔해 귀로 듣기 위해 시작한 OCR→EPUB 파이프라인이 어떻게 진화했는지, 그리고 OCR 엔진을 ‘모델’과 ‘도구’ 두 겹으로 나눠 보게 된 과정을 묶는다.

히스토리

  • [2026-06-07 Sun 04:45] @junghan — 이거 내보내자!
  • [2026-06-06 Sat 13:03] 생성 — 세 엔진(MinerU/DeepSeek-OCR/PaddleOCR-VL) 비교와 ‘모델 layer vs 도구 layer’ 구분 정리
  • [2026-06-06 Sat 13:35] 네 번째 엔진 PP-StructureV3(도구) 측정 — ‘도구 대 도구’ 빈칸 채움. MinerU 도구 유일성이 깨지고, 띄어쓰기 붕괴가 한국어 린터(kime)와 만나는 지점 발견
  • [2026-06-06 Sat 14:00] 다섯째 GLM-OCR 측정 — 공개 벤치마크 1등(SOTA)이 한국어 스캔책에선 꼴찌(한자 환각). ‘점수표 ≠ 내 책’ 확인
  • [2026-06-06 Sat 14:30] 진짜 답 — PaddleOCR-VL을 ‘도구’로 세우니 모델+도구 동시(본문·띄어쓰기 + asset·수식·구조), 앞선 세 약점(MinerU 환각·PP 띄어쓰기·GLM 한국어) 동시 회피. 같은 모델도 모델/도구 쓰임으로 갈림. 다섯 엔진을 격리 서빙으로 올려 재현·확장 가능하게 정리

관련메타

관련노트

OCR 파이프라인의 여정 — 스캔책을 귀로 듣기까지

[2026-06-07 Sun 04:49]

왜 책을 잘라서 스캔했나

내가 모으는 책 다섯 권 중 번역서 한 권을 빼면, 모두 내가 존경하는 한국 노학자의 저술이다. 《물질 생명 인간》, 《최무영 교수의 물리학 강의》, 《자연철학 강의》… 평생을 한 분야에 부은 노학자의 책에는 전자책이 없다. 종이로만 남아 있다.

나는 책을 눈으로 읽기보다 귀로 듣는다. 그래서 이 책들을 듣고 싶었다. 방법은 하나뿐이었다 — 제본 업체를 찾아가 책등을 잘라내고, 낱장을 스캔해 PDF로 들여왔다. 거기서부터가 시작이다. 스캔한 PDF를 깨끗한 EPUB으로 바꾸는 일.

막다른 길에서 세 번 갈아엎다

처음엔 tesseract 한국어 OCR을 썼다. 결과는 차마 못 쓸 정도였다. 답답한 마음에 아주 무식한 방법을 택했다 — GPT에게 통째로 부탁했더니 Opus를 여러 개 병렬로 띄워, 페이지 그림을 눈으로 보고 받아 적게 했다. 놀랍게도 품질은 나쁘지 않았다. 그러나 이건 너무 어리석은(비싸고 느린) 방법이었다. 사람 대신 거대한 모델에게 한 글자씩 베껴 쓰게 한 셈이니까.

그래서 제대로 찾아보기 시작했고, 갈아엎기를 거듭했다. 깃 로그가 그 속도를 증언한다.

  • 2026-05-31 — Opus vision 전사 파이프라인(scanpdf2org). 동시에 “결국 핵심은 Org→EPUB”이라고 못 박음.
  • 2026-06-02 — 하루 사이에 두 번 갈아엎은 분기점. tesseract를 버리고 marker(surya OCR)를 들였다가, 같은 날 marker마저 은퇴시키고 MinerU VLM 에 정착. 이날 scanbook 스킬이 태어남.
  • 2026-06-03DeepSeek-OCR 을 둘째 엔진으로. 한 엔진을 믿지 않고 여러 엔진을 같은 잣대로 재는 멀티엔진 평가가 시작됨.
  • 2026-06-04 — 페이지에서 잘린 문단을 도로 봉합하는 노하우와 구조 복원기를 쌓으며 다섯 권을 본격 진행.
  • 2026-06-06PaddleOCR-VL 합류. 세 엔진을 한자리에 세움.

변하지 않는 중심: Org와 ox-epub

OCR 엔진을 세 번 갈아엎는 동안에도 파이프라인의 중심은 한 번도 바뀌지 않았다. Org 파일 이다. 엔진이 무엇이든 결국 깨끗한 .org 로 모이고, 거기서 EPUB이 나온다. 그래서 Org→EPUB 변환기인 ox-epub 패키지(개인 포크)도 이 파이프라인에 맞춰 다시 손봤다. EPUB3 네이티브 출력에 epubcheck 무결점(0/0/0).

PDF ─(MinerU)→ md + 구조 ─(mineru2org.py)→ 깨끗한 .org ─(ox-epub)→ EPUB

엔진은 갈아끼우는 부품이고, Org가 골격이다. 이 구분이 다음 깨달음의 씨앗이었다.

세 엔진을 같은 책으로 재다

《물리학 강의》 5강 열일곱 쪽을, 세 엔진에 똑같이 먹였다. 후처리(교정·구조 복원)는 어차피 우리가 결정론적으로 소유하니, 엔진은 우리가 못 고치는 부분 — 날것의 글자·이미지·수식 충실도 로만 줄 세웠다.

항목MinerUDeepSeek-OCRPaddleOCR-VL
인명 ‘톰슨’✗ 톈슨 + 환각✓ 정확 5/5✗ 네 갈래로 흩어짐
인명 ‘돌턴’✓ 정확✗ ‘돌탄’ 4/5✓ 정확
’슈뢰딩거’✗ ‘슈퇴당거’
수식(LaTeX)✗ 평문화
이미지 픽셀✓ 유일(크롭 추출)✗ 위치만✗ 없음
구조 라벨✓ 가장 풍부△ 일부✗ 본문에 섞임
본문 가독성△ 환각 잦음✓ 깨끗✓ 깨끗

점수표만 보면 “어느 게 1등이냐”를 묻고 싶어진다. 그런데 표를 한참 보다가, 더 중요한 건 등수가 아니라 분류 라는 걸 깨달았다.

깨달음: OCR 엔진은 ‘모델’과 ‘도구’ 두 겹이다

엔진은 한 덩어리가 아니라 두 겹이다.

  • 모델 — 페이지 그림을 글자로 바꾸는 인식기. MinerU2.5-VLM, DeepSeek-OCR, PaddleOCR-VL이 여기서 경쟁한다.
  • 도구 — 레이아웃을 잡고, 그림을 픽셀째 오려내고, 수식을 LaTeX로 인식하고, 각주·쪽번호·캡션을 구조 라벨로 분리하는 파이프라인.

이 구분으로 보면 오래 품었던 질문 — “MinerU가 의미가 있나?” — 의 답이 갈린다. 모델로서 MinerU는 약하다. 흔한 단어도 깨먹고, 없는 글자(mosaic, 한자 )를 지어내는 환각까지 있다. 그런데 도구로서 MinerU는 압도적이다. 그림을 실제 이미지로 오려 주고, 수식을 LaTeX로 주고, 문서 구조를 라벨로 분리해 주는 건 순수 OCR 모델이 원천적으로 못 하는 일이다.

그래서 결론은 “모델 직결이 낫다”가 아니다. 그림과 수식이 많은 책에서는 모델만으로는 픽셀도 수식도 못 얻는다. MinerU를 도구(골격)로 두고, 글자가 더 정확한 모델을 교정용 오라클로 덧대는 조합 이 맞다.

뜻밖의 선물: 엔진 불일치가 곧 오독 탐지기

세 엔진을 나란히 놓으니 묘한 규칙이 보였다. 서로 다른 단어에서 깨진다. 톰슨은 MinerU·PaddleOCR이 틀리고 DeepSeek이 맞혔다. 돌턴은 DeepSeek이 틀리고 둘이 맞혔다. 슈뢰딩거는 PaddleOCR만 틀렸다.

뒤집으면 — 세 엔진이 서로 다르게 읽은 지점이 곧 OCR 오독 의심점 이다. 지금까지 사람이 책을 정독하며 손으로 찾던 인명·고유어 오독을, 세 엔진의 다수결로 기계가 후보를 던질 수 있다는 뜻이다. 한 엔진이 같은 실수를 반복하면 못 잡지만, 엔진 사이의 불일치 는 그 자체로 신호가 된다.

빈칸을 채우다 — 도구는 둘이 되었다

마지막 빈칸은 “도구 대 도구”였다. 앞의 비교는 모델끼리였지, PaddleOCR의 도구 레이어인 PP-StructureV3 는 아직이었다. 같은 날 GPU 노드에 그것을 올려, 같은 열일곱 쪽을 먹였다.

답은 분명했다. PP-StructureV3도 진짜 도구였다. 이미지를 아홉 장 그대로 오려내고(MinerU와 같은 수), 수식을 인라인까지 LaTeX로 잡고, 레이아웃·캡션·쪽번호를 구조 라벨로 분리했다. MinerU 도구의 유일성은 깨졌다 — 이제 골격을 맡길 도구가 둘이다.

다만 공짜가 아니었다. PP-StructureV3의 한국어 글자 모델은 띄어쓰기를 뭉갰다. 공백 비율 0.12(정상은 0.21 안팎)로, 단어가 죄다 붙어 나왔다. 그런데 이 약점이 뜻밖의 자리로 이어졌다. 띄어쓰기를 도로 세우는 일은 형태소 분석의 몫이고, 나는 이미 그걸 하려고 한국어 린터(textlint + 형태소 분석 kime)를 짓고 있었다. 스캔책 파이프라인과 한국어 린터, 따로 가던 두 작업이 여기서 만났다.

마지막으로, 네 엔진이 인명 ‘톰슨’을 저마다 다르게 — 톈슨, 톰슨, 톱슨, 통슨 — 읽었다. 네 개의 서로 다른 오답은 곧 네 배 더 또렷한 신호다. 어느 엔진도 혼자선 못 잡는 오독을, 넷의 불일치가 가리킨다.

SOTA의 역설 — 1등이 내 책에선 꼴찌

하나가 더 남아 있었다. GLM-OCR. 문서 인식 공개 벤치마크에서 다섯 중 1등, 그러니까 세계 최고로 알려진 모델이다. 당연히 기대했다.

그런데 같은 열일곱 쪽을 먹이자, 한국어가 무너졌다. 톰슨은 ‘통속’이, 데카르트는 ‘대칭르트’가, 볼츠만은 ‘불초만’이 되었다. 한국어 글자를 닮은 중국 한자를 지어내기까지 했다(磊, 嚣, 螽). 띄어쓰기만은 멀쩡했지만, 글자가 그 모양이니 소용없다. 다섯 중 꼴찌였다.

교훈은 분명하다. 점수표는 내 책을 모른다. 영어와 표·그림 위주로 매긴 벤치마크의 1등이, 노학자의 한국어 산문 앞에서는 가장 약했다. 그래서 나는 매번 “한 챕터를 직접 재 보고 정한다”는 규칙을 고집한다. 예측은 번번이 틀렸고, 측정만이 맞았다.

진짜 답 — 같은 모델도 ‘모델’로 쓸 때와 ‘도구’로 쓸 때가 다르다

다섯 엔진을 줄 세우고 났을 때 한 가지가 걸렸다. PaddleOCR-VL은 이미 ‘모델’로 재 봤다. 본문은 깨끗했지만 그림도 수식도 주지 않았다. 그런데 바로 그 PaddleOCR-VL을 도구로 — 레이아웃 파이프라인의 글자 엔진으로 — 끼워 다시 세울 수 있었다.

같은 모델, 다른 자리. 결과가 갈렸다. 이번엔 본문을 제대로 읽고 띄어쓰기를 지키면서도, 그림을 픽셀째 오려내고 수식을 LaTeX로, 각주·소제목을 구조로 분리했다. 앞서 본 약점들 — MinerU의 환각, PP-StructureV3의 뭉개진 띄어쓰기, GLM의 무너진 한국어 — 을 한꺼번에 비켜갔다.

그러니까 “어느 엔진이 최고냐”라는 질문 자체가 반쪽이었다. 같은 엔진도 어떻게 세우느냐 가 절반을 결정했다. 오늘의 답은 PaddleOCR-VL을 도구로 세우는 것이다. 느린 게 흠이고, 인명 같은 고유어는 여전히 다른 엔진의 눈을 빌려 고쳐야 한다. 그래도 골격으로 삼을 단 하나를 꼽으라면, 오늘은 이것이다.

그리고 이 ‘오늘의 답’은 박제가 아니다. 다섯 엔진을 각자 격리된 자리에 올려 두어, 언제든 같은 책으로 다시 재고 새 엔진을 더 세울 수 있게 해 두었다. 더 나은 엔진이 나오면 답은 또 바뀔 것이다. 중요한 건 답을 고정하는 게 아니라, 답을 다시 잴 수 있는 자리를 갖추는 일이었다.

맺으며

세 번 갈아엎고 다섯 엔진을 지났다. 도구는 부품이고, Org가 골격이다. 그 골격 위에서 노학자의 목소리를 귀로 듣는 날이 가까워졌다.

관련 노트

  • memex-kb 리포의 scanbook 스킬과 NEXT.md 에 측정 원자료와 엔진별 상세가 남아 있다.