6千円でレーザーレンジファインダーを作る
安曇野の森から > 6千円でレーザーレンジファインダーを作る > 制御プログラム
以下はレーザーレンジファインダーのソフトウェアブロック図です。
Webカメラで撮影された赤外画像は二値化やノイズ除去、細線化などの画像処理を行い結果の二値画像を距離計算処理へ渡します。
二値画像から縦1ライン毎の距離を計算し、さらに均等な角度毎のデータになるように補間を行い単位角度毎の距離を計算します。
最後に単位角度毎の距離をsensor_msg/LaserScanメッセージに入れて/scanトピックにpublishします。
以降でこれら処理の詳細を説明します。
以下で画像処理方法を説明します。
実機による赤外画像を以下のようになります。
左図は測定対象物がない状態で測定距離外に壁がある状態を俯瞰したものです。
左図は上記の状態でレーザー光を投射し、レーザーレンジファインダのカメラで赤外画像を取り込んだものです。
床面に当たったレーザー光が一直線で見えています。
シート光はレーザーレンジファインダから450mmで床面に当たるように調整しています。
左図は測定対象物をレーザーレンジファインダから300mmの距離に置いた状態を俯瞰したものです。
左図は上記の状態でレーザー光を投射し、レーザーレンジファインダのカメラで赤外画像を取り込んだものです。
床面と測定対象物に当たったレーザー光が段になって見えています。
処理を高速にするため、最初に画像を二値化し、データ量を減らします。
二値化の閾値を固定値で決めてしまうと、カメラの露出条件が変わったりした時に適切に二値化が出来ない場合があるので、ここでは与えられた画像から閾値を自動で計算してくれる「大津の方式」を使います。
この「大津の方式」はOpenCVに標準でライブラリが用意されています。
左図はカメラから取り込んだ赤外画像です。
左図はカメラから取り込んだ赤外画像を「大津の方式」で二値画像にしたものです。
レーザー反射光の弱い部分ではレーザー反射光特有のスペックルパターン(粗い面で拡散した反射光が互いに干渉することによって見える斑点模様)が二値化により目立つようになります。
左図では右下のラインや中央の太りラインの周辺にスペックルパターンによる斑点模様が見えます。
上記のスペックルパターン以外にも、赤外フィルタを取り付けると画像が暗くなり、カメラの自動露出機能が働いてカメラのゲインを上げてしまうため、画像にホワイトノイズなどが入りやすくなってしまいます。
上図を拡大して見た時、中央の太いラインの周辺に点状に見えるのがホワイトノイズです。
次のノイズ除去処理によってスペックルパターンを潰し、ホワイトノイズを除去します。
ゲインが高い状態でレーザーのような強い光を撮像すると、上図の中央部のラインのようにレーザーの反射光が明るすぎて潰れて太く写ってしまうのも、情報が飽和してしまっているという点で、あまりよくありません。
本来であれば、このような不具合を防ぐため自動露出を止めて、一定の低いゲインで測定したいところですが、OpenCVから制御出来る方法を見つけられなかったため、自動露出ONのまま使っています。(v4l2-utilsを使うとコマンドラインでUVCカメラをコントロール出来ますが、これを使っても自動露出をOFFにすることが出来ませんでした。)
ここでは、モルフォロジー変換(膨張2回と収縮3回)を使って二値画像に点在するホワイトノイズとスペックルパターンによる斑点模様を除去します。
モルフォロジー変換の膨張では白ピクセルがあったらその周りに白ピクセルを1つ追加するという操作を行い、収縮では白ピクセルの塊の縁から白ピクセルを1つ削除するという操作を行います。
ここでは膨張させた後に収縮を1回多く行うことにより、近接した白ピクセルの塊同士を融合させ、孤立している白ピクセルを消します。
左図は二値化画像にモルフォロジー変換をかけた結果の画像です。
二値画像に比べて斑点模様が潰れているのがわかります。
赤外画像で得られるレーザー光は幅が太い線となるので、距離計算する際に、どこの値を使ったらよいかわかりません。
この太い線を細線化することにより距離を計算しやすくします。
一番光の強い位置をとる、または輝度で重みをかけて重心を計算し、その重心位置で細線化するなど輝度をうまく使う方法もありますが、ここでは二値化してしまっているので、その方法が使えません。
そこでモルフォロジー変換後の画像をY方向(縦方向)でスキャンし、ある幅以上に白が続くピクセルのグループがあったら、そのグループの重心位置をグループの代表位置とし、その代表位置のピクセルのみを白とし、他のピクセルは黒とすることにより細線化を行います。
また、この処理の中で、ある幅より狭いグループのピクセルは全て黒とすることによりノイズ成分も除去しています。
左図はモルフォロジー変換画像を細線化した画像です。
床面が反射しやすい素材の場合、床面で反射したレーザー光が測定範囲外にある壁に反射して赤外画像に見えてしまう場合があります。
左図の右側の二重になっているラインがそれです。
この影響を除くため、細分化処理では一番下のラインのみを残すようにしています。
このレーザーレンジファインダを室内照明の下で使う分には外乱光を気にする必要はありませんが、太陽光が室内に入ってきてしまう場合、太陽光には赤外線が多く含まれるため、赤外画像に太陽光が写り込んでしまいます。
左図は背景にある厚手のカーテンを通して太陽光が赤外画像に写り込んだものです。
赤外線リモコンでは赤外光に30〜40KHz程度の変調をかけて、受光側でハイパスフィルタを使って変調された信号のみを取り出すという方法を使って外乱光の影響をなくしていますが、カメラのような二次元センサでは、各ピクセルにハイパスフィルタを付ける訳にはいかず、このような方法が使えません。
撮影間隔が十分に短ければレーザー光ONの画像とレーザー光OFFの画像の2つの画像の引き算を行う(数値微分になるのでハイパスフィルタと同じ効果がある)ことにより、直流成分である外乱光の影響を除くことが出来ます。
以下で外乱光除去の原理を実例を使って説明します。
左図は太陽光が赤外画像に写り込んだ状態でレーザーをOFFにしたものです。
レーザーをOFFにすると自動露出が働いて外乱光部分が明るくなってしまいます。
外乱光部分を正確にキャンセルするために本来は一定露出にしてレーザーのON/OFFどちらでも外乱光部分が同じ明るさになるようにしたいところですが、実際は以下の処理で二値化して減算しますので、OFFで明るくなって領域が広がってしまった部分は減算時に負の値となり、キャンセルしやすくなります。
左図はレーザーON画像を二値化したものです。
左図はレーザーOFF画像を二値化したものです。
左図はレーザーON二値画像からレーザーOFF二値画像を減算したものです。
この演算で外乱光の部分がキャンセルされます。また、ここでは演算結果の負値は0としています。
実際には二値画像での処理だと外乱光部分とレーザー反射光が重なってしまうと分離出来なくなってしまうので、二値化の前に差分を取る方法などを検討する必要があります。
今回は室内での使用を前提としているので、この方法による外乱光除去の処理は入れていませんが今後の課題です。
以下で距離計算方法を説明します。
以下は工事中です。
以下でメッセージ発行方法を説明します。
以下は工事中です。