この記事で扱っていること
- アドオンを使用しないで画像分類プログラムを作る方法
を紹介しています。
注意:すべてのエラーを確認しているわけではないので、記事の内容を実装する際には自己責任でお願いします。また、エラー配線は適当な部分があるので適宜修正してください。
以前別の記事で、画像分類プログラムを作成する方法を紹介しました。
以前の記事では、Vision Development Moduleという、画像処理用の関数が揃ったLabVIEWのアドオンから使用できる、Deep Learning用の関数を用いた実装としています。
画像分類が行えるように学習されたモデルを用意すればそのモデル(ファイル)をロードするだけで画像分類ができるのですが、この有償アドオンがないと使用できません。
今回の記事では、アドオンなしでも、つまりLabVIEWだけでも、画像分類を行えるような方法を紹介します。
・・・ただしLabVIEWにそのような機能が標準でついているわけではないので、Pythonのスクリプトを呼び出しています。
「なら全部Pythonでよくね?」なんて言わないで、見て頂ければと思います。
アドオンを使用しないで画像を表示する必要がある関係上、ピクチャの関数を使用しています。
ピクチャ関数について細かくは説明していないので、もしこれらの関数に不慣れということであれば先に以下の記事を見ておくといいかなと思います。
なお、画像分類のモデルとしては以前の記事同様Inception V3を用います。
どんな結果になるか
フロントパネルには、画像ファイルを指定するためのファイルパス制御器と、指定した画像を表示させる2Dピクチャ表示器、そして画像分類の結果を表示する部分があります。
プログラムを実行し適当に画像を与えることで、その画像が何であるかを表示してくれます。
プログラムの構造
プログラムのコアとなる、画像分類の処理自体はPython任せです。LabVIEWは結果だけ受け取ります。
以下に紹介するブロックダイアグラムは、LabVIEW 64 bitで作成しています。
これは、呼び出すPythonが64 bitのものを入れたPCを使用しているからです(つまり、PythonスクリプトとLabVIEWのビット数は同じにする必要があります)。
全体の構造としてはイベントストラクチャを置いたイベントベースのプログラムであり、イベントは二つだけです。
イベントストラクチャが入ったWhileループの外にあるのはPythonセッションを開く関数と、後で紹介するPythonスクリプトのファイルパスです。
イベントとしてJudgeボタンを押した後のイベントでは、Pythonスクリプトに対して、どの画像を対象にするかという情報と、予想結果をいくつ表示するかの数値を渡します。
フロントパネルに表示させる画像としてはピクチャに表示させるためにピックスマップに平坦化関数を使用します。
なお、イベントストラクチャの中に時間のかかる処理を入れておくのは本来いいプログラムではありません。
しかし今回の場合Python側の処理にある程度時間がかかることを考えると、その処理が終わらないとどっちにしろ次の画像の判定ができないため、イベントストラクチャの中に入れても入れなくても変わらないと思いこのようにしています。
もちろん、画像分類以外の処理を行わせるように複数のループにメッセージを渡すようなキューメッセージハンドラタイプのプログラムの場合にはちゃんとイベントストラクチャのループ以外のループで処理を行わせるようにします。
Pythonのコードは以下の画像を参考にしてください。numpy等、必要なモジュール等はあらかじめ用意する必要があります。
LabVIEWで呼び出す前にこのスクリプトを試してモジュール等が揃っているかを確認するのがオススメです。
PythonとLabVIEWの連携の基本的な方法は以下の記事が参考になると思います。
なお、Pythonのスクリプトを指定するパス、つまりPythonスクリプトファイルを配置しているディレクトリパスには日本語が入っていない方がいいようです(日本語が入っている場合エラーが起こることがあります。)
もう一つのイベントは単にWhileループを終了させているだけです。
画像の一部を切り取って判定させる場合
もし画像に複数の「分類されるもの」がある場合、ピンポイントで画像の一部を切り取って判定させたいことがあるかもしれません。
例えば、犬と猫が写っている画像を渡しても、結果には犬の情報しか出ない場合があり得ます。
今回のPythonスクリプトには、画像のファイルパスを入力しているので、画像の一部を切り取ったものを一度保存してこれをPythonに渡してやればよさそうです。
そこで、Adjustのボタンを新たに配置しています。
このAdjustのボタンを押すと別画面が開いてどの部分を抽出するかを指定できるようにしています。
ついでに、2Dピクチャ上に表示する時点で、画像のサイズに応じて2Dピクチャの大きさ自体もフィットするように処理を加えます。
Adjustのボタンの値変更イベントを追加しているわけですが、処理としては以下のものを考えました。
Judgeボタンの中身とほとんど同じ、ですが、create_picture.viというサブVIを追加しています。
サブVIの中身は以下のようにしています。
サブVIへの入出力はファイルパス制御器および表示器だけです。実際にこのサブVIを操作する時点ではファイルパス制御器などは見えている必要がないため、ウィンドウのサイズを変更して、ファイルパス制御器や表示器は見えないようにしておきます。
ブロックダイアグラムの前半部分は以下のようにしています。
フロントパネル上の数値のスライダの上限値をプロパティノードの「スケール/最大」で決めています。
続いて中間部分です。
ここはイベントストラクチャを使用してもいいのですが、別にパフォーマンスを求める部分でもないのでポーリング処理として単に待機の関数を置くだけにしています。Whileループを出る際に4つのI16の数値を外に出しますが、並びの順番に注意してください。
後半部分は以下の図のようにしています。
Whileループから出した4つの数値でピックスマップの画像配列の一部を抽出しています。
このようなサブVIを含めてメインVIを実行すると、「~~_mod.jpeg」などといった画像が生成されます。
これはもちろん、サブVIで生成した、元画像の一部を切り出した画像、ということになるのですが、これが不必要な場合には、プログラムの中で「削除」の関数(ファイルIOのパレットの上級ファイル関数にあります)を使用して、プログラムが終わった時点で生成した画像を削除するようにします。
この記事では、画像分類プログラムを画像処理用のアドオンソフトであるVision Development Moduleを使用せずにLabVIEWで実装する方法を紹介しました。
プログラムとしてはPythonのスクリプト(とPythonの実行環境)があればできてしまうので比較的楽な方かなと思うので参考になればうれしいです。
ここまで読んでいただきありがとうございました。
コメント