OCR:
광학 문자 인식(Optical character recognition; OCR)은 사람이 쓰거나 기계로 인쇄한 문자의 영상을 이미지 스캐너로 획득하여 기계가 읽을 수 있는 문자로 변환하는 것
- 테서랙트(Tesseract):
-
다양한 운영 체제를 위한 광학 문자 인식 엔진 이 소프트웨어는 Apache License, 버전 2.0 에 따라 배포되는 무료 소프트웨어이며 2006년부터 Google에서 개발을 후원
-
2006년 테서랙트는 당시 가장 정확한 오픈 소스 OCR 엔진 중 하나로 간주되었다.
-
한글인식이 상당히 좋지않은편이라 학습 또는 이미지 전처리 과정이 필요
# 다음 과정은 구글 코랩에서 진행
필요한 라이브러리 설치
sudo apt install tesseract-ocr
pip install pytesseract
pip install jellyfish
pip install --upgrade imutils
#### 필요 라이브러리 import
from skimage.filters import threshold_local
import matplotlib.pyplot as plt
from pytesseract import Output
import pytesseract
from PIL import Image
import numpy as np
import jellyfish
import imutils
import cv2
import os
import re
4개의 가장자리를 찾기위한 함수
def order_points(pts):
rect = np.zeros((4, 2), dtype="float32")
s = pts.sum(axis=1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
diff = np.diff(pts, axis=1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
return rect
def four_point_transform(image, pts):
rect = order_points(pts)
(tl, tr, br, bl) = rect
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
maxWidth = max(int(widthA), int(widthB))
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
maxHeight = max(int(heightA), int(heightB))
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype="float32")
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
return warped
기울어진 이미지를 보정하기 위한 3가지 단계
- 만약 코랩이 아닌 환경에서 돌릴 경우 plt.imshow() , plt.show()를 지우고 cv2.imshow(“text”, img) 로 변경
image_name = "/content/5.jpg"
### 인식을 이미지 경로
min_conf = 0
image = cv2.imread(image_name)
ratio = image.shape[0] / 500.0 ### 이미치 처리 속도를 높이고 가장자리 탐지를 위해
original = image.copy()
image = imutils.resize(image, height= 500)
GRAY = cv2.cvtColor(image , cv2.COLOR_BGR2GRAY)
height, width = GRAY.shape
GRAY = cv2.GaussianBlur(GRAY, (5, 5), 0)
edged = cv2.Canny(GRAY, 75, 200)
plt.imshow(cv2.cvtColor(edged,cv2.COLOR_BGR2RGB))
plt.show()
### 코랩이 아닌 경우 위 plt 함수를 지워주고 밑에 주석 코드 사용
'''
cv2.imshow("img", edged)
cv2.waitkey(1)
cv2.destroyAllWindows()
'''
########################## STEP1 #######################
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
screenCnt = approx
break
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
plt.imshow(cv2.cvtColor(image,cv2.COLOR_BGR2RGB))
plt.show()
### 코랩이 아닌 경우 위 plt 함수를 지워주고 밑에 주석 코드 사용
'''
cv2.imshow("img", edged)
cv2.waitkey(1)
cv2.destroyAllWindows()
'''
########################## STEP2 #######################
warped = four_point_transform(original, screenCnt.reshape(4, 2) * ratio)
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
T = threshold_local(warped, 11, offset = 10, method = "gaussian")
warped = (warped > T).astype("uint8") * 255
warped = imutils.resize(warped, height = 650)
plt.imshow(cv2.cvtColor( warped,cv2.COLOR_BGR2RGB))
plt.show()
### 코랩이 아닌 경우 위 plt 함수를 지워주고 밑에 주석 코드 사용
'''
cv2.imshow("img", edged)
cv2.waitkey(1)
cv2.destroyAllWindows()
'''
########################## STEP3 #######################
인식된 결과값 확인을 코드
height, width = warped.shape
enlarge = cv2.resize(warped, (2*width, 2*height), interpolation=cv2.INTER_LINEAR)
denoised = cv2.fastNlMeansDenoising(enlarge, h=10, searchWindowSize=21, templateWindowSize=7)
plt.imshow(cv2.cvtColor(denoised,cv2.COLOR_BGR2RGB))
plt.show()
results = pytesseract.image_to_string(denoised ,lang='kor')
print(results)
가끔 위 과정에서 인식이 실패하여 바코드를 인식하는 경우가 있음 위 과정을 캔슬하고 기본적인 전처리만 하는 코드 인식률은 나쁘지않지만 추가적인 개선은 필요
image_name = "/content/5.jpg"
min_conf = 0
image = cv2.imread(image_name)
GRAY = cv2.cvtColor(image , cv2.COLOR_BGR2GRAY)
height, width = GRAY.shape
cv2.GaussianBlur(GRAY, (5, 5), 0)
####################### Gaussian ######################
#GRAY = cv2.adaptiveThreshold(GRAY_enlarge,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
#cv2.THRESH_BINARY,15,2)
####################### Gaussian ######################
####################### Enlarge 2x
GRAY_enlarge = cv2.resize(GRAY, (2*width, 2*height), interpolation=cv2.INTER_LINEAR)
####################### Enlarge 2x
###################### Denoising ######################
denoised = cv2.fastNlMeansDenoising(GRAY_enlarge, h=10, searchWindowSize=21, templateWindowSize=7)
###################### Denoising ######################
plt.imshow(cv2.cvtColor(denoised,cv2.COLOR_BGR2RGB))
plt.show()
results = pytesseract.image_to_string(denoised ,lang='kor') ### /usr/share/tesseract-ocr/4.00/tessdata/kor.traineddata 원하는 데이터를 넣어줘야 함
# results = re.compile('[|가-힣|+').sub('', results)
print(results)
미리 분류해놨던 재료클라스와 현재 이미지에 인식된 결과값이 같다면 출력해주는 코드
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)
Korean = re.compile('[^ ㄱ-ㅣ가-힣+]')
result = Korean.sub(' ',string)
result = result.replace("\n", " ")
result = result.split(" ")
recipe = []
for i in result :
if i != '' :
recipe.append(i)
print(recipe)
for i in recipe:
for j in classes:
if j in i:
print("인식된 재료는 : ", j)
# for i in recipe:
# for j in classes:
# confidence = jellyfish.jaro_distance(i, j)
# if(confidence > min_confidence ):
# print(j)
#### 자카드 유사도 검사를 통해 출력하려 했으나 딱히 정확도가 좋지않아 주석처리