반응형

"Claude 3 API 활용: Vision (시각적 질문 응답)"에 이어, 이번 글에서는 Claude 3 API의 또 다른 중요 기능인 OCR(광학 문자 인식)에 대해 알아보겠습니다. OCR 기능을 통해 이미지 속 텍스트를 효율적으로 인식하고 추출하는 방법을 살펴보며, Claude 3 API가 제공하는 이미지 처리 능력의 다양한 측면을 더 깊이 이해할 수 있을 것입니다.


기본 설정

Claude 3 API를 활용하기 전에 필요한 기본 설정 과정을 살펴보겠습니다. 이 과정은 Claude 3 API와의 통신을 위한 준비 단계로, 필요한 패키지를 임포트 하고, API 키를 설정하여 API 클라이언트 인스턴스를 초기화하는 작업을 포함합니다. Python 기본 구성은 이전 글을 참고하시기 바랍니다.

Import Package

import anthropic
import os
import httpx
import base64
import imghdr
import io
from PIL import Image as PILImage
import matplotlib.pyplot as plt
from pathlib import Path

Set Variable

만약 API 키 생성 및 설정 방법에 대해 자세히 알고 싶으시다면, 이전 글에서 제공된 안내를 참고하시기 바랍니다. 이전 글에서는 Claude API 접근을 위한 계정 생성부터 API 키 발급 및 환경 변수 설정에 이르기까지의 과정을 자세히 설명하고 있습니다.

api_key = os.environ.get("ANTHROPIC_API_KEY")
client = anthropic.Anthropic(api_key=api_key)

Vision 처리 : OCR

Claude 3 API를 활용한 OCR(광학 문자 인식) 수행과 그 성능에 대해 다뤄보겠습니다. OCR 기능을 통해 이미지 내에 포함된 텍스트를 정확하게 인식하고 추출하는 과정을 살펴보면서, Claude 3 API의 이미지 처리 능력을 평가해 보겠습니다. 실제 예제를 통해 API의 성능을 측정하고, 다양한 유형의 이미지에서 텍스트를 얼마나 정확하고 효율적으로 인식할 수 있는지 알아보겠습니다.

Function

def load_and_encode_images(paths):
    encoded_images = []
    for path in paths:
        media_type = None  # 초기값은 None으로 설정

        # URL인 경우
        if path.startswith('http'):
            response = httpx.get(path)
            image_data = response.content
            
            # URL에서 파일 확장자 추출
            file_extension = Path(path).suffix.lower()
            if file_extension in ['.jpg', '.jpeg']:
                media_type = "image/jpeg"
            elif file_extension in ['.png']:
                media_type = "image/png"
            else:
                print(f"Unsupported media type for URL: {path}")
                continue  # 지원하지 않는 파일 형식인 경우, 건너뛰기
            
            response.close()
        
        # 로컬 파일 경로인 경우
        else:
            with open(path, "rb") as image_file:
                image_data = image_file.read()
                img_type = imghdr.what(None, h=image_data)
                
                if img_type == "jpeg":
                    media_type = "image/jpeg"
                elif img_type == "png":
                    media_type = "image/png"
                else:
                    print(f"Unsupported file format: {path}")
                    continue  # 지원하지 않는 파일 형식인 경우, 건너뛰기
        
        if media_type:
            # Base64 인코딩 후 저장
            encoded_image = base64.b64encode(image_data).decode("utf-8")
            encoded_images.append({
                "type": "image",
                "media_type": media_type,
                "data": encoded_image,
            })

    return encoded_images

def create_prompt_with_images(encoded_images, text):
    content = []
    for image in encoded_images:
        # 이미지 객체 구조를 API 요구사항에 맞게 조정
        content.append({
            "type": "image",
            "source": {
                "type": "base64",  # 'type' 키를 'base64'로 명시
                "media_type": image["media_type"],  # 이미지의 미디어 타입
                "data": image["data"],  # Base64 인코딩된 이미지 데이터
            },
        })
    content.append({
        "type": "text",
        "text": text,  # 질문 또는 설명 텍스트
    })
    
    prompts = [{
        "role": "user",
        "content": content,
    }]
    return prompts

def display_response(images, text):
    for image in images:
        img_data = base64.b64decode(image["data"])
        img = PILImage.open(io.BytesIO(img_data))
        plt.imshow(img)
        plt.axis('off')
        plt.show()
    print("Response:", text)

# 예시 사용
def chat_with_images_and_text(image_urls, text_question):
    # 이미지 인코딩
    encoded_images = load_and_encode_images(image_urls)

    # 질문 생성
    prompts = create_prompt_with_images(encoded_images, text_question)

    # Anthropics API를 통해 답변 받기 (가상의 함수, 실제 API 호출 구현 필요)
    response = client.messages.create(model="claude-3-opus-20240229", max_tokens=1024, messages=prompts)
    
    # 응답에서 텍스트 내용만 추출
    result_text = ""
    
    for content_block in response.content:
        if content_block.type == "text":
            result_text += content_block.text + "\n"

    # 답변 표시
    display_response(encoded_images, result_text)
    
    return response

OCR 간단한 사용 예

image_paths = ["asset/images/test_7.jpg"]
text_question = "이 사진에서 텍스트 추출해서 OCR 수행해줘"
response = chat_with_images_and_text(image_paths, text_question)

Output

esponse: 사진에서 추출한 텍스트는 다음과 같습니다:

김윤웅
Kim Yunwoong 
0123456789#$

위 텍스트를 보면 김윤웅이라는 이름과 Kim Yunwoong이라는 영문 이름, 그리고 숫자와 기호로 구성된 '0123456789#$' 문자열을 확인할 수 있습니다.

복잡한 표 형태에서 OCR 사용 예

Claude 3 API의 OCR 기능을 이용해 표에서 특정 정보를 추출하는 작업을 진행해 보겠습니다. 이미지 내 텍스트 추출이 흰색 배경에서의 간단한 글자 인식에서 우수한 성능을 보였다면, 이제는 더 복잡한 구조인 표 형태에서 원하는 데이터를 정확하게 찾아내는 능력을 테스트할 차례입니다.

image_paths = ["asset/images/test_8.png"]
text_question = "환자부담금액을 알려줘"
response = chat_with_images_and_text(image_paths, text_question)

Output

Response: 이 진료비 상세내역서에 따르면, 환자부담금액은 45,000원입니다. 상세 내역 중 "계" 행을 보면 환자부담금으로 45,000원이 기재되어 있습니다.

구조화된 데이터 형태로 변환

Claude 3 API의 능력 중 하나는 이미지 내의 텍스트를 분석하여 구조화된 데이터 형태로 변환하는 것입니다. 이를 통해, 이미지로 제공된 정보를 JSON 파일과 같은 형식으로 추출할 수 있습니다. 이러한 기능은 다양한 문서나 이미지에서 정보를 추출하고, 이를 프로그램이 처리하기 쉬운 형태로 변환하는 데 매우 유용합니다.

image_paths = ["asset/images/test_9.png"]
text_question = "이 레시피를 JSON 파일로 추출합니다"
response = chat_with_images_and_text(image_paths, text_question)

Output

Response: {
  "name": "Mom's Chicken Broccoli Stir Fry",
  "ingredients": [
    {
      "item": "small onion",
      "amount": 1,
      "unit": null,
      "preparation": "diced"
    },
    {
      "item": "garlic",
      "amount": 2,
      "unit": "cloves",
      "preparation": "minced"     
    },
    {
      "item": "broccoli",
      "amount": 2,
      "unit": "bunches",
      "preparation": "chopped"
    },
    {
      "item": "chicken breasts",
      "amount": 2,
      "unit": null,
      "preparation": "diced"
    },
    {
      "item": "baby carrots",
      "amount": 12,
      "unit": null,
      "preparation": "chopped"
    },
    {
      "item": "ginger-garlic paste",
      "amount": null,
      "unit": null,
      "preparation": null
    },
    {
      "item": "salt",
      "amount": null,
      "unit": null,
      "preparation": null  
    },
    {
      "item": "lemon juice",
      "amount": null,
      "unit": null,
      "preparation": null
    }
  ],
  "instructions": [
    {
      "step": 1,
      "text": "Vaghar spices in oil, then sauté onion and garlic"
    },
    {
      "step": 2,
      "text": "Add broccoli, carrots and chicken. Sauté, stirring constantly. Do not cover"
    },
    {
      "step": 3, 
      "text": "Add salt, lemon juice, and ginger-garlic paste to taste"
    },
    {
      "step": 4,
      "text": "Cook until tender but still firm"
    }
  ]
}

Claude 3 API를 활용한 OCR 기능은 매우 유용하나, 모든 경우에 완벽하게 작동하지는 않습니다. 예를 들어, 에어팟 일련번호를 추출하려고 했을 때 잘못된 텍스트가 반환되었습니다.

image_paths = ["asset/images/test_10.png"]
text_question = "S/No를 알려줘"
response = chat_with_images_and_text(image_paths, text_question)

Output

Response: The serial number (S/No) shown on the Apple AirPods case in the image is X0VY12C3X4B0x.

또 다른 예로, 수산시장 사진에서 항목과 가격을 추출하여 JSON 형식으로 출력하려고 했을 때 정확하지 않은 데이터가 반환될 수 있습니다.

image_paths = ["asset/images/test_11.png"]
text_question = "Extract the items and prices from a fish market photo and output them in JSON."
response = chat_with_images_and_text(image_paths, text_question)

Output

Response: {
  "items": [
    {
      "name": "Whole Black Cod",
      "price": 15.99
    },
    {
      "name": "Bronzino",
      "price": 14.99
    },
    {
      "name": "Rainbow Trout",
      "price": 11.99
    }
  ]
}

The image shows a display of fresh fish at a fish market. There are handwritten signs in front of the fish indicating the name and price per pound for three types of fish:
1. Fresh Whole Black Cod at $15.99/lb
2. Fresh Bronzino at $14.99/lb 
3. Fresh Rainbow Trout at $11.99/lb
The fish are arranged on a bed of ice, with some greenery added as garnish. A worker at the fish market can be seen in the background.

여기서 실제 가격이 18.99인데 15.99로 잘못 반환된 경우가 있습니다. (이 이미지의 경우 Gemini에서는 정상적으로 인식) 이러한 오류는 Claude 3 API가 이미지 내의 복잡한 텍스트를 정확하게 인식하고 해석하는 데 한계가 있음을 보여줍니다. 특히, Gemini와 같은 다른 AI 모델과 비교했을 때 Claude 3가 모든 분야에서 더 뛰어나다고 단정 지을 수는 없을 것 같습니다.


Claude 3 API의 Vision 기능을 활용한 이미지 분석과 텍스트 추출은 많은 가능성을 열어주지만, 모든 상황에서 완벽한 결과를 보장하지는 않습니다. 특정 조건이나 복잡한 이미지에서는 예상과 다른 결과가 나올 수 있습니다. 하지만 GPT, Gemini 외에도 이러한 놀라운 성능을 보이는 멀티모달 모델이 등장하는 것은 매우 고무적입니다.

반응형