이번 포스팅에서는 이전 포스팅에 이어서 종이에 쓰인 글씨를 따로 추출하는 방법에 대해서 알아보겠다.
먼저 이미지의 윤곽선을 추출한다.
# cv2.findCountours() function changed from OpenCV3 to openCV4: not it have only two parameters instead of 3
# 윤곽선을 찾아낸다
cvMajorVersion=cv2.__version__.split('.')[0]
print('OpenCV version:',cvMajorVersion)
# check for contours on thresh
if int(cvMajorVersion) >=4:
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
else:
imageContours,contours,hierarchy=cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
이미지에 쓰인 숫자에 사각형을 그려본다.
img_digits=[]
img_origin=img.copy()
margin=10
# loop to check if any possible contour is found
# 경계들을 배열로 가져와서 바운더리 사각형을 구한다
for contour in contours:
x,y,w,h=cv2.boundingRect(contour)
# 너무 작은 이미지는 무시한다
if w*h < 100:
continue
# Y and X [y-margin:y+h+margin,x-margin:x+margin]
img_digits.append(img_origin[y-margin:y+h+margin,x-margin:x+w+margin])
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
print(x,x+w,y,y+h)
plt.imshow(img)
사각형 안에 있는 글씨들만 이미지로 추출해보자.
for i in range(0,len(img_digits)):
plt.subplot(1,len(img_digits),i+1)
plt.imshow(img_digits[i],cmap='Greys',interpolation='nearest')
plt.tight_layout()
plt.show()
사전 학습된 모델이 input image를 (28,28)로 학습되어있기 때문에 위 이미지들의 사이즈를 조절해준다.
SIZE=28
for i in range(0,len(img_digits)):
plt.subplot(1,len(img_digits),i+1)
plt.imshow(cv2.resize(img_digits[i],(SIZE,SIZE)),cmap='Greys',interpolation='nearest')
plt.tight_layout()
plt.show()
그다음 미리 학습된 모델을 불러온다.
import tensorflow as tf
model=tf.keras.models.load_model('digits_model.h5')
model.summary()
마지막으로 위의 세 사진을 예측해본다.
for i in range(len(img_digits)):
plt.subplot(1,len(img_digits),i+1)
num=cv2.resize(img_digits[i],(SIZE,SIZE))[:,:,1] # 색 channel중 한가지만 사용한다
num=255-num # 색을 반전시킨다
num=num.astype('float32') / 255.0
plt.imshow(num,cmap='Greys',interpolation='nearest')
result=model.predict(np.array([num]))
result_number=np.argmax(result)
plt.title(result_number)
performance=[val for val in result[0]]
print(performance)
plt.tight_layout()
plt.show()
뭔가 예측을 하긴 하는데 정확하지가 않다.
다음 코드는 내장 카메라를 통해 실시간으로 종이에 쓰여진 숫자를 인식해보는 코드이다.
import cv2
import numpy as np
from tkinter import *
from PIL import Image
from PIL import ImageTk
import tensorflow as tf
import time
model=tf.keras.models.load_model('digits_model.h5')
default_src=0 # 기본 카메라
title_name='MNIST Hand Write Digits Recognition Video'
SZ=28
frame_width=300
frame_height=300
cap=cv2.VideoCapture(default_src)
def start():
# initialize the video stream and allow the camera sensor to
# warmup
global cap
default_src = int(srcSpin.get())
#cap = VideoStream(usePiCamera=1).start()
cap = cv2.VideoCapture(default_src)
#time.sleep(2.0)
detectAndDisplay()
def detectAndDisplay():
_, frame = cap.read()
width = frame.shape[1]
height = frame.shape[0]
width_ratio = frame_width / width
height_ratio = frame_height / height
frame = cv2.resize(frame, (frame_width, frame_height))
# hsv transform - value = gray image
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
hue, saturation, value = cv2.split(hsv)
# kernel to use for morphological operations
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# applying topHat operations
topHat = cv2.morphologyEx(value, cv2.MORPH_TOPHAT, kernel)
# applying blackHat operations
blackHat = cv2.morphologyEx(value, cv2.MORPH_BLACKHAT, kernel)
# add and subtract between morphological operations
add = cv2.add(value, topHat)
subtract = cv2.subtract(add, blackHat)
# applying gaussian blur on subtract image
blur = cv2.GaussianBlur(subtract, (5, 5), 0)
# thresholding
thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 19, 9)
#cv2.imshow('thresh', thresh)
# 윤곽선을 구한다
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
img_digits = []
positions = []
margin = 30
img_origin = frame.copy()
for contour in contours:
x, y, w, h = cv2.boundingRect(contour)
# Ignore small sections
if w * h < 2400: continue
y_position = y-margin
if(y_position < 0): y_position = 0
x_position = x-margin
if(x_position < 0): x_position = 0
img_roi = thresh[y_position:y+h+margin, x_position:x+w+margin] # 윤곽선 부분의 이미지를 자른다 threshholding 한 이미지를 이용
num = cv2.resize(img_roi, (SZ,SZ))
num = num.astype('float32') / 255.
result = model.predict(np.array([num]))
result_number = np.argmax(result)
cv2.rectangle(frame, (x-margin, y-margin), (x+w+margin, y+h+margin), (0, 255, 0), 2)
text = "Number is : {} ".format(result_number)
cv2.putText(frame, text, (margin, frame_height-margin), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(10, detectAndDisplay) # 새로운 frame이 들어오면 계속 재귀적으로 실행한다
#main
main = Tk()
main.title(title_name)
main.geometry()
#Graphics window
label=Label(main, text=title_name)
label.config(font=("Courier", 18))
label.grid(row=0,column=0,columnspan=4)
srcLabel=Label(main, text='Video Source : ')
srcLabel.grid(row=1,column=0)
srcVal = IntVar(value=default_src)
srcSpin = Spinbox(main, textvariable=srcVal,from_=0, to=5, increment=1, justify=RIGHT)
srcSpin.grid(row=1, column=1)
Button(main,text="Start", height=2,command=lambda:start()).grid(row=1, column=2, columnspan=2, sticky=(W, E))
imageFrame = Frame(main)
imageFrame.grid(row=2,column=0,columnspan=4)
#Capture video frames
lmain = Label(imageFrame)
lmain.grid(row=0, column=0)
main.mainloop() #Starts GUI
'Object Detection' 카테고리의 다른 글
tesseract와 EAST detector를 이용한 글씨 인식 (0) | 2021.09.05 |
---|---|
자동차 번호판 인식 프로젝트 (0) | 2021.09.03 |
직접 쓴 손 글씨(숫자) 인식하기 - 필터링을 통한 인식률 향상시키는 방법 (0) | 2021.08.26 |
object detection project - keras를 사용한 detection(2) (0) | 2021.08.26 |
object detection project - keras를 사용한 detection(1) (0) | 2021.08.24 |