이미지에 OCR 결과물 출력하기

2020. 8. 31. 10:26Data & AI/ComputerVision

상용 OCR 서비스를 이용하면서 이미지에 OCR결과물을 표현해야 할 필요가 생겼다. 이때의 과정을 되돌아보면서 이슈들을 정리해보았다.

OpenCV를 이용해 OCR 결과물 이미지에 출력하기

NCP OCR API 활용법

API 요청 header나 body는 OCR API 명세에 자세히 설명되어있다. 이를 참고하면서 활용법을 익히도록 합시다.

sample code

import requests
import time
import json

API_URL = 'URL'

headers = {
    'X-OCR-SECRET': 'secret key',
    'Content-Type': 'multipart/form-data'
}

files = [
    ('file', open('image file path','rb'))
]
data = {
    'message': {
        "images":[{"format":"jpg","name":"demo"}],
        "requestId":"guide-demo",
        "version":"V2",
        "timestamp":time.time()
    }
}
response = requests.post(API_URL, headers=headers, data=data, files = files)

# response에서 OCR 결과물만 선별
fields = response['images'].values[0].get('fields')

OpenCV를 이용해 결과물 출력하기

OpenCV를 이용해 이미지에 결과물 출력하기

OpenCV를 사용 자면서 자주 사용했던 method들인데 자꾸 까먹는다... 그래서 좀 정리해 보았다.

이미지에 bounding box 출력하기

OpenCV의 polylines() 메소드를 통해 이미지에 bounding box를 그릴 수 있다.

cv2.polylines(img, pts, isClosed, color, [thickness, lineType, shift])

parameter description

  • img – Image.
  • pts – Array of polygonal curves.
  • isClosed – Flag indicating whether the drawn polylines are closed or not. If they are closed, the function draws a line from the last vertex of each curve to its first vertex.
  • color – Polyline color.
  • thickness – Thickness of the polyline edges.
  • lineType – Type of the line segments. See the [line()](https://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html#void line(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness, int lineType, int shift)) description.
  • shift – Number of fractional bits in the vertex coordinates.

이미지에 OCR 결과물 출력하기

putText() 메소드를 통해 이미지에 텍스트를 출력할 수 있다.

cv2.putText(img, text, org, fontFace, fontScale, color, [thickness, lineType, bottomLeftOrigin])

parameter description

  • img – Image.

  • text – Text string to be drawn.

  • org – Bottom-left corner of the text string in the image.

  • fontFace – Font type. One of FONT_HERSHEY_SIMPLEX, FONT_HERSHEY_PLAIN, FONT_HERSHEY_DUPLEX, FONT_HERSHEY_COMPLEX, FONT_HERSHEY_TRIPLEX, FONT_HERSHEY_COMPLEX_SMALL, FONT_HERSHEY_SCRIPT_SIMPLEX, or FONT_HERSHEY_SCRIPT_COMPLEX, where each of the font ID’s can be combined with FONT_ITALIC to get the slanted letters.

  • fontScale – Font scale factor that is multiplied by the font-specific base size.

  • color – Text color.

  • thickness – Thickness of the lines used to draw a text.

  • lineType – Line type. See the line for details.

  • bottomLeftOrigin – When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner.

sample code

# 필요 라이브러리 불러오기
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 이미지 불러오기
args_image = "Original image file(.jpg / .png)"
img = cv2.imread(args_image)

for field in fields:
    verticies = field.get('boundingPoly').get('vertices')
    # bounding box의 좌표값 np.array 객체로 재구성하기
    box = np.array([tuple(v.values()) for v in verticies], np.int32)
    # bounding box 영역 이미지에 출력하기
    img = cv2.polylines(img, [box], True, (0,255,0), 2)
    # ocr결과 텍스트 bounding box 상단에 출력하기
    img = cv2.putText(img, field.get('inferText'), tuple(box[0]), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0,0,0), 1)

# 이미지 출력하기    
plt.imshow(img)
plt.show()

한글 텍스트가 제대로 나오지 않는다....

Pillow를 활용해 이미지에 한글 출력하기

OpenCV를 활용하는 방법을 적용하면 한글 텍스트가 제대로 출력되지 않는다. 하지만, Pillow를 활용하면 이 문제를 해결이 가능하다.

Pillow를 활용해 이미지 핸들링하기

pillow를 이용해 이미지를 핸들링하기 위해 별도의 과정이 필요하다.

이미지 불러오기

OpenCV의 imread()로 불러온 이미지를 PIL.Image.fromarray()로 불러오도록 하자

PIL.Image.fromarray() 사용법은 아래와 같다.

PIL.Image.fromarray(obj, mode=None)

자세한 내용은 Pillow 공식문서를 참고하도록 하자.

한글 폰트 불러오기

폰트는 PIL.ImageFont.truetype()으로 트루타입 폰트를 불러올 수 있다.

PIL.ImageFont.truetype(font=None, size=10, index=0, encoding='', layout_engine=None)

Pillow 공식문서

Image Draw 객체 생성

pillow에서는 이미지에 무언가 출력하기 위해 Draw객체를 생성해야 한다.

PIL.ImageDraw.Draw(im, mode=None)

Draw객체와 메소드에 대한 자세한 내용은 Pillow 공식문서를 참고하도록 합시다

이미지에 bounding box 출력하기

sample code

# 라이브러리 불러오기
from PIL import ImageFont, ImageDraw, Image

# 이미지 불러오기
args_image2 = "Original image file(.jpg / .png)"
img2 = cv2.imread(args_image2)
img_pil = Image.fromarray(img2)

# 폰트 불러오기
fontpath = "fonts/gulim.ttc"
font = ImageFont.truetype(fontpath, 15)

# ImageDraw 객체 생성
draw = ImageDraw.Draw(img_pil)

for field in fields:
    verticies = field.get('boundingPoly').get('vertices')
    box = [tuple(v.values()) for v in verticies]
    # bounding box 영역 마스킹하기
    draw.polygon(box, outline=(0,255,0), fill=(255,255,255))
    # ocr결과 텍스트(한글) bounding box 영역에 출력하기
    draw.text(box[0], field.get('inferText'), font=font, fill=(0,0,0))

# 이미지 출력하기
plt.imshow(img_pil)
plt.show()

이제야 원하는 결과를 얻을 수 있었다.

References

'Data & AI > ComputerVision' 카테고리의 다른 글

WSL에서 OpenCV 컴파일하기  (0) 2020.08.20