logo

OCR

광학 문자 인식 Optical Character Recognition

  • 과정
    • 이미지 전처리
    • 텍스트 위치 추정 → 문자 분리 / 텍스트 추출
    • 문자 인식
    • 후처리
  • 텍스트 추출의 어려움
    • 다양한 크기, 색상, 방향 등
    • 여러 개의 글자를 하나의 단어로 인식하는 문제
    • 하나의 단어를 여러 개의 글자로 인식하는 문제
  • 다른 이미지 인식 과제와 달리 문자의 종류는 제한되어 있음
  • 별도로 개발할 필요 없이 오픈소스 라이브러리만으로 해결할 수 있음

PaddleOCR

  • 중국 Baidu에서 개발한 딥러닝 기반 OCR 라이브러리
  • 한국어 포함 100개 이상의 언어 지원
  • OmniDocBench v1.6에서 96.3% 정확도
  • 가장 성능이 높은 오픈소스 라이브러리 중에 하나

PaddleOCR의 구조

  • 모델 하나로 페이지 전체를 처리하면 속도가 느리고, 레이아웃으로 인한 환각이 생기기 쉬움
  • 레이아웃 분석 + 요소별 인식으로 나누어 2단계 처리

PaddleOCR이 문서를 레이아웃 분석과 요소별 인식으로 나누어 처리하는 구조

레이아웃 분석

  • 문서 페이지에서 텍스트, 표, 수식, 차트 같은 영역을 찾고, 각 영역의 종류와 읽는 순서를 예측
  • RT-DETR 기반 객체 탐지 모델
    • 문서 안의 요소 위치를 bounding box로 찾음
    • 요소 유형을 분류함: text, table, formula, chart 등
  • Pointer Network
    • 탐지된 요소들의 읽는 순서를 예측함
    • 6개 Transformer layer 사용하여, 요소 간 상대적 순서를 N x N 행렬로 계산
    • 이후 deterministic decoding으로 최종 reading order를 복원

PaddleOCR의 레이아웃 분석과 reading order 예측 구조

요소별 인식 VLM

  • 대부분 이미지 처리 모델은 입력을 고정된 크기로 변환 → 텍스트가 찌그러짐
  • NaViT(Native Resolution ViT): 이미지를 텍스트처럼 길이가 가변적인 데이터로 취급하는 비전 트랜스포머 모델
  • 이미지 처리 결과를 소형 언어 모델 ERNIE에 입력하여 텍스트 생성

NaViT와 ERNIE를 사용한 요소별 인식 VLM 구조

훈련

  • 텍스트: 약 2천만 개 이상
    • 109개 언어 포함
    • 인쇄체, 손글씨, 스캔 문서, 예술적 폰트 등 포함
  • 표: 500만 개 이상
  • 수식: 7백만개 이상 LaTeX 생성 수식 및 손글씨
  • 차트: 80만 개 이상

PaddleOCR 실습

설치:

!pip install paddlepaddle==3.2.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/
!pip install "paddleocr[all]"
  • colab에서 설치 후 restart session

불러오기:

from paddleocr import PaddleOCR

ocr = PaddleOCR(
    use_doc_orientation_classify=False,  # 문서 방향 분류 사용 안 함
    use_doc_unwarping=False,  # 문서 왜곡 보정 사용 안 함
    use_textline_orientation=False,  # 텍스트 라인 방향 분류 사용 안 함
    engine="paddle",
    lang="korean",  # 언어: 한국어 (영어는 "en")
)

PaddleOCR 실습

  • 이미지 처리: 텍스트 감지 임계값을 낮추려면 text_det_thresh 인자를 사용(기본값 0.3)
result = ocr.predict(input="blueprint.jpg")

결과:

res = result[0]  # 첫 번째 이미지 결과
res["rec_texts"]  # 인식된 텍스트
res["rec_polys"]  # 텍스트별 폴리곤(다각형)의 꼭지점 좌표
res["rec_boxes"]  # 텍스트별 박스의 왼쪽 위, 오른쪽 아래 꼭지점 좌표

시각화:

res.save_to_img("output")

PaddleOCR 수동 시각화

from PIL import Image, ImageDraw, ImageFont

try:
    # 한글 출력을 위해 나눔고딕과 같은 한글 폰트가 필요합니다.
    font = ImageFont.truetype("NanumGothic.ttf", 20)
except IOError:
    print("NanumGothic.ttf 폰트를 찾을 수 없습니다. 기본 폰트를 사용합니다.")
    font = ImageFont.load_default()

img = Image.open("blueprint.jpg").convert("RGB")
draw = ImageDraw.Draw(img)


for text, poly in zip(res["rec_texts"], res["rec_polys"]):
    # 텍스트를 감싸는 다각형(폴리곤)을 파란색으로 그립니다.
    # PIL의 polygon은 (x1,y1), (x2,y2)... 형태의 튜플 리스트를 인자로 받습니다.
    draw.polygon([tuple(p) for p in poly], outline="#0000FF", width=2)

    # 인식된 텍스트를 폴리곤의 첫 번째 꼭짓점 위치에 빨간색으로 씁니다.
    # 텍스트가 박스 안쪽에 그려지도록 위치를 약간 조정할 수 있습니다.
    text_position = tuple(poly[0])
    pos = (text_position[0] + 5, text_position[1] + 5)
    draw.text(pos, text, fill="#FF0000", font=font)

img

PDF 변환

설치:

pip install pdf2image
mamba install -y poppler  # mamba 또는 conda 사용

변환:

import pdf2image
import numpy as np

pages = pdf2image.convert_from_path("교안.pdf")  # PDF에서 페이지들을 이미지 배열로
page_arrays = [np.array(p) for p in pages]
result = ocr.predict(input=page_arrays)  # 텍스트 추출
Previous
자세 추정