OpenCV 이미지 학습 시키기 - OpenCV imiji hagseub sikigi

전에 딥러닝 공부하면서 신경망을 이용하여 처음으로 해봤던 손글씨 학습시키는 내용이 OpenCV에서도 kNN 알고리즘을 이용하여 손글씨를 학습시키고 테스트해보는 내용이 있어서 소개해 본다.

http://blog.naver.com/samsjang/220684292757

먼저 아래코드에서 주석처리된 learningDigit() 함수를 주석해제해서 배열로 정리되어 있는 손글씨 데이타 이미지 (digits.png)를 학습시키면 digits_for_ocr.npz 라는 학습된 데이타 파일이 생성된다. 그런 후 learningDigit() 함수를 주석처리하고, 테스트할 손글씨 샘플이미지 0.png ~ 9.png 파일을 준비하고 다시 실행하면 샘플이미지를 보여주고 인식한 숫자를 보여준다. 만약 틀리게 결과가 나오면 0~9 사이의 맞는 숫자를 키보드로 눌러줘 재학습 시켜서 학습데이타를 업데이트 시켜주면 나중에는 손글씨 이미지를 맞게 인식하게 된다. 만약 인식한 결과가 맞으면 아무키나 누르며 다음 숫자 이미지로 넘어간다.

바로 테스트해 볼 수 있도록 손글씨 학습데이타 이미지와 샘플이미지를 첨부했다.

import numpy as np import cv2 def resize20(digitImg): img = cv2.imread(digitImg) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret = cv2.resize(gray, (20, 20), fx=1, fy=1, interpolation=cv2.INTER_AREA) ret, thr = cv2.threshold(ret, 127, 255, cv2.THRESH_BINARY_INV) cv2.imshow('ret', thr) return thr.reshape(-1, 400).astype(np.float32) def learningDigit(): img = cv2.imread('images/digits.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cells = [np.hsplit(row, 100) for row in np.vsplit(gray, 50)] x = np.array(cells) train = x[:, :].reshape(-1, 400).astype(np.float32) k = np.arange(10) train_labels = np.repeat(k, 500)[:, np.newaxis] np.savez('digits_for_ocr.npz', train=train, train_labels=train_labels) print('data saved') def loadLearningDigit(ocrdata): with np.load(ocrdata) as f: traindata = f['train'] traindata_labels = f['train_labels'] return traindata, traindata_labels def OCR_for_Digits(test, traindata, traindata_labels): knn = cv2.ml.KNearest_create() knn.train(traindata, cv2.ml.ROW_SAMPLE, traindata_labels) ret, result, neighbors, dist = knn.findNearest(test, k=5) return result def main(): #learningDigit() #이미지 학습할때 주석제거 #return ocrdata = 'digits_for_ocr.npz' traindata, traindata_labels = loadLearningDigit(ocrdata) digits = ['images/' + str(x) + '.png' for x in range(10)] print(traindata.shape) print(traindata_labels.shape) savenpz = False for digit in digits: test = resize20(digit) result = OCR_for_Digits(test, traindata, traindata_labels) print(result) k = cv2.waitKey(0) if k > 47 and k < 58: savenpz = True traindata = np.append(traindata, test, axis=0) new_label = np.array(int(chr(k))).reshape(-1, 1) traindata_labels = np.append(traindata_labels, new_label, axis=0) cv2.destroyAllWindows() if savenpz: np.savez('digits_for_ocr.npz', train=traindata, train_labels=traindata_labels) main()

- 단도직입적으로 말하자면, 현재 OpenCV 4.0 버전에서는 딥러닝 학습 기능을 지원하지 않습니다.

앞 글인 'OpenCV에서의 딥러닝 모듈'에서 적었듯, OpenCV는, 학습된 딥러닝 모델을 가져와서 순전파를 실행하고 영상 관련 정보를 처리하는 기능만을 가지고, 학습은 OpenCV 범위 밖입니다.

- 딥러닝을 사용하는 영상 분석 및 응용 프로그램을 만들기 위해선, OpenCV만이 아니라, 전문적인 딥러닝 프레임워크를 같이 사용하면 됩니다.

- 간단히 텐서플로우를 한번 알아봅시다.

텐서플로우는 딥러닝 관련 구현을 쉽게 해주는 기술을 지원하는 대표적인 프레임워크입니다.

이전에 텐서플로 2.0 버전 정리글을 올렸는데, 책에는 1.13.1버전을 사용하는군요.

2버전과 1버전은 사용법에 차이가 큰데, 아직까지는 1버전도 많이 사용하는가 보네요.

일단 텐서플로우는 기본적으로 파이썬 언어를 사용합니다.

따로 파이썬을 배워보신 분이라면 금방 익히실테고, 이제껏 C++로 진행한 컴퓨터 비전 정리글을 보신 분이라면, 파이썬은 쉬운 언어이기 때문에 어렵지 않게 익히실수 있을 것입니다.

어쨌거나, 컴퓨터 비전 카테고리의 글은 딥러닝 자체보다는 컴퓨터 비전 부분에 더 중점을 둔 글들이니, 텐서플로에 관심이 있으신 분은 인공지능 카테고리를 확인해보세요.

(텐서플로 준비)

- 파이썬 언어 설치 :

간단한 손글씨 인식 코드를 작성해볼 것이므로, 책에 적힌 버전과 맞춰야합니다.

파이썬 공식 홈페이지에서 파이썬 3.7.2를 설치하시면 됩니다.

- 텐서플로 설치 :

텐서플로 설치의 경우가 보다 더 버전을 정확히 맞춰야 합니다.

텐서플로 1.13.1버전 설치를 알아보고 설치를 진행하세요.

[텐서플로 1.x버전 학습]

- 일단 해보시면 아실텐데, 딥러닝은 이전까지의 머신러닝보다 '구조적인 부분'에 중점을 둔다는 것을 보셔야 합니다.

(파이썬 텐서플로 필기체 숫자 학습 예시코드)

# 필요 라이브러리 임포트
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
from tensorflow.python.framework import graph_util
from tensorflow.python.platform import gfile

# 로깅 설정
tf.logging.set_verbosity(tf.logging.ERROR)

# mnist 데이터셋 로딩
mnist = input_data.read_data_sets("./MNIST_data/", one_hot=True)

# 하이퍼 파라미터 설정
learning_rate = 0.001
training_epochs=20
batch_size = 100

# 모델 구축
X = tf.placeholder(tf.float32, [None, 28, 28, 1], name='data')
Y = tf.placeholder(tf.float32, [None, 10])

conv1 = tf.layers.conv2d(X, 32, [3,3], padding="same", activation=tf.nn.relu)
pool1 = tf.layers.max_pooling2d(conv1, [2,2], strides=2, padding="same")

conv2 = tf.layers.conv2d(pool1, 64, [3,3], padding="same", activation=tf.nn.relu)
pool2 = tf.layers.max_pooling2d(conv2, [2,2], strides=2, padding="same")

flat3 = tf.contrib.layers.flatten(pool2)
dense3 = tf.layers.dense(flat3, 256, activation=tf.nn.relu)

logits = tf.layers.dense(dense3, 10, activation=None)
final_tensor = tf.nn.softmax(logits, name='prob')

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=Y, logits=logits))
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)

# 학습
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    total_batch = int(mnist.train.num_examples / batch_size)
    
    print('Start learning!')
    for epoch in range(training_epochs):
        total_cost = 0
        
        for i in range(total_batch):
            batch_xs, batch_ys = mnist.train.enxt_batch(batch_size)
            batch_xs = batch_xs.reshape(-1,28,28,-1)
            _, cost_val = sess.run([optimizer, cost], feed_dict={X:batch_xs, Y:batch_ys})
            total_cost += cost_val
            
        print('Epoch: ', '%04d' % (epoch+1), 'Avg. cost = ', 
            '{:.4f}'.format(total_cost/total_batch))
            
    print('Learning finished!')
    
    # 학습 완료된 모델 파라미터를 pb 파일로 저장
    output_graph_def = graph_util.convert_variables_to_constants(
        sess, sess.graph_def, ['prob'])
    with gfile.FastGFile('') as f:
        f.write(output_graph_def.SerializeToString())
    
    print('Save done!')

: 딥러닝 학습 이론과,

파이썬 기본 문법은 설명하지 않겠습니다.

각각 파이썬 카테고리와 인공지능 카테고리를 참고해주세요.

텐서플로도 1.x버전이라 2.0버전으로 배운 저도 어색하고 불편하네요.(1.x버전도 이전에 배우고 정리한 글이 있는데, 잊어버렸습니다.)

데이터 로딩부터 봅시다.

데이터 로딩 : mnist data는 다운받으셔서 해당 파일 위치를 기입해주면 됩니다.

    one_hot은, one hot encoding으로, 정답 레이블을 0과 1의 값으로 인식하고 만들어준다는 뜻입니다.

하이퍼 파라미터 설정 : 하이퍼 파라미터는, 인공신경망 학습 방식에 대하여 구조 구축자가 설정해줘야하는

    파라미터입니다. learning rate는, 학습시 구한 미분값에 대해 분류 함수의 파라미터를 얼마나 변경해줄까에 대한

    것입니다. epochs는, 에폭, 즉 학습 반복 횟수고, batch size는, 훈련 데이터를 랜덤으로 몇개를 사용할지에 대한

    배치 방식에 대한 설정이죠. 자세한 내용은 여기선 다루지 않습니다.

모델 구축 : X는 훈련 데이터입니다. Y는 정답 레이블이죠.

    아직까지 데이터를 담은것은 아니고, 데이터를 받아들일 placeholder와 구조를 만드는것입니다.

    X로는 28x28 1채널 데이터를 받는 설정을 하고, Y로는 10개의 데이터 분류 결과에 대한 결과 벡터를 만듭니다.

    CNN으로 영상 인식 모델을 구축하므로, conv - pool 계층을 2개로 만들고,

    flat으로 flatten, fully connected 계층을 만들어, CNN 계층에서 넘어온 특징 데이터를 분류합니다.

    계층적 마지막으로 softmax로, 결과값이 확률로 나올수 있도록 만들면 끝입니다.

    설명이 대충인 것 같은데, 이는 딥러닝 이론에 연관된 내용이므로, 역시나 이전 정리글을 참고하세요.

    마지막으로, 학습의 기준이 되는 cost를 구하는 함수를 만들고,

    해당 손실함수를 어떻게 학습시킬지에 대한 것을 결정하는 optimizer를 만들어주면 됩니다.

    위에서는 Adamoptimizer로 cost를 최소화시키는 방향을 설정했습니다.

학습 : 텐서플로 1.x버전에서는 구축한 모델을 움직이려면 Session을 사용해야합니다.

    파이썬으로 만들고 구축한 인공신경망 구조 코드를, 보다 빠르고 성능 좋게 실행하기 위해 텐서플로는 내부 엔진으로

    C언어로 구축한 딥러닝 엔진을 사용하는데, 이를 위한 것입니다.

    딥러닝 관련 지식이 있는 분이 보신다면, 학습시킬 내부 파라미터를 랜덤값으로 초기화시키고, 훈련 데이터를

    미니배치하고, 설정한 에폭만큼 반복하며 훈련 데이터를 통해 학습을 시키는 것입니다.

    에폭별로 코스트 값을 로깅합니다.

pb 파일 저장 : 이제 학습된 신경망 모델 파라미터를 pb 파일로 추출하기만 하면, 다음에는 텐서플로에서 그대로

    사용해도 되고, OpenCV 등에서 사용할수 있는 학습된 신경망이 추출된 것입니다.

    이런방식으로 스스로가 만든 잘 학습된 신경망을 공유하거나, 혹은 남이 만든 신경망을 가져올수 있습니다.

- 위와 같이 학습을 진행하면 학습률이 나오게 됩니다.

원래는 accuracy로 로깅을 하는데, 여기서는 cost로 했습니다.

바로 이 cost가 줄어드는 방향으로 학습을 진행하므로, cost가 얼마나 줄어드는지를 확인하시면 됩니다.

batch 학습과 초기값을 랜덤으로 설정하기에, 이 cost는 학습을 진행할때마다 달라질 것입니다.

cost가 줄어들도록 반복해도 좋지만, cost가 작은것만으로 학습이 잘된건지 아닌건지를 판단할수는 없습니다.

오버피팅이라는 것 때문에, 보편성이 없는 학습 모델은, 특정 데이터에만 높은 성능을 내고, 그 이외에는 좋지 않기 때문이죠.

- 딥러닝 구축은 그 자체로는 별로 어렵지 않습니다. 특히나 케라스나 텐서플로 2.0 이상버전에서는 더 쉬워지죠.

하지만 적절한 데이터에 대해 제대로된 모델을 구축하기 위해서는 이론적인 지식이 필요합니다.