한글 스캔 OCR 품질 개선 가이드: 정확도 높이는 스캐너 설정·이미지 전처리·엔진 튜닝 완벽 정리

이 글의 목적은 한글 문서의 스캔부터 OCR까지 전 과정을 표준화하여 실무에서 재현 가능한 높은 인식률을 달성하도록 돕는 것이다.

1. 스캔 단계 최적화(하드웨어·드라이버)

1.1 해상도(DPI) 기준

일반 본문 텍스트는 300 DPI가 기준이며, 소제목·각주·7pt 이하 소형 글꼴이 많다면 400~600 DPI를 권장한다. 200 DPI는 데이터 입력용 초벌 인식에는 가능하나 교정 비용이 증가하므로 권장하지 않는다. 컬러 사진이 많은 보고서는 400 DPI 컬러 모드로 스캔 후 전처리에서 배경 억제를 수행하는 것이 안정적이다.

DPI권장 용도장점주의사항
300일반 본문 중심 문서속도·용량 균형7pt 이하 텍스트는 누락 가능
400작은 글씨·각주 다수획 단절 감소용량 증가
600법령 사본·팩스 품질 저하 원본재인식·후처리 여유저가 스캐너는 노이즈 증가

1.2 색상 모드

텍스트 중심 문서는 그레이스케일이 최적이다. 컬러는 배경 얼룩과 하이라이터 색이 임계값을 교란할 수 있다. 도표·컬러 구분이 중요한 문서는 컬러로 보존하되 전처리에서 채널 분리 후 전용 이진화를 적용한다.

1.3 파일 포맷·압축

단일 페이지는 TIFF(G4/팩스) 또는 무손실 PNG를 권장한다. 다중 페이지는 PDF 컨테이너로 저장하되 내부 이미지는 무손실 또는 저손실로 유지한다. JPEG 고압축은 문자 경계가 손상되어 에러율이 상승한다.

1.4 급지·선명도

ADF 사용 시 이중 급지 검출을 활성화한다. 샤프닝은 과도하면 가장자리에 링잉이 생기므로 스캐너 내장 샤프닝은 Low로 설정한다. 자동 크롭·빈 페이지 제거는 OCR 전 레이아웃 판단을 방해할 수 있으므로 스캐너 단계에서는 끄고 전처리에서 일괄 적용한다.

주의 : 스캔 단계에서의 손실은 전처리로 완전히 복구되지 않는다. DPI·색상·압축을 보수적으로 설정하는 것이 총 비용을 줄인다.

2. 이미지 전처리 표준 파이프라인

2.1 권장 순서

  1. 해상도 정규화(메타데이터 보정 포함)하다.
  2. 자동 크롭 및 여백 균질화하다.
  3. 기울기(스큐) 보정 및 원근 왜곡(디와프) 교정하다.
  4. 배경 균질화와 그림자 제거하다.
  5. 적응형 이진화(영역별) 혹은 그레이스케일 대비 확장하다.
  6. 노이즈 제거(소금·후추, 점 잡음), 얇은 획 보정하다.
  7. 선 긋기·표 격자 분리 및 텍스트 마스크 분리하다.

2.2 ImageMagick 예시

# 1) 400DPI 가정, 스큐 보정+대비 확장+적응 이진화 magick input.tif -density 400 -units PixelsPerInch ^ -deskew 40%% -trim +repage ^ -colorspace Gray -contrast-stretch 0.5%% ^ -filter Gaussian -define convolve:scale='!' ^ -adaptive-sharpen 0x1 ^ -adaptive-threshold 15x15+10% ^ -type bilevel output_clean.tif
2) 그림자 제거용 배경 추정
magick input.tif -colorspace Gray ^
( +clone -blur 0x25 ) -compose Divide -composite ^
-contrast-stretch 0.5%% output_bgfix.tif

2.3 OpenCV 파이썬 전처리 예시

import cv2 import numpy as np
img = cv2.imread('input.png', cv2.IMREAD_GRAYSCALE)

스큐 추정(허프 변환 기반)
edges = cv2.Canny(img, 50, 150)
lines = cv2.HoughLines(edges, 1, np.pi/180, 200)
angles = []
if lines is not None:
for rho,theta in lines[:,0]:
angle = (theta - np.pi/2) * 180/np.pi
if -20 < angle < 20: angles.append(angle)
skew = np.median(angles) if angles else 0.0

회전 보정
(h, w) = img.shape[:2]
M = cv2.getRotationMatrix2D((w//2, h//2), skew, 1.0)
rot = cv2.warpAffine(img, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

적응형 이진화 + 노이즈 제거
thr = cv2.adaptiveThreshold(rot, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 31, 10)
den = cv2.medianBlur(thr, 3)

cv2.imwrite('output_clean.png', den)

2.4 얇은 획·저대비 글꼴 보정

명조체 얇은 세리프가 끊어지는 경우 팽창 연산을 약하게 적용한다.

# 이진 이미지에서 미세 팽창 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,1)) fix = cv2.morphologyEx(den, cv2.MORPH_DILATE, kernel, iterations=1) 

2.5 컬러 하이라이터·볼펜 겹침 처리

HSV 채널에서 색역 마스크로 하이라이터를 분리한 뒤 V 채널 기준으로 재이진화하면 텍스트 보존율이 높다.

# 컬러 문서에서 노란 하이라이터 제거 imgc = cv2.imread('input_color.png') hsv = cv2.cvtColor(imgc, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv, (20, 50, 50), (40, 255, 255)) # yellow range nohl = cv2.inpaint(imgc, mask, 3, cv2.INPAINT_TELEA) gray = cv2.cvtColor(nohl, cv2.COLOR_BGR2GRAY) thr = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,31,8) 
주의 : 배경 균질화 없이 이진화를 먼저 수행하면 얼룩이 텍스트로 오인식된다. 그림자 제거→적응 이진화 순서를 유지한다.

3. OCR 엔진 설정(한글 중심)

3.1 Tesseract 권장 옵션

# 일반 문서 tesseract output_clean.png out -l kor+eng --oem 1 --psm 6
단일 열, 일정 행간 보고서
tesseract output_clean.png out -l kor+eng --oem 1 --psm 4

양식(테이블) 라인은 별도 처리 후 인식
tesseract form_clean.png out -l kor --oem 1 --psm 6
  • --oem 1은 LSTM 기반 엔진을 사용하여 한글 결합 규칙 처리에 유리하다.
  • --psm은 레이아웃 가정을 의미하며, 불일치 시 오인식이 급증한다. 표 영역은 라인 제거 후 6, 단일 열 문서는 4가 안정적이다.

3.2 사용자 사전·금칙어

도메인 용어가 많은 경우 wordlist를 준비하면 교정 비용이 급감한다.

# custom words 예: '유해화학물질', '용출시험', '취급자' echo -e "유해화학물질\n용출시험\n취급자" > kor.user-words
Tesseract 호출 시
tesseract input.png out -l kor --user-words kor.user-words --oem 1 --psm 6

3.3 한컴 OCR 활용 팁

  • 언어는 한국어+영어 병행 선택한다. 약어·단위가 많은 기술 문서에서 효율이 높다.
  • 페이지 구획을 수동으로 교정하여 본문·머리말·각주를 분리한다.
  • 표 인식은 격자 유지 옵션을 켜고, 배경색이 있는 셀은 전처리에서 채도 약화 후 인식한다.
  • 수식은 OCR 제외로 설정하고 LaTeX 변환이나 이미지 보존을 선택한다.

4. 글꼴·지면 특성별 전략

상황문제해결
명조체(얇은 세리프)획 단절·점 잡음미세 팽창, 400~600 DPI, 저압축
고딕체문자 붙음약한 침식 연산, 대비 과도 상승 주의
세로쓰기 섞임레이아웃 혼동영역 분리 후 별도 인식, --psm 6
낡은 사본배경 얼룩·번짐배경 보정→적응 이진화→형태학적 개복원

5. 표·도표·수식 처리

5.1 표

격자선은 OCR에 방해가 되므로 라인 검출로 분리 저장한다. 텍스트 레이어만 인식하여 CSV로 내보내고, 원본 표 이미지는 PDF에 겹쳐 둔다.

# 수평·수직선 제거(개념) lines = detect_lines(rot) # 허프변환 기반 mask_text = remove(lines, rot) # 선 제거 마스크 ocr(mask_text) # 텍스트만 OCR 

5.2 도표

차트 영역은 OCR 대상에서 제외하고 캡션만 OCR한다. 차트 데이터는 별도 추출 도구를 사용한다.

5.3 수식

수식은 일반 OCR 정확도가 낮다. 수식 영역을 인식 제외하거나 전용 엔진으로 분리 처리한다. 보고서에서는 수식을 이미지로 보존하고 LaTeX 원문을 주석으로 관리한다.

6. 저품질 원본별 실무 해결책

6.1 팩스·흐린 복사본

  • 400~600 DPI 그레이스케일로 재스캔한다.
  • 대비 확장 후 국소 대비를 살리는 CLAHE를 적용한다.
# CLAHE 예시 clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) enh = clahe.apply(rot) 

6.2 스마트폰 촬영 이미지

  • 퍼스펙티브 변환으로 평면화한다.
  • 그림자 제거 후 적응 이진화한다.
  • 손떨림 블러는 위너 필터보다 재촬영이 비용 대비 효율적이다.

6.3 접힘·구김·책자 중앙 곡률

텍스트 행을 추적하여 곡률 모델로 펴주는 디와프 알고리즘을 적용한다. 불가피하면 페이지를 분책하여 평면화 스캔한다.

주의 : 스마트폰 촬영은 조명·왜곡 변수로 인해 배치 자동화가 어렵다. 대량 처리 프로젝트는 스캐너 기반으로 표준화한다.

7. 교정(Proofing) 자동화

7.1 언어 모델·사전 결합

OCR 결과에 사용자 사전과 전문용어 리스트를 적용하여 치환·태깅한다. 단위(㎖, ㎍, ppm 등)는 정규식으로 보정한다.

# 간단한 단위 정규화 예시 import re text = open('out.txt', 'r', encoding='utf-8').read() text = re.sub(r'\b(mm|㎜)\b', 'mm', text) text = re.sub(r'\b(㎖|ml)\b', 'mL', text) open('out_norm.txt', 'w', encoding='utf-8').write(text) 

7.2 검수 뷰어 전략

  • 원본 이미지와 OCR 텍스트를 좌우 분할로 동기 스크롤한다.
  • 확신도(confidence) 하이라이트로 교정 범위를 좁힌다.
  • 표·각주·머리말을 별도 탭으로 검토한다.

7.3 CER·WER 지표 산출

# CER 계산 예시 import editdistance gt = open('gt.txt', 'r', encoding='utf-8').read() pred = open('out_norm.txt', 'r', encoding='utf-8').read() cer = editdistance.eval(list(gt), list(pred)) / max(1, len(gt)) print(f'CER: {cer:.3%}') 

8. 배치 워크플로우 설계

8.1 폴더 구조

project/ 00_raw_scan/ # 원본 스캔 01_preproc/ # 전처리 결과 02_ocr/ # OCR 텍스트 03_review/ # 교정본 99_logs/ # 처리 로그·성능지표 

8.2 파일명 규칙

YYYYMMDD_부서_문서명_p###.tif 형식을 사용하면 정렬·추적이 쉽다. 페이지 번호는 3자리 고정한다.

8.3 자동화 스크립트 체크포인트

  1. 입력 유효성 검사(해상도·색공간 메타 확인)하다.
  2. 전처리 파라미터 로그를 남긴다.
  3. OCR 엔진 버전·옵션을 결과 헤더에 기록한다.
  4. CER 표본 측정을 주기적으로 수행한다.

9. 보안·개인정보 대응

  • 주민등록번호·연락처 패턴은 인식 직후 마스킹한다.
  • 클라우드 업로드 전 메타데이터를 제거한다.
  • 교정용 협업 폴더는 읽기 전용 사본을 배포한다.

10. 문제 원인별 의사결정 트리

증상가능 원인조치
받침 오인식DPI 낮음, 이진화 과도400 DPI 재스캔, 적응 임계값 재설정
띄어쓰기 붕괴스큐·왜곡디와프·스큐 보정 후 재인식
표 인식 누락격자 영향선 제거 후 텍스트만 인식
영문 약어 깨짐언어 설정 단일kor+eng 병행, 사용자 단어 입력
파일 용량 과대고DPI 컬러그레이스케일 전환, 무손실 압축 재저장

11. 현장 체크리스트

항목체크 방법빈도
DPI·색상 모드샘플 1장 메타 확인매 배치
스큐 보정문단 경사 각도 < 0.5°매 배치
노이즈 레벨빈 여백에 점 잡음 0~1개/㎠매 배치
OCR 옵션--oem, --psm 로그 저장매 배치
CER 샘플표본 1페이지 측정 ≤ 1.0%주간
개인정보 마스킹정규식 검출 누락 0건매 배치

12. 튜닝 레시피 모음

12.1 저조도 촬영본

magick input.jpg -auto-level -contrast-stretch 1%% -colorspace Gray ^ -blur 0x1 -adaptive-threshold 17x17+8% out.png 

12.2 스캔 그림자(책자 가운데)

magick input.tif -colorspace Gray ( +clone -blur 0x35 ) -compose Divide -composite ^ -contrast-stretch 0.5%% -adaptive-threshold 15x15+10% out.tif 

12.3 표 우선 문서

# 선 검출 후 텍스트만 OCR, 표는 좌표로 CSV화(개념 스니펫) grid, textmask = detect_grid_and_text(img) ocr_text = ocr(textmask) cells = extract_cells(grid) export_csv(cells, ocr_text) 
주의 : 전처리 파라미터는 문서군별로 저장하고 재사용한다. 동일한 스캐너·용지·글꼴이면 같은 레시피로 반복 가능하다.

FAQ

스캔 해상도는 몇 DPI가 최적인가?

일반 문서는 300 DPI가 기준이다. 작은 글씨·각주가 많거나 품질이 낮은 원본은 400~600 DPI가 유리하다. 200 DPI는 교정 비용이 급증하므로 권장하지 않는다.

컬러와 그레이스케일 중 무엇이 유리한가?

텍스트 중심이면 그레이스케일이 유리하다. 컬러 마커가 많다면 컬러로 보존 후 채널 분리·하이라이터 제거 전처리를 수행한다.

스마트폰 촬영본도 고정 품질을 낼 수 있는가?

가능하나 배치 자동화가 어렵다. 평면화·그림자 제거·적응 이진화로 상당 부분 개선되나 대량 처리 프로젝트는 스캐너 기반 표준화를 권장한다.

한글과 영어가 섞인 보고서에서 실수 줄이는 방법은?

엔진 언어를 한국어+영어로 병행하고 도메인 용어를 사용자 단어로 등록한다. 영문 약어가 많은 경우 --psm 6으로 단락 가정을 단순화한다.

표와 수식 처리는 어떻게 분리하나?

표는 라인 제거 후 텍스트만 인식하고 셀 좌표를 CSV로 저장한다. 수식은 일반 OCR에서 오류가 많으므로 영역 제외 또는 전용 엔진으로 분리한다.

정확도 평가는 어떻게 수치화하나?

CER·WER를 사용한다. 표본 페이지를 선정해 기준문자와의 편집거리로 계산하고 주간 리포트에 추세를 기록한다.