ETOOS, KAKAO Vision API(OCR)로 시간만들기

재현·2022년 1월 17일
0

ETOOS

목록 보기
6/6
post-thumbnail

왜?

ETOOS247 새학기가 시작되면서
새로운 프로그램이 여럿 생겼는데 그 중 하나인
'데일리플래너', 꽤 시간이 많이 드는 일을 소개하고자한다.

등원 시 학생들이 한 장씩 챙겨서 TO-DO List 를 적고
하원 시 제출 후 다음 날 분출받는 시스템인데
스캔(1분) - 네이밍(20분) - 분류(10분) - 배분(10분)
대략, 40분 씩 걸리는 일을 데일리 업무로 진행해야했다.

3일 정도 하다 구조적으로 업무가 비효율적이라 느껴서
네이밍하는 과정에 OCR 기술을 이용해보기로 했다.

결과

우선, 학원 업무 시스템에 적용은 실패했다.
사유는 크게 두 가지로 나눠볼 수 있겠다.

  1. 설득
  2. 미흡한 기술 적용

설득

Before

After

기존 사진 구조로 테스트했을 때, 이름 index가 위치한 position이 파일마다 달라질 수 있는 변수가 많았다.
예를 들어, "D - ???" 칸을 채우는 학생도 있고 아닌 학생도 있고, 중간에 낙서하는 학생도 있어서
변수를 최소화하고자 이름 적는 칸을 맨 왼쪽으로 옮겨야 함을 생각했다.

원장님에게 설득하는 과정에서 당연하게 OK가 나오리라 생각했는데 오산이었다.
왜 이 기술을 적용해야하는지, 왜 기존 이름 칸의 위치를 옮겨야하는지 등
고착화된 기존 시스템에 변동이 생기는 것을 꺼리는 상황이었다.

이를 해결하기 위해선
확실한 결과를 근거로 상대를 설득해야하는데
이를 충족시키지 못 했다고 생각한다.

미흡한 기술 적용

위 두 번째 사진 구조로 총 3가지 버전의 "정재현" 을 테스트 해보았을 때,
"이름/저A재료", "DATE", "n" 이런 식으로 결과가 도출됐다.

예외처리를 통해

  • 공란을 A 로 인식
  • "이름: " 같이 하나의 box 로 인식
  • 영어로 시작
  • 숫자로 시작
  • 한 글자

result[index] 위치 값을 변경해서 index position 을 찾고,
더 디테일하게 예외처리하여 어떻게든 "이름 값" 을 뽑아낼 수 있다고 생각하는데
현재로서는 진행하는 프로젝트가 의미가 없기에 멈춘다!

배운 점

"개발은 도구다"

개발자들 사이에서 유명한 예시가 있다.

'느린 속도의 엘레베이터 민원을 어떻게 처리할 것인가?'

  1. 향상된 기술 적용
  2. 문 앞에 거울을 붙임

더 디테일하게 이름을 뽑아내려면 어떻게 해야할까?

  1. 빅데이터 처리를 통해 이름 같은 이름을 뽑아낼 확률을 높임
  2. 등원 시 이름을 정자로 적으라고 주기적으로 공지

현재로서 2번이 답이라고 생각했다.
개발자는 개발이라는 도구를 사용해 문제를 해결할 수도 있는 사람이지
개발만을 이용해 문제를 해결하는 사람이라고 생각하지 않는다.

"설득의 중요성"

당연하게 생각한 나와 다르게 상대방은 정반대로 생각할 수도 있다.
상대방을 설득하기 위해서 어떤 근거로 어떻게 대화를 할 것 인가?

상대방이 거부감이 들 수도 있게 무턱대고
'프로토타입 개선을 위해 구조를 개선해야합니다'라며 성급하게 말하기 보단
간단한 이유를 대며 상대방이 편하게 느끼게 하는 건 어땠을까?

또한 나 스스로에게 입증할 만큼 정확한 결과가 도출되지 못 했고
스스로 입증하지 못 했기 때문에 상대방을 설득할 수 없다고 생각했다.

그래서

총 3일 정도 소요된 시간이 나에겐 아주 값진 시간이었다.
새로운 API 를 적용해봤고, 오랜만에 Python 을 이용했고
그리고 시선의 확장이 너무 좋았다.

어떤 개발자가 되어야 하는가? 개발자는 무엇을 하는 존재일까?
에 대해 고민해본 시간에 감사하다!

문제 해결 과정 중

  1. 한 번으로 고정된 작동
    기존 KAKAO Vision API(OCR) 예제는
    sys를 통해 image_path, API_KEY 를 받아
    하나의 코드 : 하나의 이미지 를 테스트할 수 있었는데
    매개변수를 새로 정의, def main() 부분을 for 문 처리하여
    여러 장의 사진을 한 번의 입력으로 처리할 수 있게 했다.

  2. kakao_oce_resize() > 이미지 화질 저하
    resize 중 LIMIT_BYTE = 1024x1024 값으로 선언되어
    화질이 깨지는 현상이 있었는데 위 변수를 2048x2048 로 정정하여
    화질 개선을 유도했다.

  3. 양면으로 스캔된 하나의 파일
    앞, 뒤 부분이 각자 하나의 파일로 인식되어
    플래너 당 2개의 파일이 생성되었는데
    for 문 간격 처리를 통해 "이름 값" 이 위치한 앞 면만 index로 정의하여
    뒷 장은 새로 네이밍된 앞 장 값에 (1)를 붙여주는 식으로 해결

Code

import json
import cv2
from dotenv import load_dotenv
import requests

import os

from sklearn.feature_extraction import image

LIMIT_PX = 2048
LIMIT_BYTE = 2048*2048  # 1MB / 기존 LIMIT_BYTE 값은 1024*1024 였는데 픽셀이 너무 깨져서 2048로 수정했는데 크기가 1mb 를 넘지 않아 적용된듯 함
LIMIT_BOX = 40


def kakao_ocr_resize(image_path: str):
    """
    ocr detect/recognize api helper
    ocr api의 제약사항이 넘어서는 이미지는 요청 이전에 전처리가 필요.

    pixel 제약사항 초과: resize
    용량 제약사항 초과  : 다른 포맷으로 압축, 이미지 분할 등의 처리 필요. (예제에서 제공하지 않음)

    :param image_path: 이미지파일 경로
    :return:
    """
    

    image = cv2.imread(image_path)
    height, width, _ = image.shape

    if LIMIT_PX < height or LIMIT_PX < width:
        ratio = float(LIMIT_PX) / max(height, width)
        image = cv2.resize(image, None, fx=ratio, fy=ratio)
        height, width, _ = height, width, _ = image.shape

        cv2.imwrite(image_path, image)

        return image_path
    return image_path


def kakao_ocr(image_path: str, appkey: str):
    """
    OCR api request example
    :param image_path: 이미지파일 경로
    :param appkey: 카카오 앱 REST API 키
    """
    API_URL = 'https://dapi.kakao.com/v2/vision/text/ocr'


    headers = {'Authorization': 'KakaoAK {}'.format(appkey)}

    image = cv2.imread(image_path)
    jpeg_image = cv2.imencode(".jpg", image)[1]
    data = jpeg_image.tobytes()


    return requests.post(API_URL, headers=headers, files={"image": data})


def main():

    # 보안상 API_KEY 를 환경변수 처리해주었다.
    load_dotenv()
    API_KEY = os.environ.get("API_KEY")
    appkey = API_KEY

    # image folder
    image_folder_path = "/Users/heyon/Desktop/JAY/Jay-Thomas-code/Project/ETOOS_OCR/image"
    image_folder_list = os.listdir(image_folder_path)
    # 현재 image_folder 배열형태 - 순서대로 나열되어있는 형태
    image_folder_list.sort()    
    
    # 이름 변경된 사진이 저장될 폴더
    saved_image_folder_path = "/Users/heyon/Desktop/JAY/Jay-Thomas-code/Project/ETOOS_OCR/saved_image"  

    # 파일 네이밍 시 접두사 부분에 날짜를 적어야했으므로 date 를 input 받아 파일명에 추가
    date = input("이름 앞에 붙을 날짜를 입력해주세요(ex. 20220701) : " )

	# .DS_Store 예외처리, index 간격처리
    for image in range(1, len(image_folder_list), 2) : 
        
        # image file 의 경로가 들어와야함
        image_path = f"{image_folder_path}/{image_folder_list[image]}"  
        print(os.listdir(image_folder_path))
        print(f"image_path : {image_path}")
        resize_impath = kakao_ocr_resize(image_path)
        
        if resize_impath is not None:
            image_path = resize_impath

        output = kakao_ocr(image_path, appkey).json()

        # 5번 째 property 가 이름 value을 갖고있음
        OCR_result = output['result'][5] 

        print("[OCR] output:\n{}\n".format(json.dumps(output, sort_keys=True, indent=2, ensure_ascii=False)))
        # OCR_result.json file 중 0번째 index 가 이름 value
        student_name = OCR_result['recognition_words'][0]   
        print(student_name)

        # 첫 번째 파일의 이름을 json 파일에서 추출한 student_name 으로 선언하고
        # 이어서 두 번째 파일 이름을 첫 번째 파일에서 (1)을 더한 이름으로 선언
        os.rename((f"{image_folder_path}/{image_folder_list[image]}"), f"{saved_image_folder_path}/{date} {student_name}.jpg")
        os.rename((f"{image_folder_path}/{image_folder_list[image+1]}"), f"{saved_image_folder_path}/{date} {student_name}(1).jpg")


if __name__ == "__main__":
    main()
profile
Do Work As We & Respect 🙆🏾 🙆🏻‍♂️ 🙆🏻‍♀️ 🙆‍♀️

0개의 댓글