AR Fukuoka リアルタイム手書き数字認識AIを作って遊ぼうに参加してきました!
こんにちは → こんばんは!!
今日はエンジニアカフェでこちらに参加、少しだけお手伝いしてきました😊
エンジニアカフェでイベント開催すると黒板にイラストつきな紹介を書いてくれてるんですが、何気にこれ嬉しいですよね!!
今回イベントに参加しながらブログを書いているので、ちょっと長めになっちゃってます🙇🏻♂️
- イベントの雰囲気
- ディープラーニングとは
- 本日のお題
- まずはMNISTで遊んでみよう
- 画像加工処理をやってみよう
- MNISTの中身をみてみよう
- PC内臓のカメラの画像を表示する
- リアルタイム手書き数字認識を作成する
- まとめ
イベントの雰囲気
ディープラーニングとは
本日のお題
Tensorflow + Keras + Opencv を利用して、PCのカメラで撮影した手書き文字をリアルタイムで認識
- 難しい事はさておいて、ざっくり説明すると Tensorflow はゲームのハード、Keras がゲームソフト
まずはMNISTで遊んでみよう
- MNIST は機械学習のHello World!!!!
MNISTをKerasで使える形にする
import numpy as np from keras.datasets import mnist from keras.utils import np_utils #MNISTデータセット呼び出し (X_train, y_train), (X_test, y_test) = mnist.load_data() #データの正規化 X_train = np.array(X_train)/255. X_test = np.array(X_test)/255. #CNNに入れるために次元を追加 X_train = np.expand_dims(X_train, axis=-1) X_test = np.expand_dims(X_test, axis=-1) #ラベルのバイナリ化 y_train = np_utils.to_categorical(y_train) y_test = np_utils.to_categorical(y_test)
モデルの構築
from keras.layers import Input, Dense, Conv2D, MaxPooling2D from keras.models import Model from keras.layers.core import Flatten inputs = Input(shape=(28,28,1)) #入力層 conv1 = Conv2D(16, (3, 3), padding='same', activation='relu')(inputs) #畳込み層1 pool1 = MaxPooling2D((2, 2))(conv1) conv2 = Conv2D(32, (3, 3), padding='same', activation='relu')(pool1) #畳込み層2 pool2 = MaxPooling2D((2, 2))(conv2) flat = Flatten()(pool2) #全結合層に渡すため配列を一次元化 dense1 = Dense(784, activation='relu')(flat) #全結合層 predictions = Dense(10, activation='softmax')(dense1) #出力層 model = Model(inputs=inputs, outputs=predictions) #モデルの宣言(入力と出力を指定)
モデルのコンパイル、学習実行
model.compile(optimizer="sgd", loss="categorical_crossentropy", metrics=["accuracy"]) hist = model.fit(X_train, y_train, batch_size=16, verbose=1, epochs=1, validation_split=0.9)
学習結果の評価
score = model.evaluate(X_test, y_test, verbose=1) print("正解率(acc):", score[1])
モデルを保存
model.save("MNIST_test.h5")
作成されたモデルの確認
作成した学習モデルを利用して評価する
from keras.models import load_model import cv2 import numpy as np model = load_model("mnist.h5") # 学習済みモデルをロード Xt = [] img = cv2.imread("6.jpg", 0) img = cv2.resize(img,(28, 28), cv2.INTER_CUBIC) Xt.append(img) Xt = np.array(Xt)/255 Xt = np.expand_dims(Xt, axis=-1) result = model.predict(Xt, batch_size=1) print(result[0])
画像加工処理をやってみよう
OpenCVを利用して、撮影している画像をリアルタイムにKerasで認識できる形に加工する
まずはOpenCVを使って画像を表示してみる
import cv2 #Lennaを召喚する呪文:0→グレースケール、1→カラー image = cv2.imread('Lenna.png',1) #testウインドウにLennaを召喚 cv2.imshow('test',image) #何かしら操作があるまで待つ:0なので無限に待つよ cv2.waitKey(0) #ウインドウを破棄する cv2.destroyAllWindows() #Macの人は以下を入れとかないとエラー cv2.waitKey(1)
読み込んだ画像をグレーに変えてみる
*方法は簡単。2行ほど追記するだけ!
#グレースケールに変換 gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) #グレー用のウインドウを追加 cv2.imshow('gray',gray)
次は画像に資格の枠を表示する
- OpenCV は画像の左上を原点として座標を指定します。
- 以下のコードを追加
#四角を表示する cv2.rectangle(image,(50,50),(100,100),(255,0,0))
画像に文字を書く
#(窓,書き込む文字列,座標,フォント,サイズ,色,太さ,線の種類) cv2.putText(image,'Hello World',(0,30),cv2.FONT_HERSHEY_SIMPLEX,1,(255,255,255),1,cv2.LINE_AA)
画像を二値化→白黒反転→ブラーをかける
#大津の方法で二値化する _, th = cv2.threshold(gray,0,255,cv2.THRESH_OTSU) #白黒反転 th = cv2.bitwise_not(th) #ブラーを書ける th = cv2.GaussianBlur(th,(9,9),0)
画像をトリミング
th = th[50:150,50:150]
画像を縮小
#50 x 50 にトリミング th = cv2.resize(th,(50,50),cv2.INTER_CUBIC)
MNISTの中身をみてみよう
ここまでの内容を合体させて、先ほど利用したMNISTの中身の画像をOpenCVを利用して見てみましょう
from keras.datasets import mnist import cv2 #MNISTを画像部分だけロード (X_train,_),(_,_) = mnist.load_data() #X_trainの100番目を取得して表示 cv2.imshow('mnist',X_train[100]) cv2.waitKey(0) cv2.destroyAllWindows() cv2.waitKey(1)
PC内臓のカメラの画像を表示する
- PCのカメラにアクセスする為には、ご利用の環境によって段階を踏まないといけません。
① どのカメラを利用するか指定する
② カメラから画像を読み込む
③ カメラの画像を表示する
④ カメラを開放する
静止画
import cv2 #①カメラを指定 cap = cv2.VideoCapture(0) #②カメラから画像を読み込む ret,frame = cap.read() #③カメラの画像を表示する cv2.imshow('frame',frame) cv2.waitKey(0) #④カメラを開放する cap.release() cv2.waitKey(1) cv2.destroyAllWindows() cv2.waitKey(1)
動画
- OpenCVでは静止画をひたすら撮影→表示し続ける事で動画となるという思想なので以下で動画に対応できます
- 終了判定がないと無限に動画が表示されてしまうので、今回はキーボードのQが入力されると終了するっていうコードに、静止画コードの②と③を変更します。
while(True): ret,frame = cap.read() cv2.imshow('frame',frame) #キーボードのQが押されたら終了させる k = cv2.waitKey(1) & 0xFF if k == ord('q'):break
カメラアクセス#AR_Fukuoka#エンジニアカフェ pic.twitter.com/AIHypKtfEk
— AR Fukuoka (@ar_fukuoka) 2020年2月15日
動画の中心に四角を表示する
while (True): ret,frame = cap.read() #サイズでかいとき対策として半分にする h,w,_=frame.shape[:3] frame = cv2.resize(frame, (int(w/2), int(h/2))) #画像の形(高さ,幅,チャンネル数) h,w,_=frame.shape[:3] #y軸の中心点を取得 h_center=h//2 #x軸の中心点を取得 w_center=w//2 cv2.rectangle(frame,(w_center-71,h_center-71),(w_center+71,h_center+71),(255,0,0))
リアルタイム手書き数字認識を作成する
- ここまでくれば色々な事に応用できますね😊
- 本日の本題であるリアルタイム文字認識を作成してみましょう!!
- コツはPCのInカメラを利用した時に自分の動きが左右反転してしまうので、frame = cv2.flip(frame,1)で反転してあげると良い
完成コード
import cv2 from keras.models import load_model import numpy as np #学習モデルを読み込む model = load_model('mnist.h5') #カメラを指定する cap = cv2.VideoCapture(0) while (True): #判定用データを格納する変数 Xt = [] Yt = [] ret,frame = cap.read() #サイズでかいとき対策として半分にする h,w,_=frame.shape[:3] frame = cv2.resize(frame, (int(w/2), int(h/2))) #画像の形(高さ,幅,チャンネル数) h,w,_=frame.shape[:3] #y軸の中心点を取得 h_center=h//2 #x軸の中心点を取得 w_center=w//2 cv2.rectangle(frame,(w_center-31,h_center-31),(w_center+31,h_center+31),(255,0,0)) #トリミング(y,x)なので注意 im=frame[h_center-30:h_center+30,w_center-30:w_center+30] #グレースケール化 im=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) #二値化 _,im =cv2.threshold(im,0,255,cv2.THRESH_OTSU) #白黒反転 im=cv2.bitwise_not(im) #ブラーをかける im=cv2.GaussianBlur(im,(9,9),0) #28 x 28 にリサイズする im=cv2.resize(im,(28,28),cv2.INTER_CUBIC) Xt.append(im) Xt = np.array(Xt)/255 Xt = np.expand_dims(Xt,axis=-1) #Xtと学習したデータを比較して判定結果を返す result = model.predict(Xt,batch_size=1) #画面の反転 frame = cv2.flip(frame,1) for i in range(10): #小数点以下第二位までで四捨五入 r = round(result[0,i],2) #OpenCVで表示できる型に変換 r = "{0:0.2f}".format(r) #その数字が何かと一致する確率をセットで格納 Yt.append([i,r]) #Ytをソートする Yt = sorted(Yt,key=lambda x:(x[1])) #判定結果の上位1番目を画面上に表示する cv2.putText(frame,'1st:'+str(Yt[9]),(10,50),cv2.FONT_HERSHEY_SIMPLEX,0.8,(255,255,255),1,cv2.LINE_AA) cv2.startWindowThread() cv2.imshow("frame",frame) cv2.imshow("debug",im) key = cv2.waitKey(30) & 0xFF if key ==ord('q') : break #カメラを開放する cap.release() #フリーズ対策としてwaitKeyで挟む cv2.waitKey(1) cv2.destroyAllWindows() cv2.waitKey(1)
完成!#AR_Fukuoka#エンジニアカフェ pic.twitter.com/l5kiLUMvI3
— AR Fukuoka (@ar_fukuoka) 2020年2月15日
まとめ
- 甲斐さんの説明がめっちゃ丁寧だし分かり易いし感動!!!!
- やっぱりガッキーは可愛い
- ブログ書きながらは忙しすぎてしんどい事が判明w
- いち早くビール飲みたい