へっぽこ!リアルタイム画像認識

今回は、caffeのModelZooから学習済みのgoogLeNetをいただいて、それをそのままchainerで使ってリアルタイムの画像認識をします。

拝借するモデルは1000個のラベルについて学習しているので、学習したラベル以外のものについて認識することはできません。
まあ、とりあえず認識できれば嬉しいというへっぽこ感でやっていこうと思います。

モデル読み込み

とりあえず、ここからcaffemodelをダウンロードします。
それから、このスクリプトでラベルファイルなど
をダウンロードします。
chainerでのcaffemodelの読み込みは以下の通り。

import chainer
import chainer.functions as F
from chainer.functions import caffe

googlenet = caffe.CaffeFunction("bvlc_googlenet.caffemodel")

私はこのcaffemodelをpickleで保存して使っています。
こんな感じ。

import cPickle as pickle

# 保存
pickle.dump(func,open('googlenet.pkl','w'))

# 読み込み
func = pickle.load(open('googlenet.pkl', 'rb'))

画像判別

次に画像の判別です。
画像をモデルに通す前に平均画像の差分を取る必要があります。
OpenCVで取り込んだので少し変換する必要があり、変換後差分をとります。
そのあと、モデルを通して1000次元のベクトルを取得し、
最も確率の高い部分のインデックスを持つラベルを返します。

in_size = 224
cropwidth = 256 - in_size
start = cropwidth // 2
stop = start + in_size

# 平均画像の読み込み
meanfile = os.path.join('ilsvrc', 'ilsvrc_2012_mean.npy')
mean_image = np.load(meanfile)
mean_image = mean_image[:, start:stop, start:stop].copy()

def predict(image):
	"""画像を判別"""
	global mean_image, in_size, cropwidth, start, stop
	
	def swap(x):
		x = np.array(x)[:, :, ::-1]
		x = np.swapaxes(x, 0, 2)
		x = np.swapaxes(x, 1, 2)
		return x

	x_data = np.ndarray((1, 3, in_size, in_size), dtype=np.float32)
	
	image = swap(image)
	image = image[:, start:stop, start:stop].copy().astype(np.float32)
	x_data[0] = image-mean_image

	x = chainer.Variable(x_data, volatile=True)
	
	y, = func(inputs={'data': x}, outputs=['loss3/classifier'], train=False)
	synset_i = y.data.argmax(axis=1)
	return synset_words[synset_i]

OpenCVで画像をリアルタイムでキャプチャ

判別と画像出力をスレッドで並列に行うため、リアルタイムでキャプチャするための関数を作ります。

def cap():
    """リアルタイムで画像をキャプチャする"""
    global capture,msg
    fontface=cv2.FONT_ITALIC
    fontscale=1.0
    bold = 4
    color=(255,0,255)
    
    while True:
        ret, image = capture.read()

        if ret == False:
            cv2.destroyAllWindows()
            break

        location=(0,image.shape[0]/2)
        cv2.putText(image,msg,location,fontface,fontscale,color,bold)  
        cv2.imshow("Image Recognition", image)

        if cv2.waitKey(33) >= 0:
    #         cv2.imwrite("image.png", image)
            cv2.destroyAllWindows()
            break
    print 'out'
    cv2.destroyAllWindows()

取り込んだ画像を判別

取り込んだ画像を判別して、グローバル変数にラベルをセットします。
キー入力があるとプログラムを終了します。

def main():
    """取り込まれた画像を判別してラベルをセット"""
    global msg, capture
    while True:
        ret, image = capture.read()

        if ret == False:
            break
        img = Image.fromarray(image[::-1, :, ::-1].copy()).resize((256, 256), Image.ANTIALIAS)

        # ラベルをcapとの共通変数にセット
        msg = predict(img)[0]

        # キー入力で終了
        if cv2.waitKey(33) >= 0:
            break
        if capThread.isAlive() == False:
            break

スレッドの処理

cap()をスレッドで動かして、そのあとmain()を実行します。
これで一応動くはずです。

capture = cv2.VideoCapture(0)
msg = ''
cv2.namedWindow("Image Recognition", cv2.WINDOW_NORMAL)
capture.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH,324)  #2592
capture.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT,228) #1944
capThread = threading.Thread(target=cap, name='cap')
capThread.setDaemon(True)
capThread.start()
main()

まとめ

ということで、畳み込みニューラルネットワークや学習などを説明することなく画像認識できました。Model Zoo 素晴らしいですね。

コードの全体はGithubで公開しています。
GitHub - YasukeXXX/Heppoco