Unityで自分で集めた画像からモバイルで物体検出

最終更新 2019/12/22

まずはじめに

いきなりですが、この記事は実装が終わっておらず書きかけの状態です。
結論として出た事柄から記述することによりよりよい情報になることを目指します。
間違いがあれば訂正いたしますのでご教授ください。

物体検出とは

物体検出は英語だと”Object Detaction”といいます。

写真や動画から物を検出する際に必要な情報は以下の通りです。

  • 位置検出(どこにあるか) : Location
  • 分類(どんなものか) : Classification
  • 信頼性(分類の可能性) : Confidence

日本語の記事が見つからない場合は英語で調査する必要があります。

Unityで物体検出をするために

物体検出、で調べるとOpenCVが出るため、OpenCVforUnityを購入します。

更に、Unity標準のWebCameTextureだとあまり機能が無いため、NatCamを購入します。

OpenCVのサンプル

NatCamとOpenCVforUnityの連携を見ると、Matクラスへの変換までが記述されてあるためそちらをインポートします。

ひとまずUnityで準備できることは以上です。
ここからは自分で集めた画像から物体検出をするための準備を行います。

PCのスペック

Windows10(x64)
メモリ : 32GB
SSD : Sumsugn SSD 970 Evo Plus 1TB
nVidia RTX 2070 super

必要な知識

進化の激しい分野なので、リンク先が無くなったりしやすい
出来た出来なかったはハードウェアやソフトウェアのバージョンにより変わる
諦めない心が大事なようだ

画像を用意

自分で検知したいものを撮影していくか、Imageクローラを用意し、CreativeCommonsの商用利用可能画像を取得していきましょう。
大体1種類の検知につき、画像を50個は用意します。

このとき、例えばリンゴの場合はカットしたものなどを一種類として入れると精度が悪くなると思われます。
そのため、ハーフカットや更にカットしたリンゴを認識したい場合は、別々の種類として画像を用意し、
それぞれ50枚ほど用意しましょう。

調査履歴(メモ)

さて何から手をつけたらいいかが分からないためOpenCVforUnityサンプルのobjdetectから参考にしました。

objdetect

FaceDetectionExample
HOGDescriptorExample
QRCodeDetectorExample
とありますが、やりたいことは顔とQRコード認識ではないためHOGDescriptorを読んでみます。
HOG( Histogram of Oriented Gradients )Descriptorは Haar-like特徴や LBP(Local Binary Pattern)特徴 のように、
特徴検知をして物体検出を行う手法のようです。
SVM(Support Vector Machines) という単語も出てきますがひとまず特徴ごとの特性を見てみよう。
学術論文の絵だけ見れば分かるかもでチラ見をします。

Haar-like特徴

白黒にして矩形分割して似たような感じであればそれって感じな仕組みなのかな?

LBP(Local Binary Pattern)特徴

これも白黒か。これは最初から分割して白黒の濃淡で似ている、みたいにしている仕組みかな?

HOG(Histogram of Oriented Gradients)

これは論文どこだろう。色味の差分が大きいところを情報としてもっていてそれが似ていたら、という感じなのかな。

SVM( Support Vector Machines )

検出方法はあるけど、それがなにかを表すための情報がSVMのようだ。

これを自作するの大変じゃない? ということで他サンプルを漁る。

dnn( ディープニューラルネットワーク )

次の OpenCVforUnityサンプルは以下を 参考にします。
MobileNetSSDWebCamTextureExample
TensorFlowWebCamTextureExample
YoloObjectDetectionWebCamTextureExample

MobileNetSSD のサンプルではいくつかの定数と以下のデータが必要なようです。
MobileNetSSD_deploy.caffemodel
MobileNetSSD_deploy.prototxt
classesList

TensorFlow の サンプルではいくつかの定数と以下のデータが必要なようです。
tensorflow_inception_graph.pb 
imagenet_comp_graph_label_strings.txt 

Yolo の サンプルではいくつかの定数と以下のデータが必要なようです。
yolov3-tiny.weights
yolov3-tiny.cfg.txt
coco.names

この三種はMobileでも動作するようなので、高速なのだと思われます。

各種データ

classesList , imagenet_comp_graph_label_strings.txt , coco.names は
エディタで中身を見ると、それぞれ分類リストが記述されているようです。
それ以外のデータを用意できれば自作の物体検出が出来ると思われます。

ではMobileNetSSD 、 TensorFlow 、 Yolo など聞いた事もないので調査します。

MobileNetSSD

SSD(Single Shot Multibox Detector) というアルゴリズムがあります。マルチボックス前提な略し方だなぁ。
こちらはとても遅く、モバイルで写真や動画から物体検出するにはコストが高すぎるようです。
そこで計算を早めたものがMobileNetというアルゴリズムを利用して高速化したMobileNetSSDの登場、ということなんですが
ここから先は学術論文を読んでもよく分からんなのでURLだけ貼っときます。

classesList は分類の情報。
caffemodel とprototxtってなんなの? prototxt は計算式が入ってるっぽい。caffemodelが重みの情報かな?

TensorFlow

tensorFlowは 機械学習モデルの開発およびトレーニングに役立つオープンソースのコア ライブラリらしい。

imagenet_comp_graph_label_strings.txt は分類の情報。
pbファイルってなんなの?計算式と重み両方の情報が入ってるのかな?

Yolo

SxSのグリッドにしてBoundingBoxと信頼性、同時にグリッド単位での確率マップを生成してガッチャンコして判別している?

coco.names は分類の情報。
weightsとcfg.txtはなんなの? cfg.txt は計算式が入ってるっぽい。weights が重みの情報かな?

用語解説(外っ面)

データセット
予測、判断したいものの結果情報
今回の例でいうと画像を集めて分類したもの

アーキテクチャ
予測、判断したい結果が高い確率で
発生する条件を探索する方法の設計思想。
MobileNetやVGG-16やYoloなど。

アルゴリズム
問題を解くための手順を定式化した形で表現したもの。
Pythonなどを利用し、アーキテクチャ と同時に
アルゴリズムも発表されることもあるようだが
それぞれライセンスが違う可能性があるため気をつける。
(アーキテクチャが非商用利用のみ、や、
 アルゴリズムがPythonは商用利用可能だけどC#は非商用利用のみ、などありうるかも)

学習済みモデル
予測・判断したい結果が高い確率で発生する条件を
組み合わせて結果を判断するロジックのこと。
未知なデータが来たときに予測・判断が可能になる。
学習済みモデル = データセット(ImageNetなど) x アルゴリズム(VGG16など) x 初期の重み x 学習回数

入力層
入れ込むデータ。
224×224のカラー画像を想定したとして
224x224x3(RGB)の行列と考えることが出来る。

隠れ層
計算を行うところ。
この層は複数持つことが出来るため、
深層学習(ディープラーニング)という。

出力層
例えば1000種の予測判断を行いたい場合は1000×1の行列で値が帰ってくる
物によっては 1000×6の行列など(予測値,タイプ,バウンディングボックスのleft,top.right,bottom)

用語解説(内側)

ノード(ユニット)
上記各層が複数のノードを持っている。
そしてそれらはエッジで結ばれている。

エッジ
ノードをつなぎ合わせるとともに
重み情報を持つことができる。

活性化関数
上記各層は活性化関数を持つ。

重み
この値が予測の確率に影響を与える。
エッジと重みの関係上、層ごとに
入力次元Input次元、出力次元Out次元の
ベクトル変形には(Input+1)×Outのパラメータ数が必要。
つまり選択したアーキテクチャの層の数と
最終出力の際の分類数でデータの大きさにも大きく関連する。
また、ほぼ同じアーキテクチャでないとパラメータの再利用はできないと思われるので
転移学習やファインチューニングには使えない

転移学習  (transfer learning)
学習済みモデルの重みは固定し、追加した層のみを使用して学習 すること

ファインチューニング
学習済みモデルの層の重みを微調整する手法。
学習済みモデルの重みを初期値とし、再度学習することによって微調整する。
これを使用しない場合はランダムな値を入れ込んだ重みからの計算になるため
学習データが少なかったり学習する回数が少ないと正解率が低い学習済みモデルになってしまう。

ライセンス

DNN周りでフワっとしているのがライセンス。
まとめると以下の確認をしないといけないようだ。

  • アーキテクチャ的なもの? 例:元となったGitHub Repositoryや論文(設計思想)
  • モデルの重み
  • ソースコード(kerasなどで実装されたソースコードなど)
  • テストアセット(テストに使用した画像など)
  • データベース(画像の切り分け)

参考はIBM。

弁護士柿沼太一様のブログより引用。
法律は「と思われます。」との記述からまだ法律が間に合っていないのかな。

アーキテクチャ

うーん、進化凄い。

その他参考URL

よっしゃこの人のやり方でとりあえず作ってみよう
と作っていったのですが、tensorflow-gpuでの実行では
ビデオカードのメモリが足らずバカスカ失敗する。
(その前に環境構築で苦労する。pipでインストールしたけど
 ローカルで環境構築する場合は参考URLの多いanacondaのほうがいいかも。)

一応PC環境は前に貼ったので各種ライブラリのバージョンを記述。
※後述のGoogleColaboratoryに移行してしまえば環境構築の必要無いと思うのでそちらのほうがいいのではと思ったり。

  • CUDA 10.0
  • cuDNN 7.6
  • Python 3.6.8
  • tensorflow-gpu 1.13.1
  • numpy 1.16.4
  • Keras 2.3.1
  • scikit-learn 0.21.3

64×64のサイズまで縮小後に実行したら
1時間後に出来上がった!

batch_size = 8
num_classes = 103
epochs = 50
steps_per_epoch = 7507 / batch_size
image_input_shape = (64, 64, 3,)
max_queue_size = 2

Accuracy: 0.49885233358837033
f1 score: 0.4725477940429901

うーん、50%の正解率は正直低い。
でも画素数を上げるとCPUでの実行になり
更に学習時間がかかるので却下…。
そしてH5ファイルは520MB。H5って一体なんなん。
とりあえずこれ以上はPCが無理そうなので別の手段に変更。

ONNX

MSとFacebookが 提唱しているニューラルネットワークのモデル表現の標準フォーマット らしい。

さらにNetronというGUIでモデルが見れる拡張子対応してるし
MSがCustomVisionというGUIで学習モデル作れる
クラウドサービス出してるし楽に作れそう!ということでCloud Visionを試してみます。

とりあえずよく分からない用語が出たら見ていくスタイルで、
CustomVisionでモデル作成。こちらはサクサクGUIで作り終え、
onnx形式とtensorflowのpb+label形式で出力。

そこまでは良かったものの、OpenCVforUnityで 読み込もうにもエラーが出る…
ONNXはサンプルにあるため対応しているみたいだけど、何がいけないのか分からないエラーのため断念します。

というわけで素敵なツールなんだけどひとまず諦めます。

NN(Neural Network )について

DNN( Deep Neural Network、ディープニューラルネットワーク )は 脳神経回路(ニューロン)をモデルとしたアルゴリズムを多層構造化したもの
CNN( Convolutional Neural Network、畳み込みニューラルネットワーク ) は DNNだと一次元的な情報になるけど複数次元で意味合いを持ったもの(画像など)
RNN( Recurrent Neural Network 、再帰型ニューラルネットワーク ) は 以前の観測への依存を考慮することが不可欠なもの(株価予想など)

つまりDNNでもRNNでも重みの情報を更新しない限り、強化学習のように学習値が更新されていくわけではないようです。
また、クラウド上ではなくモバイルで動作するようなAIをエッジAIというみたいです。
現在はこのエッジAIの開発が盛んなようで、新たなアーキテクチャが出続けているようです。

Google Colaboratory

Google ColaboratoryというGoogleが提供しているクラウドサービスがあります。
なんと、数十万円するグラボを無料で使用させてくれます。

注意点がいくつかあるため以下にはご注意ください。
特に90分セッションは学習開始してから放置し始めて食らうことが多いです。

  • 暗号通貨の発掘などは使用禁止
  • 90分間セッションが切れると環境が元の状態に初期化されます
  • 連続使用は12時間まで

JupyterNotebookでの記述がなんともWordpressのブロックエディタのようだけど、分割して実行するのはちょっと便利ですね。
しかしエディタで見るとpythonコードが読みづらくなるので、ipynb形式に対応したエディタで操作しないといけないのが辛いです。

まずは Colab の初期登録。
JupyterNotebookでチュートリアルが出るので見たい人は見て、見なくていい人は
ファイル -> Python3の新しいノートブックを選択(Python2は2020年1月に無くなるので3にしたほうがいい)

Colabの初期設定だとCPU使用になるためTPUへ設定変更
ランタイム -> ランタイムのタイプを変更 -> ハードウェアアクセラレータ を 早いらしい TPU に指定します。

自分の用意した画像(9000枚ほど)を学習させたいのでGoogleDriveと連携します。

from google.colab import drive
drive.mount('/content/gdrive')

連携する場合、新しいタブを開くリンクが出るので選択し、GoogleDrive権限の許可を行うと AuthorizationCode が出力されます。
AuthorizationCode を、 JupyterNotebook 側の指定箇所に貼り付けしEnterすることでマウントされます。

GoogleDriveは以下ディレクトリが出来上がっています。

マイドライブ\Colab Notebooks

アップロードするファイル構成は以下の通りです。

data/train
	hogehoge/1.jpg ~ 45.jpg
	fugafuga/1.jpg ~ 45.jpg
	nikoniko/1.jpg ~ 45.jpg
	tajitaji/1.jpg ~ 45.jpg
        ....
data/val
	hogehoge/45.jpg ~ 50.jpg
	fugafuga/45.jpg ~ 50.jpg
	nikoniko/45.jpg ~ 50.jpg
	tajitaji/45.jpg ~ 50.jpg
        ....

学習用データがtrain、評価用データがvalです。
ひとまず一種類50枚以上集めたあと、
1割をランダムで選定して評価用データに入れ込みます。
学習結果が悪かったらそのとき追加すればいいかと。

なぜだかDriveのデータが反映されなかったので再度実行します。

from google.colab import drive
drive.mount('/content/gdrive')

content/MyDrive/内に全てのデータが反映されています。
うーん。その下に勝手に作られたColab Notebooksはあるんだけどそこだけマウントしてくれないのかな。
そしてGoogleDriveがよく固まります。仕方ないのでWindowsアプリケーションのGoogleDriveをインストールします。

colabのtensorflowは1.15.0なのでちょっと古いバージョンへ戻します。

pip install tensorflow==1.13.1

ipynbはGoogleDriveに入れておけば読み込めるかな?と試したところ、
colab側でファイルとして認識するまでがとても遅く、 ipynb はアップロードする形にしました。

画像検知用語

画像検知において、結果は確率で表します。
結果として、特に一番確率が高いものを提案しますが、
最後は人間がそれは何なのかを判断することになります。

例えば白を黒と認識する人がいたとしましょう。
誰がどう見ても画像に映るのもは白であり機械も白と答えているけれども
検知システムを使用した人が黒だと言えばそれは間違いになってしまうことになってしまいます。

そのため、検知システムでは正解と不正解は学習段階では正しく認識させる必要があります。
正しいラベルでの分別をした場合の認識では結果は以下の4つに分かれます。

  • True Positive : 画像に目的のものが写っており、検知システムは目的のものを検知できた
  • True Negative : 画像に目的のものが写っておらず、 検知システムは 目的のものを検知できなかった
  • False Positive : 誤検知した。画像に 目的のものが写っていないが、検知システムは認識した
  • False Negative : 誤検知した。画像に目的のものが写っており、 検知システムは 目的のものを検知できなかった

True Positive と True Negative は把握しやすいですが、
検知したいものがリンゴの場合、 False Positive は赤いボールだったりするかもしれません。
False Negative はリンゴの断面かもしれません。

ということはリンゴの精度を上げたいは2つのアプローチが出来ます。

1. False Positive を True Negative へ出来るだけ変えていく
リンゴとはこういうものだ、という特徴あるものを認識させていく。
しかし、その学習によってリンゴだけど形がいびつなものがFalse Negativeとして増えていくことになるかもしれない。

2.False Negative を True Positive へ出来るだけ変えていく
リンゴの断面の学習を行ってみる。
しかし、その学習によってリンゴの断面ではないものがFalse Positiveとして増えていくことになるかもしれない。

というわけで、トレードオフになってしまうのでどう舵取りをするか、という点は目的に応じて変える必要があります。

OpenCVサンプルの比較

mobilenetSSD,TensorFlow,Yolo3tinyがOpenCVforUnityには揃っているので
CC0ライセンスの画像を利用してどんな結果になるかを調査します。
それぞれ、「車」、「人」、「モニタ複数」、「モニタ単品」を写します。

MobileNet SSD

全体的に高い確率で認知できました。
学習の重みが良いのでしょうか。アルゴリズムが良いのでしょうか。
難点としては、デフォルトのデータだと21種の画像しか判別がつかない点です。

TensorFlow

TensorFlowのサンプルは他とは違い、1000種類近く見分けられるようです。
物体検出というよりは分類と信頼性のみの表示になっていました。
ラベルの中に人が入っていないため、カツラやメガネと認識しました。
また、モニタのところを机と認識したりしています。

Yolo3tiny

大きい画像の認識が甘い結果になりました。
また、顔の認識に関して、男の人は認識できませんでした。

MobileNet SSD を掘り下げる

MobileNet SSDのサンプルでは、 caffemodel と prototxt がありますが、元のデータはGoogleDriveからのDLで、作り方など見当たらないです。
そのため、 MobileNet ならtensorflowでも作れるはず、ということでmobile.pbと mobile.txtを作ってみます。

今までの情報をまとめたところ、個人での優秀な物体検知をするには大きくコストがかかります。
理由は、画像を多量に用意し、その画像を多量に学習させる必要があるためです。
そのため、既に優秀な学習済みデータを利用し、転移学習やファインチューニングによって
個人でも優秀な物体検出をしよう、もしくは 優秀な学習済みデータ はそのまま利用し、
その他分類はより単純なアルゴリズムで、というアプローチが良いようです。

上記は花の分類ですが、ひとまずローカルで学習してみます。
数分で500回の学習を完了、学習済みモデルが出来上がりました。ここは環境さえ出来てしまえば簡単。

更に、4000回学習させます。

これをUnityのOpenCVに読み込ませます。エラーが出て失敗します。(PythonのOpenCV4.1.0ではエラーが出ないので読み込めていると思われる)

# dnn::forward_14() : OpenCV(4.1.0-dev) C:\Users\satoo\Desktop\opencv\modules\dnn\src\dnn.cpp:524: error: (-2:Unspecified error) Can't create layer "input_1/BottleneckInputPlaceholder" of type "PlaceholderWithDefault" in function 'cv::dnn::dnn4_v20190122::LayerData::getLayerInstance'

“input_1/BottleneckInputPlaceholder” of type “PlaceholderWithDefault”のレイヤーを作成できなかった、と。

Googleで検索すると、optimize_for_inferenceで削除するといいよ、という情報が出ます。

そこで、そのレイヤーの削除を行います。

よっしゃ出来た、OpenCVで読み込んでやろう。はい、Unityがクラッシュするようになりました。
クラッシュ原因を調査するために Util.setDebugMode(true,true)にし原因を特定します。

import tensorflow as tf

from tensorflow.python.tools import optimize_for_inference_lib
from tensorflow.tools.graph_transforms import TransformGraph

with tf.gfile.FastGFile('tf_files/optimized_graph.pb', 'rb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())
    graph_def = optimize_for_inference_lib.optimize_for_inference(graph_def, ['input'], ['final_result'], tf.float32.as_datatype_enum)
    graph_def = TransformGraph(graph_def, ['input'], ['final_result'], ['remove_nodes(op=PlaceholderWithDefault)', 'strip_unused_nodes(type=float, shape=\"1,224,224,3\")', 'fold_constants', 'sort_by_execution_order'])
    with tf.gfile.FastGFile('tf_files/final_graph.pb', 'wb') as f:
        f.write(graph_def.SerializeToString())

tensorboardで出来上がったものを可視化します。

python -m tensorflow.python.tools.import_pb_to_tensorboard ^
--model_dir=tf_files/final_graph.pb --log_dir=logs

tensorboard --logdir=logs

localhost:6006 へアクセスし、PlaceholderWithDefaultが無くなっていることを確認。

更に、分類がうまくいくかチェック

python -m scripts.label_image ^
--graph=tf_files/final_graph.pb ^
--image=tf_files/test01.jpg

うまく行ったらこれをOpenCVで読み込むと読み込めるようになりました。
しかしUnityとPythonでの実行結果に差異が出ることに。

Python側はリンゴじゃない?と言い、Unity側は陰陽マークであると主張しています。
同じ学習済みモデルを利用しても、使い方が違うのか別のものと認識してしまいます。

python -m scripts.label_image ^
--graph=tf_files/final_graph.pb ^
--image=tf_files/test01.png

あれ?座標情報がない。
リザルトは1×98の行列で、パラメータはfloat値なでprobabillityしか帰ってきていない。
単純な分類器って書いてあるからその辺を考慮していないのか…。
欲しい物は 0.5を超えたprobabillity,name,boundingboxで
これだとここに写っているものはなんでしょう?だけになってしまいます。

欲しいものは分類器ではなく物体検出

学習データを作ってみる(失敗)

上記のTensorFlow版をDLして中を見ます。また新しい形式が出ました。ckptファイルです。

  • mobilenet_v1_1.0_224.ckpt.data-00000-of-00001
  • mobilenet_v1_1.0_224.ckpt.index
  • mobilenet_v1_1.0_224.ckpt.meta

上記の記述によると、以下の内容のようです。サッパリですが、metaデータから復元しpdファイルの作成ができるようです。

data : TensorBundleコレクションであり、すべての変数の値を保存します。
index : 文字列と文字列の不変のテーブル(tensorflow :: table :: Table)です。各キーはTensorの名前であり、その値はシリアル化されたBundleEntryProtoです。 BundleEntryProtoは、テンソルのメタデータを記述します。 テンソルのコンテンツ、そのファイルへのオフセット、チェックサム、いくつかの補助データなどが含まれます。
meta : 保存されたグラフ構造を記述 。 GraphDef、SaverDefなどが含まれます。 これを適用し復元します。

とりあえず、pbファイルを出力してtensorboardで見てみようじゃないか。

checkpointを読み込んでpbファイルに保存する を参考にしてみます。

import tensorflow as tf
from tensorflow.python.framework import graph_util

# デバイス情報を削除する
CLEAR_DEVICES=True
# 保存先のpbファイル名
FROZEN_MODEL_NAME="frozen_model.pb"
# pbに書き出すoperation名
OUTPUT_NODE_NAMES="final_result"

graph = tf.get_default_graph()

sess = tf.Session()

saver = tf.train.import_meta_graph('mobilenet_v1_1.0_224.ckpt.meta', clear_devices=CLEAR_DEVICES)

# graph定義を取得する
graph = tf.get_default_graph()
graph_def = graph.as_graph_def()

# print operations
print_graph_operations(graph)

# print nodes
#print_graph_nodes(graph_def)

with tf.Session() as sess:
    saver.restore(sess, 'mobilenet_v1_1.0_224.ckpt')
    # tf.VariableをConstに変換したgraphを取得する
    output_graph_def = graph_util.convert_variables_to_constants(sess,graph_def,OUTPUT_NODE_NAMES.split(","))
    # pbファイルに保存
    tf.train.write_graph(sess.graph_def, '.', FROZEN_MODEL_NAME, as_text=False)

KeyError: ‘SSTableReaderV2’ で出力できない。
他では成功している、などの記述があるためTensorFlowのバージョン依存とかなんだろうか。
だがバージョンを変えるのは地雷多そうなのでやめます。

自分のPCで再現できる物体検出を探す

残念ながらMobileNet SSDv1 は失敗した。

cv2.error: OpenCV(4.1.0) C:\projects\opencv-python\opencv\modules\dnn\src\tensorflow\tf_importer.cpp:530: error: (-2:Unspecified error) Const input blob for weights not found in function 'cv::dnn::dnn4_v20190122::`anonymous-namespace'::TFImporter::getConstBlob'

MobileNet SSDv2 は成功!

あとはfrozen_inference_graph.pbをOpenCVで読み込めるかをチェック…の前に、pbtxtが付属している。
テキストで見れるけど明らかにpbファイルより少ない。APIで引き渡しているconfigという名だが拡張情報なのだろうか。
テキストでProtobuf形式で見れるけど、具体的にそれが何を意味するかが理解できていない。

この pbtxt は転移学習の際に影響を与えるものではないようです。
frozen_inference_graph.pb をOpenCVで読み込んでみると、エラーが出ます。
エラー内容は以下のものです。

CvException: dnn::readNetFromTensorflow_11() : OpenCV(4.1.0-dev) C:\Users\satoo\Desktop\opencv\modules\dnn\src\tensorflow\tf_graph_simplifier.cpp:860: error: (-215:Assertion failed) nodesMapIt != nodesMap.end() in function 'cv::dnn::dnn4_v20190122::sortByExecutionOrder'

でも、OpenCVのほうではMobileNet SSD、サポートしてます!というものが見つかります。

というわけで、サポートしているらしいので、何かしらが足りていない、らしい。
そこでOpenCVのWikiのリストを見ると、「 TensorFlow Object Detection API 」と書いてある。

ここにpbtxtの作り方が載っていた。

# tensorflow + faster_rcnn の場合
python tf_text_graph_faster_rcnn.py --input /path/to/model.pb --config /path/to/example.config --output /path/to/graph.pbtxt

そこで、ModelZooの「 ssd_mobilenet_v1_coco 」をDLします。

ここにもckptシリーズが出ました。
そこでckptとはなんぞや?ということで、実際にトランプを検出するものを作った方の動画を見ます。(約30分)

なるほど、ckptはチェックポイントで、数分ごとに勝手に出力される、
学習中のデータであるとともにその時点でpbファイルを作る元になる、と。

ということでmodel.ckpt系はfrozen_inference_graph.pbを作る元、ということですね。

で、この frozen_inference_graph.pb を元にpbtxtを作るにはtensorflowで学習する際に使用したconfigファイルが必要です。
ssd_mobilenet_v1_coco の場合は以下にあります。

で、このssd_mobilenet_v1_coco.configと frozen_inference_graph.pb を利用してpbtxtを作ります。

まずOpenCVをDLします。

opencv-master\samples\dnn\ へ ssd_mobilenet_v1_coco.config , ssd_mobilenet_v1_coco_2018_01_28_frozen_inference_graph.pb をコピーします。

コマンドプロンプトを開き、dnnディレクトリまで進み、pythonで以下のコマンドを叩きます。

python tf_text_graph_ssd.py --input ssd_mobilenet_v1_coco_2018_01_28_frozen_inference_graph.pb --config ssd_mobilenet_v1_coco.config --output ssd_mobilenet_v1_coco_graph.pbtxt

すると、ssd_mobilenet_v1_coco_graph.pbtxtが出来上がるので、
これをDnn.readNetFromTensorflowの二番目の引数に入れ込めば読み込みが成功するようになります。
あとはClassesを用意すればいいので、以下のpbtxtを参考にテキストファイルを作成します。

上記を参考に、IDが無いものはスキップしてテキストファイル化(mscoco_label_map.txt)

?00
person
bicycle
car
motorcycle
airplane
bus
train
truck
boat
traffic light
fire hydrant
?12
stop sign
parking meter
bench
bird
cat
dog
horse
sheep
cow
elephant
bear
zebra
giraffe
?26
backpack
umbrella
?29
?30
handbag
tie
suitcase
frisbee
skis
snowboard
sports ball
kite
baseball bat
baseball glove
skateboard
surfboard
tennis racket
bottle
?45
wine glass
cup
fork
knife
spoon
bowl
banana
apple
sandwich
orange
broccoli
carrot
hot dog
pizza
donut
cake
chair
couch
potted plant
bed
?66
dining table
?68
?69
toilet
?71
tv
laptop
mouse
remote
keyboard
cell phone
microwave
oven
toaster
sink
refrigerator
?83
book
clock
vase
scissors
teddy bear
hair drier
toothbrush

OpenCvNetクラスのreadClassNamesでclasses情報が取得出来たので、これで物体検出は出来た!
あとは自分で作ったデータをファインチューニングさせて作るところができれば行けそうですね!

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください