« スマホ向け機械学習に使える「TensorFlow Lite」発表 | トップページ | 2.45インチの超小型スマホ”Jelly”が技適取得し8月に国内販売開始! »

2017年5月24日 (水)

TensorFlowで「松本城」にすり寄ってくる自動運転カー作ってみた

前回「TensorFlowで顔めがけて近づいてくる車を作ってみた」のやつは、検出された顔がカバンちゃん似だろうとフェネック似だろうと「そこに顔があるから」と見境なく突っ込んでくるという、まるで登山家の名言を地で行く車でしたが。

今回は対象を識別して、特定のものに接近するやつを作ってみました。いかにも「人工知能」って感じの電子工作です。

いろいろ考えたんですが、既存の教師データを用いるのが簡単だろうということで「TensorFlowで”日本のお城”を識別させてみた: EeePCの軌跡」の時に使ったお城の写真を使うことにしました。

ただ、カメラ映像ってのは明るい/暗い、ノイズの有無がある ので、既存の教師データから明るい画像、暗めの画像、ノイズ付き画像などを作って画像を増やしてみました。

そんな画像を作り出すコードは以下の記事を参考に

機械学習のデータセット画像枚数を増やす方法 - Qiita

こういうのを作りました。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cv2
import numpy as np
import sys
import os

# ヒストグラム均一化
def equalizeHistRGB(src):

    RGB = cv2.split(src)
    Blue   = RGB[0]
    Green = RGB[1]
    Red    = RGB[2]
    for i in range(3):
        cv2.equalizeHist(RGB[i])

    img_hist = cv2.merge([RGB[0],RGB[1], RGB[2]])
    return img_hist
# ガウシアンノイズ
def addGaussianNoise(src):
    row,col,ch= src.shape
    mean = 0
    var = 0.1
    sigma = 15
    gauss = np.random.normal(mean,sigma,(row,col,ch))
    gauss = gauss.reshape(row,col,ch)
    noisy = src + gauss
   
    return noisy

# salt&pepperノイズ
def addSaltPepperNoise(src):
    row,col,ch = src.shape
    s_vs_p = 0.5
    amount = 0.004
    out = src.copy()
    # Salt mode
    num_salt = np.ceil(amount * src.size * s_vs_p)
    coords = [np.random.randint(0, i-1 , int(num_salt))
                 for i in src.shape]
    out[coords[:-1]] = (255,255,255)

    # Pepper mode
    num_pepper = np.ceil(amount* src.size * (1. - s_vs_p))
    coords = [np.random.randint(0, i-1 , int(num_pepper))
             for i in src.shape]
    out[coords[:-1]] = (0,0,0)
    return out

if __name__ == '__main__':
    # ルックアップテーブルの生成
    min_table = 50
    max_table = 205
    diff_table = max_table - min_table
    gamma1 = 0.75
    gamma2 = 1.5

    LUT_HC = np.arange(256, dtype = 'uint8' )
    LUT_LC = np.arange(256, dtype = 'uint8' )
    LUT_G1 = np.arange(256, dtype = 'uint8' )
    LUT_G2 = np.arange(256, dtype = 'uint8' )

    LUTs = []

    # 平滑化用
    average_square = (10,10)

    # ハイコントラストLUT作成
    for i in range(0, min_table):
        LUT_HC[i] = 0
               
    for i in range(min_table, max_table):
        LUT_HC[i] = 255 * (i - min_table) / diff_table
                                 
    for i in range(max_table, 255):
        LUT_HC[i] = 255

    # その他LUT作成
    for i in range(256):
        LUT_LC[i] = min_table + i * (diff_table) / 255
        LUT_G1[i] = 255 * pow(float(i) / 255, 1.0 / gamma1)
        LUT_G2[i] = 255 * pow(float(i) / 255, 1.0 / gamma2)

    LUTs.append(LUT_HC)
    LUTs.append(LUT_LC)
    LUTs.append(LUT_G1)
    LUTs.append(LUT_G2)

    # 画像の読み込み

    file_list = os.listdir('./jpg/')
    for file in file_list:
      img_src = cv2.imread('./jpg/' + file)
      trans_img = []
      trans_img.append(img_src)
   
    # LUT変換
      for i, LUT in enumerate(LUTs):
          trans_img.append( cv2.LUT(img_src, LUT))

    # 平滑化      
      #trans_img.append(cv2.blur(img_src, average_square)) 
   
    # ヒストグラム均一化
      trans_img.append(equalizeHistRGB(img_src))

    # ノイズ付加
      trans_img.append(addGaussianNoise(img_src))
      trans_img.append(addSaltPepperNoise(img_src))

    # 反転
      #flip_img = []
      #for img in trans_img:
      #    flip_img.append(cv2.flip(img, 1))
      #trans_img.extend(flip_img)

    # 保存
      if not os.path.exists("trans_images"):
          os.mkdir("trans_images")
   
      base =  os.path.splitext(file)[0] + "_"
      img_src.astype(np.float64)

      for i, img in enumerate(trans_img):
         
          cv2.imwrite("trans_images/" + base + str(i) + ".jpg" ,img)

これを使うと明暗画像やノイズの入った画像、ピンボケ気味の画像、それらを反転した画像が作られ、結果1枚の画像が18枚に増えます(ただし、このコードでは「反転」をコメントアウトしてるため9枚 理由は後述)。

つまり、当初 全383枚だったお城の写真が一気に6894枚に!

となるはずだったんですが、ここで問題発生!!

なんとうちのGeForce GTX 1050がメモリオーバーを起こしちゃったようで、妙なエラーをはいて動かなくなってしまいました。

画像を3700枚程度まで減らすと動いたため、メモリ不足だと推測しています。

やっぱり安いボードはこういうところがボトルネックになりますね。やはり8GB搭載した1080あたりが欲しい・・・

とりあえず「反転」をコメントアウトし、枚数を9倍(3447枚)に抑えておきました。

これを使ってTensorFlowコードで学習。

また、カメラ映像の中から「お城」部分を切り出す判別器は以下の記事のとおり作成。

TensorFlowで”日本のお城”を識別させてみた: EeePCの軌跡

これで準備完了。

続いて、目標となるお城の写真を準備。

Img_1383

A4で6枚入るように印刷し切り取り、百均で買ってきた札立てに張り付けて作成。

このブログ、百均に頼ってばかりです。セリア、ダイソーに足を向けて寝られませんね。

この写真のうち「松本城」を目標に接近するようプログラムしました。

なぜ「松本城」なのか?ですが、私の苗字とは関係なく、ただ単にこの中で最も識別率が高かったからという理由だけです。

ちなみに私の作った学習器はどういうわけか「迷ったら岡崎城!」と思うようにしているらしく、岡崎城の誤認識率が異常に高いです。

・・・てことで、岡崎城にすり寄るマシーンだけは作れそうにありません。家康公ゆかりのいいお城なんですけどねぇ。

Img_2885

写真を並べて(ここでは左から2番目)

Img_2886

「松本城めがけて走るカー」を置き、いざスタート!

Img_2887

たどたどしく動きながら

Img_2888

だんだんと「松本城」に接近

Img_2889

20cmほどのところで予定通り停止。成功です!

Img_2890

今度は一番左に配置して再びGo!!

Img_2892

最終的にはご覧のとおり、たどり着いてくれました。

よく似てる写真(熊本城)もあるんですが、全く見向きもしませんね。「松本城」一筋です。

Img_2894

なお、松本城の写真だけを引きはがすと

Img_2895

ついてきます。けなげ~。

Img_2896

なんだか「松本城」が死ぬほど好きなワンちゃんのような感じ。なぜか愛着がわきますね。

丸いつぶらな瞳がよりかわいさを誘います・・・が、あれは目ではなくて超音波センサーなんですけどね。

なお、彼の”眼”(カメラ)にはこう見えてます。

Cnnautocar01

たまに誤認識、検出ミスはありますが、大体の写真を識別していることがわかりますね。

(この画像では右から2番目に目標)

Cnnautocar02

20cm付近ではこの大きさになります。もう彼の眼には「松本城」だけしか見えない状態。めろめろです。

動画も載せておきます。実際にはこんな感じの動き。

徐々にほふく前進して迫っていくような慎重な動きですが、確実に目標に向かってます。

ようやく今回で”人工知能”ぽいものを作ることができました。

もっとも、これが一体何の役に立つのか!?といわれると何とも言えませんが・・・

ただ、この工作の製作目的は”デモンストレーション”なので、個人的には満足のいく出来でしょうか。

そういえば、前回書き忘れましたが、Arduinoとモーターの間には「DRV8835」というモータードライブがついてます。

ここで使われてる電子部品は、Raspberry PiとPiカメラ、Arduino UNO互換ボード、DRV8835、タミヤのロボットリモコンキット、超音波センサーHC-SR04、乾電池とモバイルバッテリー。

そんなに派手な部品は使用しておりませんが、人工知能と結びつけばこんなものも作れるってことで。

なお、これだけみると動作は一見完璧なようですが、実は夜になるとうまく動作してくれないという問題を抱えてます。

Img_2874

部屋の明かりが悪いのか、カメラセンサーがダサいのかわかりませんが、写真がちょっと暗くなるとすべて”岡崎城”に見えてしまうようです。

Img_2872

そこでこういうものを使って

Img_2868

照らしてやるとようやく「松本城」に気付いてくれました。

なんだか光で誘導しているように見えますが、ほかのお城の写真を照らしても見向きもしないので、やはり彼は「松本城」一筋です。

ちょっと面倒さに負けてコード・回路図を作っておりませんが、もし需要あればアップします。要望はコメントまで。

ラズベリーパイ3 (Raspberry Pi 3B made in JAPAN) 技適対応 日本製   5.1V/2.5A ラズベリー財団公式アダプタ 【本体 アダプタ セット品】

タミヤ 楽しい工作シリーズ No.162 リモコンロボット製作セット タイヤタイプ (70162)

デュアルモータードライバDRV8835

« スマホ向け機械学習に使える「TensorFlow Lite」発表 | トップページ | 2.45インチの超小型スマホ”Jelly”が技適取得し8月に国内販売開始! »

Raspberry Pi・Arduino・電子工作」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: TensorFlowで「松本城」にすり寄ってくる自動運転カー作ってみた:

« スマホ向け機械学習に使える「TensorFlow Lite」発表 | トップページ | 2.45インチの超小型スマホ”Jelly”が技適取得し8月に国内販売開始! »

無料ブログはココログ

スポンサード リンク

ブログ村