R-CNNを「Tensorflow x Pepper」で実装する方法

アトリエ秋葉原で勉強会を開催

こんにちは。

AI coordinatorの清水秀樹です。

アトリエ秋葉原で勉強会の講師を努めさせて頂きました。

独学でDeepLearningを学んで「Tensorflow x Pepper」でアプリを作っている話【勉強会】

R-CNNを使った物体検出をPepperで試してみたという内容です。

 

その時に使用したスライドとソースコードをまとめて紹介します。

参考にして頂けたらと思います。

 

スライドショーの紹介

keynoteでの作成は今回初めてでした。

 

R-CNN:物体検出入門編

いきなりペッパーから始めるのはハードルが高いので、まずは自宅のPCで物体検出にチャレンジしてみましょう。

以下の記事で、物体検出をローカル環境で実装する方法を紹介しています。

映像からの物体検出(SSD_Keras)に挑戦 for ubuntu

映像物体検出(SSD_Keras)を簡単に実装する方法 for maxOS

ubuntu用とmac用それぞれで試せます。

macの方が準備は簡単です。

ただ、anacondaではPepper SDKが使えないので、そこを知った上で試してみてください。

 

デモで使用したソースコードの紹介

開発環境はスライドで紹介していますので、ここでは省略します。

 

公開済み学習モデルでR-CNNを実装したペッパーサンプル

DeepLearningを活用した物体検出(SSD_Keras)を可能とするPepper

こちらの記事で紹介した内容を、そのままデモで使用しています。

物体検出の精度がとても高いので、初めはこれからチャレンジして感覚を掴んでもらった方が良いかと思います。

 

R-CNNを使った美人女優を検出できるペッパーのソースコード

学習モデルの作成方法は、

Tensorflowで映像からの美人女優顔検出学習モデルの見直し」の記事を参考にしてください。

 

R-CNNを実装するにはOpenCVのカスケードファイルが必要になりますので、

簡単にできるOpenCVを使った顔検出」の記事も合わせてご確認ください。

 

Slackに画像をアップロードする方法は、

監視カメラで撮影した画像を自動でSlackにアップロードする方法」が参考になるかと思います。

 

そして以下のソースコードがPepperでR-CNNを実装した時のソースコードになります。

# vim: set fileencoding=utf-8 :
import sys, os
from keras.preprocessing.image import load_img, img_to_array
import numpy as np
import cv2
import time
from keras.models import model_from_json
from naoqi import ALProxy
from slacker import Slacker

from datetime import datetime
 
# get NAOqi module proxy
ip = "192.168.11.5"
port = 9559
videoDevice = ALProxy('ALVideoDevice', ip, port)
tts = ALProxy('ALTextToSpeech',ip,port)

# subscribe top camera
AL_kTopCamera = 0
AL_kQVGA = 2  # {0 = kQQVGA, 1 = kQVGA, 2 = kVGA}
AL_kBGRColorSpace = 13 # {0 = kYuv, 9 = kYUV422, 10 = kYUV, 11 = kRGB, 12 = kHSY, 13 = kBGR}
fps = 10 # {5, 10, 15, 30}

nameID = 'test14'
captureDevice = videoDevice.subscribeCamera(
    nameID, AL_kTopCamera, AL_kQVGA, AL_kBGRColorSpace, fps)
videoDevice.unsubscribe(nameID)
 
# create image
pepper_width = 640
pepper_height = 480
frame = np.zeros((pepper_height, pepper_width, 3), np.uint8)

# カスケードファイルの指定
cascade_path = "./haarcascades/haarcascade_frontalface_alt.xml"
cascade = cv2.CascadeClassifier(cascade_path)
cam = cv2.VideoCapture(0)
color = (255, 0, 255)

#学習モデルの定義
image_size = 32
categories = ["aya ueto", "ayame gouriki", "mayu watanabe", "nozomi sasaki","yui aragaki"]

#使用する学習モデルを指定する
keras_model = "./idol_makedata/idol.json"
keras_param = "./idol_makedata/idol-model.hdf5"

#学習モデルの読み込み
model = model_from_json(open(keras_model).read())
model.load_weights(keras_param)
model.summary()

def slack(interval,last_time):
    #撮影は2秒以上の間隔で撮影
    now = datetime.now()
    fntime = lambda n : int(n.strftime('%S'))
    sec = fntime(now) - fntime(last_time)
                
    if sec < 0:
        sec = sec * -1

    if sec > interval:
        #動いている物体の画像を保存する
        f = now.strftime('%Y-%m-%d-%H-%M-%S') + ".jpg"
        cv2.imwrite(f,frame)
        last_time = now
                
        #Slackにアップロードする
        token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        slacker = Slacker(token)
        channel_name = "#" + "general"
        result = slacker.files.upload(f, channels=['xxxxxxxxxxx'])

def main():
    
    #写真撮影用初期パラメータ/2秒以上の間隔で撮影
    last_time = datetime.now()
    print(last_time)
    interval = 3


    while(True):
        
        # get image
        result = videoDevice.getImageRemote(captureDevice);

        if result == None:
            print 'cannot capture.'
        elif result[6] == None:
            print 'no image data string.'
        else:
            # translate value to mat
            values = map(ord, list(result[6]))
            i = 0
            for y in range(0, pepper_height):
                for x in range(0, pepper_width):
                    frame.itemset((y, x, 0), values[i + 0])
                    frame.itemset((y, x, 1), values[i + 1])
                    frame.itemset((y, x, 2), values[i + 2])
                    i += 3
        
        %%time
        #顔の検出
        facerect = cascade.detectMultiScale(frame, scaleFactor=1.3, minNeighbors=2, minSize=(10, 10))
        
        for rect in facerect:
            x = rect[0]
            y = rect[1]
            width = rect[2]
            height = rect[3]
            
            cv2.imwrite("frontalface.png", frame)
            img = cv2.imread("frontalface.png")
            
            dst = img[y:y+height, x:x+width]
            cv2.imwrite("output.png", dst)
            cv2.imread("output.png")
            X = []

            img = load_img("./output.png", target_size=(image_size,image_size))
            in_data = img_to_array(img)

            X.append(in_data)
            X = np.array(X)
            X  = X.astype("float")  / 256
            
            pre = model.predict(X)
            #print(pre)
            
            if pre[0][0] > 0.99:
                #aya ueto 学習モデル失敗 原因不明
                print(categories[0],pre[0][0])
                #text = categories[0]
                #font = cv2.FONT_HERSHEY_PLAIN
                #cv2.putText(frame,text,(rect[0],rect[1]-10),font, 2, color, 2, cv2.LINE_AA)
                
            elif pre[0][1] > 0.99:
                #ayame gouriki
                print(categories[1],pre[0][1])
                text = categories[1]
                font = cv2.FONT_HERSHEY_PLAIN
                cv2.rectangle(frame, tuple(rect[0:2]),tuple(rect[0:2] + rect[2:4]), color, thickness=2)
                cv2.putText(frame,text,(rect[0],rect[1]-10),font, 2, color, 2, cv2.LINE_AA)
                
                #認識した物体をPepperに喋らせる
                tts.say('おひさしぶりです     ごうりきあやめさん')
                
                slack(interval,last_time)
                
            elif pre[0][2] > 0.99:
                #mayu watanabe
                print(categories[2],pre[0][2])
                text = categories[2]
                font = cv2.FONT_HERSHEY_PLAIN
                cv2.rectangle(frame, tuple(rect[0:2]),tuple(rect[0:2] + rect[2:4]), color, thickness=2)
                cv2.putText(frame,text,(rect[0],rect[1]-10),font, 2, color, 2, cv2.LINE_AA)
                
                #認識した物体をPepperに喋らせる
                tts.say('わたなべまゆさん     このあいだは     ありがとうございました')
                
                slack(interval,lastqqq_time)
                
            elif pre[0][3] > 0.99:
                #nozomi sasaki
                print(categories[3],pre[0][3])
                text = categories[3]
                font = cv2.FONT_HERSHEY_PLAIN
                cv2.rectangle(frame, tuple(rect[0:2]),tuple(rect[0:2] + rect[2:4]), color, thickness=2)
                cv2.putText(frame,text,(rect[0],rect[1]-10),font, 2, color, 2, cv2.LINE_AA)
                
                #認識した物体をPepperに喋らせる
                tts.say('ささきのぞみさん     こんどあそびにいきましょう')
                
                slack(interval,last_time)
                
            elif pre[0][4] > 0.99:
                #yui aragaki
                print(categories[4],pre[0][4])
                text = categories[4]
                font = cv2.FONT_HERSHEY_PLAIN
                cv2.rectangle(frame, tuple(rect[0:2]),tuple(rect[0:2] + rect[2:4]), color, thickness=2)
                cv2.putText(frame,text,(rect[0],rect[1]-10),font, 2, color, 2, cv2.LINE_AA)
                
                #認識した物体をPepperに喋らせる
                tts.say('あらがきゆいさん     げんきですか')
                
                slack(interval,last_time)

        cv2.imshow("pepper-top-camera-320x240", frame)
        time.sleep(0.1)

        k = cv2.waitKey(1)

        if k == ord('q'):
            break

    videoDevice.unsubscribe(nameID)
    
    cam.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

 

SlackからのPepper操作

SlackからPepperを操作した時のソースコードは、

SlackからPepperを発話させる超簡単な方法」の記事を参考にしてください。

 

実際の発表では、SlackからPepperのモーションを使うことで、左右にPepperを動かしてみました。

その時のソースコードも紹介しておきます。

# coding: utf-8

from slackbot.bot import default_reply
import os, re, json, random
from naoqi import ALProxy
# 入力メッセージを取得し、pepperに喋らせる
@default_reply()
def default_func(message):
    text = message.body['text'].encode('utf-8')     # メッセージを取り出す
    ip = "192.168.100.31"
    port = 9559

    motion = ALProxy("ALMotion", ip, port)
    tts = ALProxy("ALTextToSpeech", ip, port)

    if text == '前':
        motion.moveTo(0.5, 0.0, 0.0)
    elif text == '後':
        motion.moveTo(-0.5, 0.0, 0.0)
    elif text == '右':
        motion.moveTo(0.0, -0.5, 0.0)
    elif text == '左':
        motion.moveTo(0.0, 0.5, 0.0)
    else:
        tts.setLanguage("Japanese")
        say = text
        tts.say(say)

 

類義語を出力するword2vec

wikipediaを学習した類義語を話すSlackbotの作成方法

類義語を話すPepperを作ってみることもできます。

 

物体検出する方法の考察

今回は物体を検出する方法にOpecCVのカスケードファイルを使用しました。

そこで抽出した画像と学習モデルをぶつけてR-CNNを実装しています。

物体を検出する方法の一つとして、

カメラ映像から動く物体の輪郭検出が簡単にできた話」の記事で紹介した内容をデモで実施させて頂きました。

R-CNNの難しいところは、物体らしき領域をどうやって抽出してくるか?

これがうまくできるようになると、物体検出の精度も大幅に上がってくるかと思います。

 

Cifar10の紹介

DeepLearningを手っ取り早く始められる画像データセットを紹介させて頂きました。

DeepLearningのモデル可視化方法とmatplotlibで学習の様子を可視化する方法

簡単に学習モデルの作成が試せるのでおすすめです。

 

最後に

誰か一緒にビジネス関係なくPepperアプリ開発しませんかぁ〜?

 

それではまた。

 


その他のPepperアプリ記事はこちらから

あなたにオススメの記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

PAGE TOP