FastAPI를 이용하여 서버에서 이미지를 받아와서 영수증 재료를 처리하는 코드를 만들어보자!!

FastAPI?

FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트에 기초한 Python3.6+의 API를 빌드하기 위한 웹 프레임워크입니다.

주요 특징으로:

  • 빠름: (Starlette과 Pydantic 덕분에) NodeJS 및 Go와 대등할 정도로 매우 높은 성능. 사용 가능한 가장 빠른 파이썬 프레임워크 중 하나.

빠른 코드 작성: 약 200%에서 300%까지 기능 개발 속도 증가. *

  • 적은 버그: 사람(개발자)에 의한 에러 약 40% 감소. **
  • 직관적: 훌륭한 편집기 지원. 모든 곳에서 자동완성. 적은 디버깅 시간.
  • 쉬움: 쉽게 사용하고 배우도록 설계. 적은 문서 읽기 시간.
  • 짧음: 코드 중복 최소화. 각 매개변수 선언의 여러 기능. 적은 버그.
  • 견고함: 준비된 프로덕션 용 코드를 얻으십시오. 자동 대화형 문서와 함께.
  • 표준 기반: API에 대한 (완전히 호환되는) 개방형 표준 기반: OpenAPI (이전에 Swagger로 알려졌던) 및 JSON 스키마.

#출처 : FastAPI 공식문서

요약하자면 FastAPI는 공식문서에서 말하는것처럼

빠르고 쉽다!! 또한 python 기반이라 python 코드를 연동할 때 편하다…!!

FastAPI를 이용하여 로컬서버에서 받은 이미지를 이용하여 영수증 재료 인식 해보기

시작전 Google이 제공하는 무료 OCR 라이브러리인 Tesseract 설치

sudo apt install tesseract-ocr 
sudo apt-get install tesseract-ocr-kor ### 기본적으로 영어는 지원해주지만 한글은 따로 설치 필요

Step1. FastAPI를 사용하여 이미지를 인식하기 위한 필수 라이브러리 설치

vim requirements.txt 
### 위 코드를 이용하여 txt파일을 만들어도 좋고 그냥 txt파일을 만들어도 상관없음

이제 requirements.txt 파일을 다음과 같이 작성해준다.

click==7.1.2 ## CLI도구를 만들기 위한 library
fastapi==0.63.0 ## FastAPI를 사용하기 위한 library
gunicorn==20.0.4 ## HttpRequest를 python으로 이해하기 위한 library
h11==0.12.0 ##  python으로 쓰여진 HTTP/1.1 protocol library
numpy==1.20.1 ## 다차원 배열 처리를 위한 library
opencv-python==4.5.1.48 ## 이미지 처리를 위한 library
Pillow==8.1.0 ## 이미지 처리를 위한 library
pydantic==1.7.3  ## 데이터를 검증하고 설정등을 관리하는 library 
pytesseract==0.3.7 ## Tesseract를 python에서 제어하기 위한 library
python-multipart==0.0.5 
six==1.15.0
starlette==0.13.6 ##Starlette는 비동기적으로 실행할 수있는 Web application server  tarlette는 Uvicorn 위에서 실행
unicorn==1.0.2  ## 서버연동을 위한 library
uvicorn==0.13.3 ## 서버연동을 위한 library

이후 다음 명령어를 입력하여 한번에 설치

pip install -r requirements.txt

Step2. 이제 영수증에서 재료를 인식하는 코드를 넣어보자

### Python 파일 생성 서버 구동 때 파일 이름이 들어감
vim OCR.py
from lib2to3.pgen2.token import OP
from pydantic import BaseModel
from urllib3 import Retry
from pytesseract import Output
from shutil import ReadError
import numpy as np
from fastapi import FastAPI, UploadFile, File
from typing import Optional
from starlette.requests import Request
import sys, os
import io
import cv2
import pytesseract
import re


def read_img(img):
    pytesseract.pytesseract.tesseract_cmd = r'/usr/bin/tesseract' ### Tesseract가 들어가 있는 폴더 이름 배포 시 헤로쿠 환경에 맞춰줘야 함 밑에 설명함
    results = pytesseract.image_to_string(img ,lang='kor')

    classes = ["가지","감자", "깻잎", "버터", "당근",
            "대파","마늘", "무","배추","브로콜리",
            "상추","새송이버섯","시금치","애호박",
            "양배추", "양송이버섯","양파","오이",
            "고추","고구마", "콩나물", "귤","감",
            "딸기", "멜론", "참외", "배", "복숭아",
            "블루베리", "사과", "수박", "파프리카",
            "키위","방울토마토", "소고기","돼지고기",
            "닭고기", "달걀", "조기", "갈치","고등어",
            "문어", "꽃게", "새우", "오징어","바지락",
            "멸치", "두부", "옥수수","밥"]
       
    min_confidence = 0.6
    string = results

    list = []
    for i in string :
        if i.isalpha() :
            list.append(i)
        elif i == "\n" :
            list.append("\n")
        
    string = "".join(list)
    result = string

    result = result.replace("\n", " ")
    result = result.split(" ")
    recipe = []
    for i in result :
        if i != '' :
            recipe.append(i)
    out = []
    for i in recipe:
        for j in classes:
            if j in i:
            #print("인식된 재료는 : ", j)
                out.append(j)
    return out

app = FastAPI()

class ImageType(BaseModel):
    url:str


@app.post("/predict/")
def prediction(requset: Request, file: bytes = File(...)):
    if requset.method == "POST":
        image_stream = io.BytesIO(file)
        image_stream.seek(0)
        file_byte = np.asarray(bytearray(image_stream.read()), dtype = np.uint8)
        ########################## 서버에서 이미지를 읽어오는 과정 #####################
        frame = cv2.imdecode(file_byte, cv2.IMREAD_COLOR)
        gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
        height, width = gray.shape
        gray = cv2.resize(gray,(2*width, 2*height), interpolation=cv2.INTER_LINEAR)
        frame = cv2.fastNlMeansDenoising(gray,h=10, searchWindowSize=21,templateWindowSize=7)
        ########## 들어온 이미지를 영수증 인식을 위한 전처리 ##############
        label = read_img(frame)
        return label
    else :
        return "No post request found"

Step3. 로컬에서 이미지를 받아와 파이썬 코드 실행

### OCR->위에서 만든 python 파일 이름
uvicorn OCR:app --reload
# 참고 위 python코드 중 밑에 부분은 자신이 설치한 Tesseract가 있는 폴더 이름을 넣어주면 된다 리눅스 경우 다음 명령어 사용해서 찾는다.
which tesseract
찾은 경로를 넣어준다.
pytesseract.pytesseract.tesseract_cmd = r'/usr/bin/ 

http://127.0.0.1:8000/docs/ 접속 이후

prediction -> POST -> Try it out -> file첨부 ->이미지 업로드 ->Excutu -> 결과값 확인!

#추후 로컬뿐 아니라 헤로쿠를 이용하여 배포

Step4. 헤로쿠를 이용하여 배포!

이제 로컬에서 돌아가는걸 확인했다면 헤로쿠에서 무료 배포

1. 배포 전 서버에서 Tesseract가 동작하기 위해서 코드 설정값 변경

### 위 python 코드에서 밑에 부분만 수정
 pytesseract.pytesseract.tesseract_cmd = '/app/.apt/usr/bin/tesseract'
 # 헤로쿠 환경변수를 기본값으로 설정

2. runtime.txt 파일 작성

## 파일 생성
vim runtime.txt 
## 파일 생성 후 :wq를 입력하여 저장후 종료

runtime.txt파일 수정

##  코드가 돌아가는 버전에 맞춰서 파이썬 버전 설정 
python-3.8.10

3.requirements.txt 파일에 코드 추가

click==7.1.2
fastapi==0.63.0
gunicorn==20.0.4
h11==0.12.0
numpy==1.20.1
Pillow==8.1.0
pydantic==1.7.3
pytesseract==0.3.7
python-multipart==0.0.5
six==1.15.0
starlette==0.13.6
unicorn==1.0.2
uvicorn==0.13.3
opencv-python-headless ## 추가
uvloop ## 추가 
httptools ## 추가 

4. Procfile 생성

vim Procfile ## 파일생성 :wq로 저장 후 종료

Procfile 내용 추가

web: gunicorn -w 4 -k uvicorn.workers.UvicornWorker OCR:app
## OCR:app 이 부분에서 OCR은 자신의 Python 코드 이름

5. Aptfile 생성

vim Aptfile ## 파일생성 :wq로 저장 후 종료

Aptfile 내용 추가

tesseract-ocr
tesseract-ocr-eng
tesseract-ocr-kor
libtesseract-dev
libatlas-base-dev
libarchive-dev
libarchive-tools
libarchive13

6. .gitignore 생성

vim .gitignore

.gitignore 내용 추가

__pycache__
### 같은 경로에 있는 무시하고 싶은 파일을 추가해주면 된다.
### ex) 가상환경 폴더 없으면 그냥 진행

1 OCR.py
2 rentime.txt
3 requirements.txt
4 Procfile
5 Aptfile
6 .gitignore
이렇게 총 6개 파일이 같은 경로에 있어야 한다!

Step 5. 모든게 준비가 끝났다면 이제 Github에 새로운 repo을 생성해서 해당 파일등을 add - commit - push

카테고리:

업데이트: