본문으로 바로가기

손글씨 학습용 데이터인 MNIST 데이터 셋을 이용해서 텐서플로우를 이용해서 단층 신경망으로 손글씨 학습을 하던 초보스런 시작부터 갑자기 Keras로 갈아타서는 Keras로 CNN 모델을 이용해서 MNIST 손글씨를 학습했었네요. 이때는 목적이 있었죠. 바로 학습한 모델을 저장하고, 그걸 단지 불러와서 내 손글씨를 인식시켜 보겠다는 것이었죠. 그래서 이미 학습된 모델을 Keras를 이용해서 내 손글씨 인식하기를 했는데, 문제는 이때는 내가 쓴 손글씨를 모델에 적용하기 위해 사진을 자르고 사이즈를 강제로 맞추고, 뭐 그런 짓을 수동으로 했죠.ㅠㅠ. 

그걸 다시 자동(^^)으로 하기 위해.. 손을 댄 것이 바로 OpenCV였습니다. OpenCV는 최초 그냥 쉽게 사람 얼굴을 OpenCV로 인식해 보고자 시작했다가. 내가 쓴 손글씨에서 숫자 영역을 OpenCV로 추출하는 과정도 수행을 했었죠.^^ 와우~ 오늘 글은 여기서부터 이어서 가는 겁니다.^^. 직전 글인 내가 쓴 손글씨에서 숫자 영역을 OpenCV로 추출하는 과정에서 마지막 부분이

였죠. 그 때 저 반복문 안의 코드를 좀 바꿉니다.^^

img_result = []
img_for_class = img.copy()

margin_pixel = 60

for rect in rects:
    #[y:y+h, x:x+w]
    img_result.append(
        img_for_class[rect[1]-margin_pixel : rect[1]+rect[3]+margin_pixel, 
                      rect[0]-margin_pixel : rect[0]+rect[2]+margin_pixel])
    
    # Draw the rectangles
    cv2.rectangle(img, (rect[0], rect[1]), 
                  (rect[0] + rect[2], rect[1] + rect[3]), (0, 255, 0), 5) 

추가한 코드는 숫자로 인식된 이미지의 영역만 추출하는 거죠. 뭐 어차피 좌표를 아니까요...

plt.figure(figsize=(15,12))
plt.imshow(img);

그 결과야...

잘 추출된 영역이 위의 박스와 같을 겁니다.

plt.figure(figsize=(8,6))
plt.imshow(img_result[0]);

하나만 빼서 데리고 

시작하죠.  저 하나를 잘 인식시킬 수 있으면 나머진 반복문안에 넣어버리면 되니까요^^ 먼저 28*28로 사이즈를 변경해야 합니다.

plt.figure(figsize=(4,4))
plt.imshow(cv2.resize(img_result[0], (28,28)));

뭐... resize 명령으로 끝났네요^^

네.. 사진으로 봐서는 알수 없지만, 28*28로 되었습니다.^^

count = 0
nrows = 3
ncols = 4

plt.figure(figsize=(12,8))

for n in img_result:
    count += 1
    plt.subplot(nrows, ncols, count)
    plt.imshow(n, cmap='Greys', interpolation='nearest')

plt.tight_layout()
plt.show()

12개 모두를 뽑아보죠 

저게 원본이겠죠^^

count = 0
nrows = 3
ncols = 4

plt.figure(figsize=(12,8))

for n in img_result:
    count += 1
    plt.subplot(nrows, ncols, count)
    plt.imshow(cv2.resize(n,(28,28)), cmap='Greys', interpolation='nearest')

plt.tight_layout()
plt.show()

그걸 하나만 데리고 방금 한 것 처럼 통으로 resize를 걸죠.

넵.. 이쁘죠.. 이제.. 

import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)

import sys
import tensorflow as tf
import keras

from keras.models import load_model
model = load_model('MNIST_CNN_model.h5')

model.summary()

이전에 CNN으로 모델을 학습시키고 저장했던 것을 불러오던 때 처럼 그냥 부르죠. 주의해 주세요. 전 지금 그냥 저장된.. 학습이 완료도어 저장된 모델을 불러올 뿐이랍니다. 물론 이전에 CNN으로 학습을 시켰죠.

그때의 CNN 구조는 위와 같구요^^ 이제...

test_num = cv2.resize(img_result[2], (28,28))[:,:,1]
test_num = (test_num < 70) * test_num
test_num = test_num.astype('float32') / 255.

plt.imshow(test_num, cmap='Greys', interpolation='nearest');

test_num = test_num.reshape((1, 28, 28, 1))

print('The Answer is ', model.predict_classes(test_num))

하나만~ 확인하면 되죠~

네~ 2를 2라고 알아주네요^^ 그럼 뭐 다 돌려볼까요^^

count = 0
nrows = 3
ncols = 4

plt.figure(figsize=(12,8))

for n in img_result:
    count += 1
    plt.subplot(nrows, ncols, count)
    
    test_num = cv2.resize(n, (28,28))[:,:,1]
    test_num = (test_num < 70) * test_num
    test_num = test_num.astype('float32') / 255.
    
    plt.imshow(test_num, cmap='Greys', interpolation='nearest');
    
    test_num = test_num.reshape((1, 28, 28, 1))
    plt.title(model.predict_classes(test_num))
    
plt.tight_layout()
plt.show()

짠~ 네.. 그냥 12개 숫자를 다 보겠다는거죠^^

ㅎㅎㅎㅎ. 응? 흠.. 9를 3이라고 인식하는 오류를 범했네요ㅠㅠ. 흠.. 일단 이 부분을 개선하는 것은 좀 더 진행하는 걸로 하고.. 오늘은 계속 절차적인 면에서^^ 이제 인식도 할 수 있게 되었으니 최초의 이미지에 적용해 봐야죠... 즉...

이랬던 반복문 안에... 이 과정을 다 녹여줘야죠^^

img_result = []
img_for_class = img.copy()

margin_pixel = 60

for rect in rects:
    #[y:y+h, x:x+w]
    target_num = img_for_class[rect[1]-margin_pixel : rect[1]+rect[3]+margin_pixel,
                               rect[0]-margin_pixel : rect[0]+rect[2]+margin_pixel]
    test_num = cv2.resize(target_num, (28,28))[:,:,1]
    test_num = (test_num < 70) * test_num
    test_num = test_num.astype('float32') / 255.
    test_num = test_num.reshape((1, 28, 28, 1))
    predicted_num = model.predict_classes(test_num)
    
    # Draw the rectangles
    cv2.rectangle(img, (rect[0], rect[1]), 
                  (rect[0] + rect[2], rect[1] + rect[3]), (0, 255, 0), 5) 
    
    font = cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(img, str(predicted_num[0]), (rect[0],rect[1]), font, 4, (0,0,255), 10)

plt.figure(figsize=(15,12))
plt.imshow(img);

역시... 짧죠^^ 넵.. 완성하고 나면 참 아무것도 아닌게 되죠^^

결과는 위와 같습니다. 그놈의 3이라고 오류를 낸 9 빼고는 다 잘 되었네요^^ 이로써... 학습이 완료된 CNN 모델에서, 제가 그냥 연습장에 쓴 숫자에서 숫자 영역을 찾고, 그 개별 영역의 숫자를 인식해서 결과를 다시 원본 이미지 위에 쓰도록 했습니다.~~~^^


댓글을 달아 주세요

  1. BlogIcon 공수래공수거 2018.05.21 08:49 신고

    손글씨도 인식을 할수 있군요
    이번주도 힘내는 한주가 되시길~~

  2. BlogIcon 즐거운 우리집 2018.05.21 12:52 신고

    마지막에서 왜 에러가... ㅎ
    그래도 멋지네요 ^^

  3. BlogIcon 휴식같은 친구 2018.05.21 22:59 신고

    앞으로는 필기로 적은 글씨를 쉽게 읽어들일날이 곧 올것 같습니다.

  4. BlogIcon Deborah 2018.05.22 01:14 신고

    좋은 예제를 들어가시면서 정성을 다한 포스팅 잘 보고 있네요.
    잘 이해는 안되지만 분야에 종사하는 분들에게는 좋은 참조가 되겠어요

  5. BlogIcon *저녁노을* 2018.05.22 05:40 신고

    오호...
    이렇게 하는군요ㅎㅎ

  6. BlogIcon Bliss :) 2018.05.23 06:56 신고

    코드로 얼굴을 인식하고 숫자를 추출해 인식하는 거 정말 신기한 것 같아요~ 오류를 조금씩 수정해가면서 작업한 후 원하는 결과 나오면 정말 짜릿한 성취감 느낄 것 같아요. 행복한 하루 되세요~

  7. BlogIcon 북두협객 2018.05.23 07:02 신고

    글씨를 인식할 수 있다니 신기합니다