딥러닝 (Deep Learning)/딥러닝 분석연습

tensorflow.keras 손글씨 MNIST

DS지니 2021. 4. 7. 09:20
728x90
반응형

www.youtube.com/watch?v=TV3oplqa5VA(유튜브 영상)참고

!pip install tensorflow-gpu==2.0.0-rc1
import tensorflow as tf
#손글씨모듈
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.preprocessing.image import ImageDataGenerator
batch_size = 128
num_classes = 10
epochs = 12

# 데이터셋 불러오기
img_rows, img_cols = 28,28

(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 컨볼루션 신경망 모델이 요구하는 형태로 이미지 배열 변환
# 마지막에 차원하나 추가
x_train = x_train.reshape(x_train.shpae[0], img_rows, img_cols, 1) 
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)  # 28*28*1

# 이미지 실수타입으로 변경, 픽셀 0~1로 정규화
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255

# 원핫인코딩
y_train = to_categorical(y_train, num_classes)
y_test = to_categorical(y_test, num_classes)

# 컨볼루션 신경망 모델 구축
model = Sequential()
model.add(Conv2D(32, kernel_size=(3,3), activation='relu',
				input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))

# 좋은 결과를 위해 회전, 평행이동으로 데이터셋 양 늘리기
datagen = ImageDataGenerator(rotation_range=40,
							width_shift_range=0.2,
                            height_shift_range=0.2,
                            shear_range=0.2,
                            zoom_range=0.2,
                            fill_mode='nearest')
                            
# 모델 학습
modle.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size),
					steps_per_epoch=x_train.shape[0] // batch_size,
                    validation_data=(x_test, y_test),
                    epochs=epochs, verbose=2)

# 성능평가
score = model.evatluate(x_test, y_test, verbose=2)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

# 파일저장
model.save('model.h5')
#학습된 모델로 실제 손글씨 인식시키기

import cv2 as cv
import numpy as np
import tensorflow.keras.models import load_model

#이미지 파일 불러와서 그레이스케일 이미지로 변환
img_color = cv.imread('test3.jpg', cv.IMREAD_COLOR)
img_gray = cv.cvtColor(img_color, cv.COLOR_BGR2GRAY)

#그레이스이미지 바이너리로 변환
ret,img_binary = cv.threshold(img_gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)

#모폴로지 연산 적용(이진화 결과 혹시모를 빈 공간 메꾸기)
kernel = cv.getStrucuringElement(cv.MORPH_RECT, (5,5))
img_binary = cv.morphologyEx(img_binary, cv.MORPH_CLOSE, kernel)

cv.imshow('digit', img_binary)
cv.waitKey(0)

#숫자별로 분리하기 위해 컨투어 검출
contours, hierarchy = cv.findContours(img_binary, cv.RETR_EXTERNAL,
						cv.CHAIN_APPROX_SIMPLE)
                        
for contour in contours:
	#숫자별로 경계박스 구하기
	x,y,w,h = cv.boundingRect(contour) 
    
    #가로,세로 중 긴 방향 선택, 여분추가해 한 변의 크기 정하기
    #잘라낼 이미지를 저장할 빈 이미지 생성
    length = max(w, h) + 60
    img_digit = np.zeros((length, length, 1),np.unint8)
    
    #숫자가 이미지의 정중앙에 오도록 경계박스의 시작 위치 조정
    new_x, new_y = x-(length - w)//2, y-(length - h)//2
    
    # 바이너리 이미지에서 숫자 영역 가져와 변수에 저장
    img_digit = img_binary[new_y:new_y+length, new_x:new_x+length]
    
    #숫자가 잘 인식되도록 팽창 모폴로지 연산 적용
    kernel = np.ones((5,5), np.unit8)
    img_digit = cv.morphologyEx(img_digit, cv.MORPH_DILATE, kernel)
    
    cv.imshow('digit', img_digit)
    cv.waitKey(0)
    
    #학습된 모델 불러오기
    model = load_model('model.h5')
    
    #이미지 크기를 학습된 모델에서 요구하는 가로세로 28로 변환
    img_digit = cv.resize(img_digit, (28,28), interpolation=cv.INTER_AREA)
    
    img_digit = img_digit /255.0  #이미지 픽셀도 변환
    
    img_input = img_digit.reshape(1, 28, 28, 1) #이미지 형태도 변환
    
    #이미지를 입력으로 사용해 예측 진행
    predictions = model.predict(img_input)
    
    #argmax함수를 사용해 softmax 결과를 숫자로 변환
    number = np.argmax(predictions)
    print(number)
    
    #원본 이미지의 숫자마다 사각형 그려주기
    cv.rectangle(img_color, (x,y), (x+w, y+h), (255,255,0), 2)
    
    #이미지에 있는 숫자 위에 인식된 숫자 적어주기
    location = (x+int(w*0.5), y-10)
    font = cv.FONT_HERSHEY_COMPLEX
    fontScale = 1.2
    cv.putText(img_color, str(number), location, font, fontScale, (0,255,0),2)
    
    #이미지에서 잘라낸 숫자를 가공한 결과
    cv.imshow('digit', img_digit)
    cv.waitKey(0)
   
   #원본 이미지에 인식한 숫자를 적은 결과
   cv.imshow('result' img_color)
   cv.waitKey(0)
728x90
반응형