← 블로그 홈

OCR 기술과 Upstage Document OCR API 활용법

OCR이란?

OCR이란?

OCR(Optical Character Recognition, 광학 문자 인식)은 이미지나 스캔된 문서에서 텍스트를 자동으로 인식하고 추출하는 기술입니다. 종이 문서를 디지털화하거나, 이미지 속 텍스트를 편집 가능한 형태로 변환할 때 필수적인 기술입니다.

OCR의 주요 활용 분야

1. 문서 디지털화

  • 종이 문서의 전자화
  • 고문서 및 아카이브 자료 보존
  • 법률 문서 관리 시스템

2. 자동화 업무 프로세스

  • 영수증 및 청구서 처리
  • 신분증 정보 추출
  • 계약서 데이터 추출

3. 모바일 애플리케이션

  • 텍스트 번역 앱
  • 명함 정보 추출
  • 실시간 문서 스캔

Upstage Document OCR API 소개

Upstage는 한국의 AI 기업으로, 고성능 OCR API를 제공합니다. 특히 한국어 문서 처리에 뛰어난 성능을 보입니다.

주요 특징

  • 높은 정확도: 한국어 문서에 최적화된 인식 성능
  • 다양한 문서 형태 지원: PDF, 이미지 파일 등
  • 구조화된 출력: JSON 형태의 체계적인 결과 제공
  • RESTful API: 간단한 HTTP 요청으로 이용 가능

Upstage OCR API 사용법

1. API 키 발급

먼저 Upstage Console에서 계정을 생성하고 API 키를 발급받습니다.

2. Python으로 API 호출하기

import requests
import base64
import json

# API 설정
API_URL = "https://api.upstage.ai/v1/document-ai/ocr"
API_KEY = "your_api_key_here"

def encode_image_to_base64(image_path):
    """이미지 파일을 base64로 인코딩"""
    with open(image_path, "rb") as image_file:
        encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
    return encoded_string

def extract_text_with_upstage_ocr(image_path):
    """Upstage OCR API를 사용하여 텍스트 추출"""
    
    # 이미지를 base64로 인코딩
    encoded_image = encode_image_to_base64(image_path)
    
    # API 요청 헤더
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    }
    
    # API 요청 데이터
    data = {
        "document": encoded_image
    }
    
    try:
        # API 호출
        response = requests.post(API_URL, headers=headers, json=data)
        response.raise_for_status()
        
        result = response.json()
        return result
        
    except requests.exceptions.RequestException as e:
        print(f"API 요청 오류: {e}")
        return None

# 사용 예제
if __name__ == "__main__":
    image_path = "sample_document.jpg"
    result = extract_text_with_upstage_ocr(image_path)
    
    if result:
        print("OCR 결과:")
        print(json.dumps(result, indent=2, ensure_ascii=False))

3. cURL을 사용한 API 호출

# 이미지를 base64로 인코딩
IMAGE_BASE64=$(base64 -w 0 sample_document.jpg)

# API 호출
curl -X POST "https://api.upstage.ai/v1/document-ai/ocr" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "document": "'$IMAGE_BASE64'"
  }'

4. JavaScript/Node.js 예제

const fs = require('fs');
const axios = require('axios');

async function extractTextWithUpstageOCR(imagePath) {
    try {
        // 이미지를 base64로 인코딩
        const imageBuffer = fs.readFileSync(imagePath);
        const encodedImage = imageBuffer.toString('base64');
        
        // API 요청
        const response = await axios.post('https://api.upstage.ai/v1/document-ai/ocr', {
            document: encodedImage
        }, {
            headers: {
                'Authorization': `Bearer ${process.env.UPSTAGE_API_KEY}`,
                'Content-Type': 'application/json'
            }
        });
        
        return response.data;
        
    } catch (error) {
        console.error('OCR API 오류:', error.response?.data || error.message);
        return null;
    }
}

// 사용 예제
extractTextWithUpstageOCR('sample_document.jpg')
    .then(result => {
        if (result) {
            console.log('OCR 결과:', JSON.stringify(result, null, 2));
        }
    });

API 응답 형태

Upstage OCR API는 다음과 같은 구조화된 JSON 응답을 제공합니다:

{
  "text": "전체 추출된 텍스트",
  "pages": [
    {
      "page": 1,
      "text": "페이지별 텍스트",
      "bboxes": [
        {
          "text": "개별 텍스트 블록",
          "coordinates": {
            "x": 100,
            "y": 200,
            "width": 300,
            "height": 50
          }
        }
      ]
    }
  ]
}

실전 활용 예제: 영수증 데이터 추출

import re
from datetime import datetime

def parse_receipt_data(ocr_result):
    """OCR 결과에서 영수증 정보 파싱"""
    
    text = ocr_result.get('text', '')
    
    # 정규표현식으로 주요 정보 추출
    patterns = {
        'store_name': r'^([^\n]+)',  # 첫 번째 줄을 매장명으로 가정
        'total_amount': r'합계[:\s]*([0-9,]+)원?',
        'date': r'(\d{4}[-./]\d{2}[-./]\d{2})',
        'phone': r'(\d{3}-\d{3,4}-\d{4})'
    }
    
    parsed_data = {}
    
    for key, pattern in patterns.items():
        match = re.search(pattern, text, re.MULTILINE)
        if match:
            parsed_data[key] = match.group(1).strip()
    
    return parsed_data

# 사용 예제
def process_receipt_image(image_path):
    """영수증 이미지 처리 전체 프로세스"""
    
    # OCR 수행
    ocr_result = extract_text_with_upstage_ocr(image_path)
    
    if not ocr_result:
        return None
    
    # 데이터 파싱
    receipt_data = parse_receipt_data(ocr_result)
    
    print("=== 영수증 정보 ===")
    print(f"매장명: {receipt_data.get('store_name', '미확인')}")
    print(f"총 금액: {receipt_data.get('total_amount', '미확인')}원")
    print(f"날짜: {receipt_data.get('date', '미확인')}")
    print(f"전화번호: {receipt_data.get('phone', '미확인')}")
    
    return receipt_data

# 실행
receipt_info = process_receipt_image('receipt.jpg')

OCR 정확도 향상 팁

1. 이미지 전처리

  • 해상도 최적화: 300 DPI 이상 권장
  • 노이즈 제거: 가우시안 블러 또는 미디언 필터 적용
  • 대비 개선: 히스토그램 평활화
import cv2
import numpy as np

def preprocess_image(image_path):
    """OCR 정확도 향상을 위한 이미지 전처리"""
    
    # 이미지 로드
    img = cv2.imread(image_path)
    
    # 그레이스케일 변환
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 노이즈 제거
    denoised = cv2.medianBlur(gray, 3)
    
    # 대비 개선
    enhanced = cv2.equalizeHist(denoised)
    
    # 이진화
    _, binary = cv2.threshold(enhanced, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    # 전처리된 이미지 저장
    processed_path = image_path.replace('.jpg', '_processed.jpg')
    cv2.imwrite(processed_path, binary)
    
    return processed_path

2. 문서 정렬 및 회전 보정

def correct_skew(image_path):
    """문서 기울어짐 보정"""
    import cv2
    import numpy as np
    
    img = cv2.imread(image_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 엣지 검출
    edges = cv2.Canny(gray, 75, 200, apertureSize=3, L2gradient=True)
    
    # 직선 검출
    lines = cv2.HoughLinesP(edges, 1, np.pi/180, 30, minLineLength=20, maxLineGap=5)
    
    if lines is not None:
        angles = []
        for line in lines:
            x1, y1, x2, y2 = line[0]
            angle = np.arctan2(y2 - y1, x2 - x1) * 180 / np.pi
            angles.append(angle)
        
        # 중간값으로 회전 각도 결정
        rotation_angle = np.median(angles)
        
        # 이미지 회전
        h, w = img.shape[:2]
        center = (w // 2, h // 2)
        M = cv2.getRotationMatrix2D(center, rotation_angle, 1.0)
        rotated = cv2.warpAffine(img, M, (w, h), flags=cv2.INTER_CUBIC)
        
        corrected_path = image_path.replace('.jpg', '_corrected.jpg')
        cv2.imwrite(corrected_path, rotated)
        return corrected_path
    
    return image_path

에러 처리 및 모니터링

import logging
from functools import wraps
import time

# 로깅 설정
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def retry_on_failure(max_retries=3, delay=1):
    """API 호출 실패 시 재시도 데코레이터"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    logger.warning(f"시도 {attempt + 1} 실패: {e}")
                    if attempt == max_retries - 1:
                        raise
                    time.sleep(delay * (2 ** attempt))  # 지수적 백오프
            return None
        return wrapper
    return decorator

@retry_on_failure(max_retries=3)
def robust_ocr_extraction(image_path):
    """안정적인 OCR 추출 함수"""
    try:
        # 이미지 전처리
        processed_path = preprocess_image(image_path)
        
        # OCR 수행
        result = extract_text_with_upstage_ocr(processed_path)
        
        # 결과 검증
        if not result or not result.get('text'):
            raise ValueError("OCR 결과가 비어있습니다")
        
        logger.info(f"OCR 성공: {len(result['text'])} 문자 추출")
        return result
        
    except Exception as e:
        logger.error(f"OCR 처리 오류: {e}")
        raise

비용 최적화 전략

1. 이미지 크기 최적화

def optimize_image_size(image_path, max_size=2048):
    """API 호출 비용 절약을 위한 이미지 크기 최적화"""
    import cv2
    
    img = cv2.imread(image_path)
    h, w = img.shape[:2]
    
    if max(h, w) > max_size:
        if h > w:
            new_h = max_size
            new_w = int(w * (max_size / h))
        else:
            new_w = max_size
            new_h = int(h * (max_size / w))
        
        resized = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_AREA)
        optimized_path = image_path.replace('.jpg', '_optimized.jpg')
        cv2.imwrite(optimized_path, resized, [cv2.IMWRITE_JPEG_QUALITY, 95])
        return optimized_path
    
    return image_path

2. 캐싱 시스템

import hashlib
import pickle
import os

class OCRCache:
    """OCR 결과 캐싱 시스템"""
    
    def __init__(self, cache_dir='./ocr_cache'):
        self.cache_dir = cache_dir
        os.makedirs(cache_dir, exist_ok=True)
    
    def _get_image_hash(self, image_path):
        """이미지 해시값 생성"""
        with open(image_path, 'rb') as f:
            content = f.read()
        return hashlib.md5(content).hexdigest()
    
    def get_cached_result(self, image_path):
        """캐시된 결과 조회"""
        image_hash = self._get_image_hash(image_path)
        cache_file = os.path.join(self.cache_dir, f"{image_hash}.pkl")
        
        if os.path.exists(cache_file):
            with open(cache_file, 'rb') as f:
                return pickle.load(f)
        return None
    
    def cache_result(self, image_path, result):
        """결과 캐싱"""
        image_hash = self._get_image_hash(image_path)
        cache_file = os.path.join(self.cache_dir, f"{image_hash}.pkl")
        
        with open(cache_file, 'wb') as f:
            pickle.dump(result, f)

# 사용 예제
cache = OCRCache()

def cached_ocr_extraction(image_path):
    """캐시를 활용한 OCR 추출"""
    
    # 캐시 확인
    cached_result = cache.get_cached_result(image_path)
    if cached_result:
        logger.info("캐시된 결과 사용")
        return cached_result
    
    # OCR 수행
    result = extract_text_with_upstage_ocr(image_path)
    
    # 결과 캐싱
    if result:
        cache.cache_result(image_path, result)
    
    return result

결론

OCR 기술은 디지털 트랜스포메이션의 핵심 요소로, 다양한 업무 자동화에 활용되고 있습니다. Upstage OCR API는 특히 한국어 문서 처리에 뛰어난 성능을 제공하며, 간단한 API 호출만으로 고품질의 텍스트 추출이 가능합니다.

성공적인 OCR 시스템 구축을 위해서는:

  • 이미지 전처리를 통한 품질 개선
  • 에러 처리재시도 로직 구현
  • 캐싱 시스템을 통한 비용 최적화
  • 모니터링을 통한 성능 관리

이러한 요소들을 고려하여 안정적이고 효율적인 OCR 서비스를 구축할 수 있습니다.


이 포스트가 도움이 되셨다면 댓글로 피드백을 남겨주세요. OCR 관련 궁금한 점이 있으시면 언제든 문의하세요!

이 글을 공유해보세요!