この記事で扱っていること
LabVIEWで簡易的に消しゴムマジックを実装する方法
を紹介しています。
注意:すべてのエラーを確認しているわけではないので、記事の内容を実装する際には自己責任でお願いします。また、エラー配線は適当な部分があるので適宜修正してください。
(はじめに。TV CMで扱われている、いわゆるGoogleの「消しゴムマジック」のようなAIを駆使して背景処理を行うといった内容を本記事で扱っているわけではないのであしからず)
スマートフォンに搭載された消しゴムマジックという画像処理機能、指で囲った部分に対して背景処理をして、余分な箇所を消しゴムで消すがごとくなかったことにできて便利ですよね。
LabVIEWでも頑張ればより近いことができるのかもしれないですが、AIを駆使した「賢い」方法で無ければ、マウスで囲った任意領域を特定の色で塗りつぶすことで疑似的に消しゴムマジックのような画像処理を行うことができます。
今回はVision Development Moduleを使用した場合の例を紹介しています。
どんな結果になるか
画面には、処理を行う前と行った後の画像を表示させるための画像表示器を用意していて、処理前画像でフリーハンドで囲った領域に対し特定の色を適用するためのボタンを用意しています。
ある程度くねくねした部分も消すことができます。
プログラムの構造
囲った部分を任意の色にする、というのが今回のプログラムのミソになります。Vision Development Moduleの関数で、IMAQ ROIToMaskだったりIMAQ FillImageという関数がありこれらが使えそう・・・かと思うのですが、IMAQ ROIToMaskがカラー画像に対して適用できないことから、ROIで囲まれた領域に対して特定の色をあてるように、画像全体を配列にして処理しています。
プログラム全体としてはイベントベースの構造を持っていて、消しゴムマジックのブールボタンを押したときだけ処理されるようにしています(下の図で示した以外に、停止ボタンに対するイベントもありますが省略しています)。
なお、後で紹介するサブVIに、IMAQ ROIProfileの結果を渡していますが、ここで渡しているのはROIを構成する座標の情報になります。
これらの座標の情報自体はROIのプロパティでもPointsとして取得できるのですが、ROIProfileの方がより細かく座標情報が得られているようだったので、サブVIで行う計算にはこちらを使用しました。
いくつかサブVIがありますが、これらのサブVIではROIで囲った領域を指定した色で塗りつぶすようにしています。
ROIで囲った領域はフリーハンドで書いた部分ですが、後で色を塗る際に、画像のある点がこの領域の中か外かを識別できる必要があるため、そのための準備を行います。
そもそも領域の中か外かを調べるために、まずは領域がX、Y方向どの範囲にわたっているかを調べます。(以下の図ではX方向の説明ですが、Y方向に対しても同様なことを行います)
X方向の範囲がわかったら、その範囲内の各Xに対するYの最大値、最小値を求めます。
キレイな四角のROIであればXに依らずYの最大値や最小値は変わらないですが、今回は任意領域なので各XごとにYの範囲は異なる可能性があり、これを先ほど調べたX軸の範囲すべてに対して調べます。
これを、X方向だけでなくY方向に対しても行います。
「え、片方だけでよくない?」と考える方もいるかもしれないですが、片方の場合、くねくねした領域をうまく処理できなくなります。
画像上のある一点に対し、X方向、Y方向どちらから調べても、上記で調べた範囲内にその点が属しているときだけ、「この点はROIで囲まれた領域内だ」とみなせます。
さて、こういった処理を実装しているのがサブVIですが、まずは「各X(Y)に対するY(X)の最大、最小を求める」のがGet Range Info.viになります。
Search Y MaxMinのブールの値がTRUEかFALSEかで、「各Xに対するYの最大、最小を求める」のか「各Yに対するXの最大、最小を求める」のかを指定しています。
次に、画像中のある点が調べた領域に属するかを調べるのがJudge ROI inout.viです。
こちらも、X Range ?のブールがTRUEかFALSEかによって、「対象となる点のX座標に着目した場合に対象の点のY座標が、ROIで囲まれた領域の同じXに対するYの最大最小の間にあるかどうか」を調べるか「対象となる点のY座標に着目した場合に対象の点のX座標が、ROIで囲まれた領域の同じYに対するXの最大最小の間にあるかどうか」を調べるかを指定しています。
調べた結果はブールの配列として得られて、「ある点がROIで囲まれた領域の中だったらTRUE」としています。
ケースストラクチャが入れ組んでいて、もう少しうまい組み方がありそうですが・・・ひとまず以下のような形で実装ができます。
さて、X軸方向に着目した場合、Y軸方向に着目した場合で、画像上のある一点がROIで囲まれた領域の中かどうかを判別しましたが、「X軸方向に着目した場合にはROIの領域内だが、Y軸方向に着目した場合にはROIの領域内ではない」という場合(ROIがくねくねしていると起こりえる)を除くため、どちらの場合であってもROIの領域内と認められる点のみ、指定した色で塗りつぶすようにします。
それが以下のColor Mask.viになります。
ブロックダイアグラムは以下のようです。
Pixel Valueという制御器が、塗りつぶしのための色を指定しています。
任意の色で背景を変えたい場合
後の処理内容によっては、消したい場所を特定の色で塗りつぶす必要があるかもしれません。
その場合には、特定の色をカラーボックスで指定できるようにすれば対応できます。
また、制御器でなくても、何か別のアルゴリズムで特定の色を自動で判定させる際にも、以下の図の赤枠で囲った部分を編集するだけで対応できます。
グレースケール画像の場合
グレースケール画像に対して同様な処理を行う場合には、グレースケール画像用の関数を使用します。
カラー画像で使用していたサブVIは使いまわしができますが、扱うデータタイプが異なるため一部の入力に対しては強制ドットが付くことになります。
本記事では、LabVIEWで簡易的に消しゴムマジックを実装する方法を紹介しました。
フリーハンドで書いた領域に対して処理を実行する方法、もっといいやり方があるよというアイデアがある方はコメントいただけるとうれしいです。
ここまで読んでいただきありがとうございました。
コメント