この記事では、LabVIEWで動画を扱う方法を解説しています。
LabVIEWは計測やテストを行うアプリケーションを作りやすいプログラミング言語です。ハードウェア操作と相性がいい、とも言えますね。
もともと、プログラミングを得意としない人たちに向けて開発されたプログラミング言語だ、といったような宣伝文句をどこかで見たことがある気がしますが、だからといってやれることが限られるわけでもなく、National Instruments社のハードウェアはもちろん、サードパーティの計測器も幅広く扱えたりします。
計測というとセンサで温度や電圧といった信号を測るというイメージが強いと思いますが、画像情報も立派な計測対象です。画像に対してのセンサはカメラが対応します。
カメラで画像を撮るというところから派生して、いやいや一つ一つの画像じゃなくて連続した画像、つまり動画を扱いたいんだ、という要求にもLabVIEWで対応できます。
LabVIEW自体だけだと、一応簡単な画像処理的なことは追加ソフト無しでできますが、カメラを動かすのは難しいです。そこで、Vision Acquisition Software(以下VAS)というアドオンソフトを使用することでカメラの操作、ひいては画像、動画を扱えるようになります。(厳密にいえば、カメラメーカーによってはカメラを操作するdllを提供していて、これをLabVIEWで使用するというケースもあるみたいですが)
以下では、LabVIEWで動画を扱う際の最もオーソドックスな方法である、VASを使用したプログラムの考え方を中心に紹介していきます。
VASでビデオを扱う際の注意点
いきなりですが、VASでビデオを扱うときの注意点については最初に紹介しないといけません。それは、特定のビデオ形式しか扱えない、ということです。
具体的にはAVIというビデオ形式しか扱えません。一応昔からある動画の形式であり、色々なコーデックを使用できるのですが、なにはともあれこれ一択です。
もし他の動画形式も扱いたい場合、動画の保存はできないもののWindows Media Player(以下WMP)を呼び出してフロントパネル上で再生するといったような力業もできなくないです。今回の記事のメインはVASを用いたAVIファイルの扱い方なので、WMPは最後におまけとして紹介します。
AVIファイルを扱うのに必要な関数と基本的な考え方
LabVIEWでVASを使用する場合にはAVIファイル一択であるということを紹介しました。では、実際にどのように扱うか、それはもちろんAVI専用の関数を使うわけですが、実はそんなに種類が多いわけではありません。それぞれの関数の役割もはっきりしています。
ありがたい(?)ことに、この7つの関数の役割を覚えてしまえばLabVIEWでAVIファイルを扱うプログラムを組むことができます。
動画は、「再生する」場合と「作成する」場合があると思いますが、どちらであってもプログラムを組むうえでのベースの考え方は共通していて、以下の3つのステップがあります。
- (ファイルを)開く
- (ファイルに対して)操作する
- (ファイルを)閉じる
これ、実はLabVIEWでとてもよく出てくる「型」になっています。
テキストファイルなどを扱うファイルIOの関数も上の3つのステップと同じ形式ですし、計測器を扱う場合も似たような考え方で組むことができる場面が多いです。なので、この一連の流れに慣れてしまえば、LabVIEWで初めて扱う関数群も、何となく使い方がわかるようになったりします。
話がそれましたが、ここからはサンプルを例に、動画(AVIファイル)の再生、および作成を行うプログラムの仕組みを紹介します。
再生について
まずAVIファイルの再生の仕方です。後述するAVIファイルの作成はカメラの操作を伴うため、上で紹介したAVIの関数だけではできない(既存の画像があればその限りではないですが)のに対し、再生はAVIの関数とあとは一般的な関数で完結することが多いです。
サンプルは、LabVIEWのメニューバーにある「ヘルプ」から「サンプルを検索」で開く「NIサンプルファインダ」のサンプルを使用します。
検索タブでAVIをキーワードに調べるとサンプルがヒットすると思いますが、ここではRead AVI File.viを例にとります。
このプログラムでは、AVIの関数が4つ使用されています。
最初の関数はAVIファイルを開くための関数です。AVIファイルのファイルパスを指定して「今からこのAVIファイルを扱いますよ」という準備をします。
これより前にある関数は全て、ファイルを指定するための処理です。別にこれらの関数を使わなくても、代わりに例えばファイルパス制御器を使用する方法で何の問題もありません。
AVIファイルを開く関数から緑色のワイヤが出力されていますが、これは「今指定したAVIファイルの情報」を次の関数に渡すようなリファレンスの役割をしています。プログラム全体にわたってAVIの関数にこのリファレンスを渡すことで、その特定のAVIファイルに対する操作を実現していきます。
次の関数は、AVIファイルの中の情報を取得する関数になっています。
ここで言う情報とは、例えばFrames Per Second、つまり一秒あたりのフレーム(画像)数の情報であったり、フレームの総数、画像タイプ(グレースケールなのかRGBなのかといったもの)、画像の縦および横の大きさ、そのAVIファイルが作成された際に使用されたコーデック、そして「データ」を持っているかといった情報なんかもあります。
「データ」とは、AVIファイルの各画像に対し紐づけられた何かしらの(数値)データです。この記事ではあまり詳しく説明はしませんが一応後で少し紹介します。
さて、続くプログラムの中でAVIファイルの情報はいくつか活用されて、まずは画像タイプの情報をIMAQ Createに使用しています。IMAQ Createの関数は、LabVIEWでVASを使用したプログラムを書くときには必ずと言っていいほど使用する関数で、のちに使用する「AVIファイルから画像を抜き出して表示する」ための関数へ画像自体のメモリリファレンスを渡すために、メモリリファレンスを作る関数になっています。大雑把に、画像を扱うにはこの関数が必要、と思ってください。
また、AVIファイルの情報の一つであるで1秒当たりのフレーム数は「AVIファイルからどの程度の早さで各画像を抜き出して表示するか」を指定するのに使用されています。
このサンプルでは、フレームの総数の情報がForループの回数の指定以外もプロパティノードに使用されていますが、プロパティノードの使用は必須ではありません。要は、あらかじめAVIファイルの長さ(画像の多さ)がわかっているので、それらの画像の内今何番目の画像を表示しているかといった情報(プログレスバー)をフロントパネルに表示する機能をつけているだけです。
さて、AVIの関数の3つめは、先ほどから出ている「AVIファイルから画像を抜き出して表示する」ための関数です。この関数に「何番目の画像を表示させるか」といった番号を入力します。
動画は画像の集まりなので、その集まっている各画像をForループで繰り返し読みだして表示するということをしています。
基本的にはすべての画像を最初から読み出すことになると思うのですが、それに便利なのがForループの反復端子です。反復端子は「今ループの何回目か」を出力してくれる端子であり、これを「何番目の画像を表示させるか」の指定に使用します。
反復端子は0から始まり、フレームの総数分ループが回ることで全ての画像を抜き出します。
で、このForループ、特に何もしないと一瞬で高速で回るため、動画が瞬く間に終了します。それを防ぐのがForループの上部にある3つの関数(種類は二つですが)になっています。これらはタイミングを制御する関数となっていて、これらのおかげでForループが適切な速度(1秒当たりのフレーム数に対応した早さ)で回るようになっています。
Forループの一回につき、一つの画像が表示されるわけですが、それを次の画像に切り替えるまでの時間の長さは、つまり「1フレームを表示し続けたい時間」のことです。これは「1秒当たりのフレーム数」の逆数になりますね。
IMAQ AVI2 Read Frameの前後で実行される二つの関数で「AVIファイルから画像を抜き出して表示する」という動作にかかった時間を測っています。その時間を、「1フレームを表示し続けたい時間」から引くと、Forループの繰り返しのタイミングを制御する待機の関数で待つべき時間が決まります。これを設定しているだけです。
(例えば1秒当たりのフレーム数が2だったとすると、1フレームは500ミリ秒表示することになります。このフレームを読み出す処理に100ミリ秒かかったとすると、残りの400ミリ秒経過してから次のループに進む必要があります。下の図の①と②で100ミリ秒が計算され、400ミリ秒待つのが③の部分です。実際はフレームを読み出す処理に100ミリ秒もかかることはないと思いますが)
あとは、Forループを抜ける、つまり動画が終わったら、動画ファイルを閉じる関数を使用して、プログラムでこのAVIファイルは使い終わりました、ということになってめでたく終了します。(厳密にはその後にIMAQ Createで作成した画像のメモリリファレンスを破棄しています)
開いて、操作して、閉じる、大まかにはこの流れになっているということがわかるでしょうか?
これがAVIファイルを再生するときの基本的な流れです。
作成について
次にAVIファイルを作成する場合です。こちらはカメラの操作を伴うことが多いと思います。
そのため、カメラ操作のための関数の使い方にも慣れる必要がありますが、今回はカメラ操作の関数についての説明は知っている前提で話を進めます。
サンプルはいくつかあるのですが、今回はStream to AVI Files (Optimized Performance).viを例にとります。
やはり、カメラの操作のための関数も使われていたりするので、再生の場合と比べるとブロックダイアグラムは一見「いかつい」感じがします。が、一つ一つはそこまで複雑なことをしているわけではありません。
最初はカメラの操作のための関数が続きます。AVI関係の関数で一番最初なのは、使用できるコーデックの一覧を取得する関数です。
AVIファイルを作成するときに、コーデック、つまり動画の圧縮や復元に使用する符号化形式の種類を指定することができます。ただもちろんどんなコーデックも使えるわけではなく、そのPCに入っているコーデックから選ぶことになります。この関数は、そのようなコーデックの種類を配列として出力します。
出力されたコーデックの情報は、Codecと書かれたテキストリング制御器に渡されるので、ユーザーがプログラム実行時に選べるようになっています。
ブロックダイアグラムで見ると真ん中のあたりに小さいWhileループがありますが、この中でコーデックを選んで、Startボタンが押されるとこのWhileループを抜け、選ばれたコーデックがAVIの関数である「IMAQ AVI2 Create」の関数に渡されます。
このIMAQ AVI2 Create関数には他の入力として「どこにAVIファイルを保存するか」というファイルパスを入力します。また、1秒当たりのフレーム数の指定を入力することもできます。
再生の時同様、「このAVIファイルを扱いますよ」というリファレンスを渡していくのですが、動作生成の場合には「書き込み」の関数であるIMAQ AVI2 Write Frameに渡しています。この書き込みの関数にはAVIファイルに含める画像を入力することで、AVIファイルに動画を書き込んでいきます。
動画を撮り終えたらWhileループは抜けて、再生の時と同じく、AVIファイルを閉じる関数を使用してプログラムを終えます。
なお、このサンプルはImages per AVIという制御器により、一つのAVIファイルに書き込む画像の枚数を指定することができます。撮影した画像がこれよりも大きい場合には新たなAVIファイルに書き込む、という動作を自動で行うようになっています。
再生時同様、これも結局は開いて、操作して、閉じる、です。
動画の作成の基本的な流れは以上です。
データとともに動画を生成、あるいは再生
動画再生のところで少し触れましたが、AVIファイルには、画像だけでなくその画像に付随した何かしらのデータを記録させることもできます。ある動画を撮影しているときの他の情報(何か数値を測定したときのその数値)を一緒に保存、あるいは再生することができるわけですが、注意点としては「通常関数パレットに表示されない関数を使う」ことになります。
この特殊な(?)関数は、C:\Program Files (x86)\National Instruments\LabVIEW XXXX\vi.lib\visionのフォルダ(XXXXはバージョン番号)にあるAvi1.llbとAvi2.llbに入っています。
「え、さっき使う関数は7個しかないって言ってたじゃないか」と言われそうですがご安心を。確かに、通常関数パレットに表示されない関数を使うのですが、それは「AVI」関数になります。
お気づきの方も多いと思いますが、これまで紹介してきたプログラムでは「AVI2」の関数を使っていました。関数パレットに通常表示されている関数をよく見ると、全部AVI2と書いてあると思います。AVIの関数もAVI2の関数もラインナップや基本的な使い方はほぼ同じなので、AVI2の関数の使い方さえ覚えておけば簡単にAVIの関数も扱えるようになると思います。
(ややこしいですが、通常関数パレットに表示される関数である「AVI2」は、上記のパスのAvi.llbに入っているのに対し、「AVI」の関数はAvi1.llbとAvi2.llbに入っています)
データとともに保存および再生するというプログラムもまたサンプルがあります。
細かくは説明しませんが、上で紹介した「再生」および「生成」の流れがわかっている方ならこのサンプルを読み解くのは難しくないはずです。
実行すると、波形データ等の数値のデータと画像データが保存され、その後にそのデータを再生でき、任意の位置のデータ/画像を確認できるようになります。
くどいようですが、やっていることは「開く」「操作(読み書き)する」そして「閉じる」の3つだけです。
これで、LabVIEWで動画を扱う際のAVIの関数を使用する流れの紹介は終わりです。
コーデックのどれがいいか選べないときには
さて、動画の生成時に話が出たコーデック、これは画像の圧縮率等の符号化形式になっています。
そんなこと言われてもどれがいいか分からないよ、という方もいると思います。私も、このコーデックはこういう時にオススメ、といったことを説明できるほど詳しくはないのですが、もし迷ったら、コーデックごとの比較を行ってどれがよさそうか確かめるのも一つの手だと思います。
サンプルで、コーデックを比較してくれる便利なプログラムがあります。これを使用することで、同じ複数画像を用いてAVIファイルにしたときの、ファイルのサイズや生成までにかかる時間、そして元の画像と動画ファイルの中の画像の違いをスコア化した、動画の品質の差を比較することができます。
コーデックでどれを選んだらいいかわからない!という場合には一度試してみてください。
以下の図は一例ですが、使用するPCの環境によって表示されるコーデックの種類などは異なります。
Windows Media Playerを使用する
最後におまけとして、VASの関数を使用しないで動画を再生する方法として、WMPを使用する場合を紹介します。
WMPはLabVIEWとは独立した外部のアプリケーションなので、読み出しにはActive Xを使用します。
フロントパネルにActiveXコンテナを用意したら右クリックして、Active X を選択します。Windows Media Playerを選択すると、それ専用の画面に早変わりします。
・・・なのですが、こんな操作をしなくても、WMP専用のオブジェクトがあらかじめ制御器パレットに用意されています。
後はプログラム的に表示したい動画を指定します。これにはプロパティノードを使用します。これでAVIファイル以外でもWMPで扱える動画形式例えばMP4も再生できるようになります。
以下がプログラム例です。
注意点としては、再生時、再生終了時といった状態が変わるごとに、コンテナ境界のプロパティの設定を行わないと、再生するビデオの大きさによってWMPの枠自身が大きくなってしまうことがあります。
そのために、上のプログラムでは、Whileループの中で「今の状態が終わったか」を確かめ、Whileループを抜けたらプロパティノード(これはプログラム一番左上のWindows Media Playerのリファレンスを右クリックして「作成」から選べます)を用意してコンテナ境界にWMPの枠の大きさを書き込んでいます。
実際はもっとプロパティノードの項目は多くありいろいろできるとは思いますが、今回の記事の本題からは外れるので割愛します。
また、フロントパネルとは独立してWMPを呼び出し表示させることもできます。以下にそのプログラム例を示しています。
この記事では、LabVIEWで動画を再生、保存する際に使用するAVIの関数の基本的な使い方を紹介してきました。
カメラを使用して状態を監視するといったアプリケーションを組む際に、こうした動画を扱うケースは少なくないと思います。
そんなに凝ったプログラムでなければAVIの関数は扱いやすい関数だと思うので、この記事が少しでも理解の助けになればうれしいです。
ここまで読んでいただきありがとうございました。
コメント