この記事で扱っていること
- 標準関数だけでラインプロファイルを取得する方法
を紹介しています。
注意:すべてのエラーを確認しているわけではないので、記事の内容を実装する際には自己責任でお願いします。また、エラー配線は適当な部分があるので適宜修正してください。
LabVIEWで画像を扱う際に使用するアドオンソフトであるVision Development Module、これは画像解析に使える強力なソフトですが、LabVIEWとは別途購入する必要があります。
ただ、LabVIEWだけでもある程度の画像操作は行うことができ、ピクセルの2次元配列とみなしてがちゃがちゃ配列処理をすることで目的の動作が達成できたりします。
今回の記事では、ラインプロファイルとして、画像上にユーザーが引いた直線に沿ったピクセル値のグラフ表示を行う方法を紹介しています。
なお、ピクチャの扱い方について以下の記事の内容を知っていると本記事の内容をより理解できると思いますので、適宜参考にしてみてください。
どんな結果になるか
フロントパネルには、画像を表示させるためのピクチャ表示器や画像ファイルを選択するためのファイルパス制御器、ユーザーが引く直線の色を指定するカラーボックスがあり、結果を示すためのグラフや数値のクラスタがあります。
プログラムを実行し、ピクチャ上に線を引くと、その線を「左から右に」見た時のピクセル値の変化がグラフで表れ、またそれらの値に対しての簡単な解析結果(最大値など)を表示します。
なお、縦にまっすぐ線を引いた場合には「上から下に」見た時の変化を表示します。
もちろん、斜めに引いても対応できます。
プログラムの構造
Vision Development Moduleを使用しない場合に画像を扱う方法としてあるのがピクチャ制御器やピクチャ表示器です。
線や四角などを描画する際には、サンプルファインダにあるサンプルをベースにするのが簡単です。
サンプルを新規のviに丸々コピペして、ここをベースに機能を作り替えることをオススメします。
イベントベースで作成することで、ユーザーの操作に無駄なく反応させることができます。
イベントは7つあって結構多いですが、サンプルからコピペした場合、ほとんど作り直す必要はなく、「要らない機能を消す」だけで構成できるイベントが多いので、実装はそこまで大変ではないと思います。
まずはピクチャのマウスダウンイベントです。
サンプルをベースにしている場合、ケースストラクチャを消して以下のような構成のみとします。
次にマウス移動イベントです。こちらもサンプルにあったマウス移動イベントに少し手を加えるだけですね。
次にマウスアップイベントです。このイベントが、最も編集を加える部分になります。
マウスダウンしてからマウスアップした段階で線分が確定するので、このときにこの線分の直線の式を計算し、線分の範囲内でXやYの値を代入して対応するYやXの値を計算し配列とみなした画像から各ピクセル値を抽出していきます。
それぞれのサブVIの中身を見ていきます。
まずはcalculate_line.viです。
フロントパネルおよびコネクタペーンは次のようにしています。
ユーザーが引いた線分の始点と終点の情報から、直線の式を導きます。
こういった演算は、フォーミュラノードを使ってテキスト言語風に書いた方がすっきりします。
ここで注意するのは、y=ax+bという式だけでなく、x=ay+bという形式でも式を導いている点です。
後半の実装としては、直線の式、例えばy=ax+bのaとbを計算した後に、xの値を入力してyを求め、これら(x,y)のペアの配列を求めて、次のサブviに渡すことになります。
このときの前提としては、「xの値が変化する直線」です。なぜなら、y=ax+bはxが変化しなければyの値は一定になるからですね。
しかし実際にはユーザーはもしかすると縦に線を引くかもしれません。その場合、xの値は変化しないものの、yの値は変化しているはずで、この場合のピクセル値の変化をグラフ表示するためにはy=ax+bにxを代入するだけでは処理をうまく進められなくなります。
つまり、xが全然変化しないような直線に対しても対応するためにx=ay+bという直線の式を求めyの値を入力しxを求めた状態での(x,y)のペアもあわせて求めておきます。
なお、無意味に2Dピクチャの制御器と表示器があるように見えますが、これはメインのVI上でワイヤを一直線につなげるために敢えて設けています。
次のサブVIがextract profile.viです。
フロントパネルおよびコネクタペーンは以下の通りです。
エラーの入出力をつけていませんが、それは気持ち悪い、と思う方は適宜つけてください。
こちらでは、先ほど求めた「y=ax+bへ線分範囲のxを代入し求めた(x,y)」と「x=ay+bへ線分範囲のyを代入し求めた(x,y)」それぞれに対して、ピクチャを2D配列に変化させた結果からそれぞれ(x,y)の値に対応する配列要素を抽出するという操作をしています。
なお、今回の例では画像は「24ビットピックスマップ」となっていると仮定しており、「色をRGBに変換」の関数を使用して8ビットの情報に変換しています。
カラー画像で特定の色に対してプロファイルを見たいという場合にもこの組み方をして、R、G、B好きな出力の値を抽出します。
それぞれのForループから抜けた後には、配列サイズを調べて、より配列サイズが大きい方の値をライン情報として取得しています。
つまり、y=ax+bとしてxの値を代入していって(x,y)のペアを作った場合と、x=ay+bとしてyの値を代入していって(x,y)のペアを作った場合とで、どちらがペアの数が多いかを判断しています。
こうすることで、縦や横にひかれた線分であっても、より最適な方の線分に沿ってピクセル値の情報を表示させるようにします。
最後のサブVIはprofile_analysis.viです。
配列最大最小や標準偏差と分散の関数を使用してライン情報の配列から解析結果を抽出しています。
今回のサンプルの「山場」はこれで終わりです。
メインVIの方に戻りまして、マウス境界外やマウス境界内、そして停止ボタン値辺ののイベントもほぼサンプル通りの実装としています。
この辺りのイベントは、なくても動作しますが、ユーザーが「ピクチャ上で線を書けるのだな」ということがわかりやすくなるので、使い勝手の面で意外と重要だったりします。
停止イベントも、ただ単にWhileループを止めるためだけにあります。
最後のイベントはファイルパスの値変更イベントで、新しい画像ファイルが指定されたときにその画像を表示させます。
標準関数で扱える画像はbmp、jpeg、pngであり、どの画像が選択されてもいいようにファイル拡張子を取得の関数とケースストラクチャを組み合わせています。
ピクチャが入りきらない場合
今回のプログラムでは、ピクチャ表示器は最初にフロントパネルに用意した大きさとなっているため、もし選んだ画像がかなり大きい場合、元々用意していたピクチャ表示器に収まらない、ということが起こりえます。
対策の一つとしては、画像のサイズに合わせてピクチャ表示器の大きさを変える事ですが、その場合、上で紹介したプログラムとは、レイアウトを変えた方がいいです。
より良いレイアウトの一例が以下の図のような配置です。
ピクチャの大きさを変えるときに、左上座標の位置は変わらずに右下方向に延びたり縮んだりするため、ピクチャ表示器自体を残りのどの制御器や表示器よりも下部に配置すると都合がよくなります。
このようなレイアウトにした状態で、以下のように機能を追加します。
なお、ピクチャ部分は別ウィンドウで表示させる、という手もあると思います。
操作画面と結果画面を分離させる、といった考え方ですね。
その場合、ピクチャ表示器上で引いた線の情報を結果画面に伝える必要があります。
実装の方法は例えばグローバル変数を使用するという方法もあるとは思いますが、キューを使用した方法の方がスマートだと思います。
組み方の考え方についてはQMHチックになるので、以下の記事を参考にしてもらえると思います。
本記事では、標準関数だけでラインプロファイルを取得する方法を紹介しました。
単純にラインプロファイルを知りたい場合のみならず、例えばエッジ検出(ピクセル値の変化が大きいことで判断)にも役立てると思いますので参考になればうれしいです。
ここまで読んでいただきありがとうございました。
コメント