Spinnaker SDKでFLIRのカメラをPythonから動かす
FLIRのSpinnaker SDKではC/C++,Pythonといった主要なプログラミング言語をサポートしています.ここではPythonを使ってFLIRのカメラを動かすための具体的な方法を説明します.
Spinnaker SDKのインストール方法はこちらを参考にしてください.
PySpinのインストール
Spinnaker SDKをPythonから使うためには,PySpinをインストールする必要があります.
numpyとmatplotlibをインストールしてない場合は,pipでインストールします.Pillowは無くても動きますが,あった方が良いみたいです.
MacOS
- /Applications/Spinnaker/PySpin内にあるspinnaker_python-2.0.0.109-cp37-cp37m-macosx_10_9_x86_64.tar.gzを解凍します.2.0.0.109はSpinnaker SDKのバージョン,cp37はPythonのバージョンです.
- 解凍したフォルダ内にあるPySpinのwheelをインストールします.
pip install spinnaker_python-2.0.0.109-cp37-cp37m-macosx_10_9_x86_64.whl
PySpinの使用例
FLIRが配布しているコードの中には,PySpinのexamplesがありますが,なぜか非常に複雑です.ここではPySpinを使うためのコードを要点を絞って紹介します.
撮影・保存
import PySpin #カメラの指定・初期化 system = PySpin.System.GetInstance() cam_list = system.GetCameras() cam = cam_list.GetByIndex(0) cam.Init() #撮影開始 cam.BeginAcquisition() #カメラから画像を転送&保存 image_result = cam.GetNextImage() image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) image_converted.Save("image.png") image_result.Release() #撮影終了 cam.EndAcquisition() #終了処理 del cam cam_list.Clear() system.ReleaseInstance()
注意したいのは終了処理(特にdel cam
やcam_list.Clear()
)の部分で,これが実行されない場合エラーになります.
numpy配列への変換
image_NDArray = image_result.GetNDArray()
PySpinでは撮影した画像をnumpy配列に変換することができます.そのため,opencvやnumpyとの連携が容易です.
撮影の設定
カメラのパラメータを設定をするにはQuickSpinAPIかGenAPI(GenICamAPI)を使います.QuickSpinAPIは,ほとんどのパラメータがサポートされていて,GenAPIより短いコードで実行できます.そのため,基本的にはQuickSpinAPIを使えば良いです. ここではQuickSpinAPIを使った各種パラメータの設定方法を紹介します.
露光時間
#Auto exposureをon (continuousモード) cam.ExposureAuto.SetValue(PySpin.ExposureAuto_Continuous) #Auto exposureをoff cam.ExposureAuto.SetValue(PySpin.ExposureAuto_Off) #Exposure modeをTimedに設定 cam.ExposureMode.SetValue(PySpin.ExposureMode_Timed) #Exposure timeを20000usに設定 cam.ExposureTime.SetValue(20000) #設定されているexposure timeを取得 value = cam.ExposureTime.GetValue()
ゲイン
#Auto gainをon (continuousモード) cam.GainAuto.SetValue(PySpin.GainAuto_Continuous) #Auto gainをoff cam.GainAuto.SetValue(PySpin.GainAuto_Off) #Gainを10.5dBに設定 cam.Gain.SetValue(10.5) #設定されているGainを取得 value = cam.Gain.GetValue()
ガンマ
#Gammaを1.5に設定 cam.Gamma.SetValue(1.5) #設定されているGammaを取得 value = cam.Gamma.GetValue()
黒レベル
#BlackLevelSelectorをAllに設定 cam.BlackLevelSelector.SetValue(PySpin.BlackLevelSelector_All) #BlackLevelを1.5%に設定 cam.BlackLevel.SetValue(1.5) #設定されているBlackLevelを取得 value = cam.BlackLevel.GetValue()
転送する画像の順番
#GenAPI #転送する画像を最新のもの(NewestOnly)に設定 s_node_map = self.cam.GetTLStreamNodeMap() handling_mode = PySpin.CEnumerationPtr(s_node_map.GetNode('StreamBufferHandlingMode')) handling_mode_entry = handling_mode.GetEntryByName('NewestOnly') handling_mode.SetIntValue(handling_mode_entry.GetValue())
webカメラのように撮影した画像をリアルタイムで確認したい場合は,StreamBufferHandlingModeをNewestOnlyに設定して,最新の画像のみを転送してくるようにします.OldestFirstに設定すると,カメラ内のバッファに保存されている古い画像から順に転送されます.
OpenCVのVideoCaptureクラスっぽく使う
PySpinはカメラの詳細な設定をできますが,それ故に複雑で独特なコーディングになりがちです.一方で,OpenCVのVideoCaptureクラスは簡素なコードでwebカメラを動かすことができます.そこで,OpenCVのVideoCaptureクラスっぽいコードで,FLIRのカメラを動かすためのラッパーを作ってみました.複雑なコードでお困りの方は使ってみてください. github.com
FLIRのSpinnaker SDKのインストール方法のメモ
FLIRのマシンビジョンカメラ(BlackFly, Oryx等)はSpinnaker SDKを使って動かすことができます.ここでは,Spinnaker SDKをインストールして,FLIRのカメラを動かすための方法をメモしておきます.
Spinnakerのインストール
下のリンクからSpinnakerSDKをダウンロードします.すべてのバージョンをダウンロードしようとすると時間がかかるので,自分の環境に適したものを選択してダウンロードします. www.flir.com
MacOS
- Homebrewでpkg-config,libomp,libusbをインストールします.
brew install pkg-config libomp libusb
- MacOS/Spinnaker-2.0.0.109.dmgを開き,Spinnaker-2.0.0.109.pkgから手順にしたがってインストールを進めます.
- /Applications/Spinnaker/apps/SpinView_QT.appを実行すると,カメラからの映像を確認することができます.
Windows
- SpinnakerSDK_WEB_1.29.0.5_x64.exeもしくはSpinnakerSDK_FULL_1.29.0.5_x64.exeを実行して,手順にしたがってインストールを進めます.
Camera EvaluationかApplication Developmentを選択します.どちらを選んでもSpinView(GUIのビューワー)はインストールされ,後者のApplication DevelopmentはSDKが付属します. - SpinViewを実行すると,カメラからの映像を確認することができます.
SpinViweの比較
SpinViewはFLIRのカメラの設定・撮影・保存といった動作をGUIで実行できます. MacOS版とWindows版のSpinViewのスクリーンショットを比較すると,Windows版だけが持つ機能を確認できます.Windows版だけの機能は,「ヒストグラムの表示」「スライダーなどのUIによるパラメータの設定」「ログビュアー」などがあります.
偏光カメラで出来ること
概要
偏光を見ることで,通常のカメラでは得られない情報を獲得することができます.最近では偏光カメラが比較的安価に手に入るようになり,偏光イメージングの機運が高まっています.ここでは,偏光カメラで撮影した画像を使って,偏光イメージングの応用例を紹介します.
偏光の基礎
*ここでは直線偏光のみを考えています.
偏光の状態
偏光と偏光板
偏光板を回転させたときに観測される輝度は次式のようなコサイン関数で表せられます.
ここでは偏光板の偏光角,とは輝度の最大値と最小値,は位相角です.
偏光の度合いを表す偏光度は次式で表せられます.完全偏光の場合は,ランダム偏光の場合はになります.
ストークスベクトル
偏光の状態はストークスベクトルを用いて表すことができます.
:光の輝度の合計.
:方向の直線偏光成分.
:方向の直線偏光成分.
コサイン関数のパラメータ,,とストークスベクトルのパラメータ,,の関係は次式で表せられます.
,,
偏光の計測
偏光の状態を取得するためには,カメラの前に配置した偏光板を回転させながら複数枚撮影した画像(輝度値)からパラメータを推定します.非線形最小二乗法を用いてコサイン関数にフィッティングさせることにより求めることができますが計算コストが高いです.一方でストークスベクトルは線形最小二乗法を用いてパラメータの推定ができるので高速に演算することができます.
偏光板の回転角度を*1と変化させながら観測した輝度値がとなるとき,ストークスベクトルとの関係を行列の形で表すと次式のようになります.
この式を最小二乗法で解くことでストークスベクトルのパラメータが求まります.
偏光カメラ
偏光カメラはイメージセンサーの前にの偏光子が規則的に配置されており,ワンショットで4方向の偏光情報を撮影できます.Sonyは2018年から偏光イメージセンサーの量産を始めました.そのため,最近では偏光カメラが安価に手に入るようになってきています.
偏光の応用
偏光カメラ(FLIRのBFS-U3-51S5P-C,SonyのIMX250MZRセンサーを搭載)を用いて撮影を行いました.
偏光度
黒いカメラを撮影しました.通常の撮影では暗くてわかりにくいですが,偏光度に注目するとカメラの領域だけがはっきりと見えます.影で暗くなっている部分とも見分けがついていることもわかります.
偏光方向(面法線)
アボカドを撮影しました.位相角(~)の値をHSVで擬似カラー化して表しています.ランダム偏光の光が物体表面で反射すると,フレネル反射に従って反射光は偏光します.偏光した光の位相角や偏光度は光の入射角(=反射角)と関係があります.そのため,位相角や偏光度から反射面の法線方向を推定することができます(ただし曖昧性の問題があります).
応力・ひずみ
透明のプラスチックのスプーンを液晶ディスプレイ(面発光する偏光光源)の上に置いて,真上から撮影しています.通常では透明なスプーンですが,わずかな歪みが偏光に影響を与えています.
反射除去
池にいる鯉を撮影しました.水面の反射によって外の風景が映り込んでおり,鯉がはっきり見えない場所があります.成分を取り出すと,水面の反射成分を除去できています.
拡散反射と鏡面反射成分の分離
シーンに対して完全直線偏光の光で照らしています.拡散反射成分はランダム偏光になるのに対して,鏡面反射成分は偏光が保たれます.そのため,は拡散反射成分,は鏡面反射成分に対応しています.
プログラム
偏光カメラ(FLIR, BFS-U3-51S5P-C)で撮影した画像のデモザイキングやストークスベクトルの推定などを行うプログラムをGitHubに置いておきます.この記事に掲載している画像も一緒に置いています.
参考資料
*1:パラメータの数は3つなので最低3回の撮影が必要です(n>=3).また,偏光板の回転角度が同じだと不良設定問題になる場合があります.
ダイポールモデルによる半透明物体の散乱特性の計測
概要
半透明物体では,光が物体内部に入り込んで反射する表面下散乱という現象が発生します.この現象をダイポールモデルで近似することによって,半透明物体の散乱特性を計測することができます.
今回はろうの散乱特性を計測しました.さらに,計測した結果を用いてろうの質感をCGで再現しました.
半透明物体
私たちの身の周りには半透明物体で溢れています.大理石・皮膚・ろうそく・果物・肉・牛乳など,程度の差はありますが,これら全ては半透明物体としての性質を持っています.
半透明物体では光が物体内部に入って,別の点から出てくる現象が発生します.このような現象を表面下散乱(Subsurface scattering)と呼びます.表面下散乱では,ある物体表面上の点に入った光が物体内で1回ないし複数回反射して別の点から出てきます.
表面下散乱が発生する物体の表面上での光の関係を表現した関数をBSSRDF (Bidirectional Scattering Surface Reflectance Distribution Function, 双方向散乱面反射率分布関数)と呼びます.BSSRDFは入射光と出射光の位置,と方向,の8次元の関数です.
BSSRDFが既知であれば,その物体をCGで表現できるようになります.しかし,実際に計測しようとすると非常に時間がかかります.また,計測できたとしても莫大なデータ量になります*1.
ダイポールモデル
BSSRDFを表すパラメトリックモデルとして,ダイポールモデル(Dipole model)*2があります.このモデルは,多重散乱*3 *4で,無限平面で,十分に厚みのある*5,均一散乱物体のBSSRDFを良く近似します.
ダイポールモデルではBSSRDFを次式のように構成しています.
は相対屈折率,はフレネル透過率です.とすると,散乱項は次式で表せられます.
このとき各変数は次式のようになります.
,,,,,,,,,
この中で,散乱係数(Scattering cofficient),吸収係数(Absorption coefficient),相対屈折率,散乱方向の平均コサイン(Mean cosine of the scattering angle)*6の4つがパラメータになります.
例として,皮膚(Skin1[Jensen et al, 2001])のパラメータを元にとの関係をプロットしました.光が入射された位置から離れるほどは指数関数的に減衰します.
実験
実際に計測を行いダイポールモデルのパラメータを推定します.対象の半透明物体は,ろう(一辺の長さは6.9cm)です.光源として赤色レーザを使いました.カメラはCanon EOS 6DでレンズはSMC TAKUMAR 90mm F2.8です.レーザ光が対象物体に対して垂直に入射するように設置しました.表面下散乱は距離に応じて指数関数的に減衰するので輝度差が大きくなります.そこでHDR撮影を行いました.
まず,半透明物体を撮影した画像から,レーザ光の入射位置を原点としたときの距離に対応する画素値を抜き出しました.レーザ光の放射束と未知の定数を用いるとは次式で表せられます.
次に,とを求めるために拡散反射板を撮影します.理想的には標準拡散反射板(反射率>0.99)を使いたいのですが,持ってなかった*7のでコピー用紙で代替しました.拡散反射板を撮影した画像の画素値の合計を求めるとになります.は1画素あたりで撮影された拡散反射板の領域の面積です.コピー用紙に既知の長さの線を印刷しておいたので,それを元にを求めました.が求まったのでを求めることができます.
最後にを計算するとが求まります.はろうの大きさを定規で測定して,画像中の位置との関係から求めました.
結果
レーザ光の入射位置を原点としたときの距離を横軸に,計測した散乱項を縦軸にしてプロットしました.原点から離れるとは小さくなっていることが確認できます.原点に近い点<1では,が極端に大きくなっています.この点では物体表面での直接反射成分が含まれているためだと考えられます.
ダイポールモデルに基づいてパラメータの推定を行います.ここでは等方散乱を仮定するのでとします.相対屈折率は多くの物体でとなることが知られているのでこの値を用います.非線形最適化でパラメータを推定すると,/mm,/mmとなりました.
推定したパラメータを用いてレンダリングを行いました.レンダラはMitsubaを使いました.
表面下散乱の生じない拡散反射と比べると,ダイポールモデルでは陰影が少なくなり,半透明物体の質感が表現できていると思います.
立方体以外の複雑なシーンにも適用してみました.
参考資料
*1:100x100の画素数で1度単位の計測を行うと,入射光位置は100x100通り,出射光位置は100x100通り,入射光方向は360x90通り,出射光方向は360x90通り,となる.全ての組み合わせは通り.8bitで記録しても100PB(ペタバイト)必要になる.
*2:H. W. Jensen, S. R. Marschner, M. Levoy, and P. Hanrahan, “A Practical Model for Subsurface Light Transport”, Proc. SIGGRAPH2001, 2001.
*3:物質内で何度(2回以上)も反射する散乱を多重散乱.1回だけの反射は単一散乱と呼ぶ.
*4:単一散乱も近似できるモデルとして,Directional dipole modelが提案されている.J. R. Frisvad, T. Hachisuka, and T. K. Kjeldsen, “Directional dipole model for subsurface scattering,” ACM Trans. Graph., 2014.
*5:特定の厚みを持つ物体を近似できるモデルとして,Multipole modelが提案されている.C. Donner H. W. Jensen, “Light Diffusion in Multi-Layered Translucent Materials”, Proc. SIGGRAPH2005, 2005.
*6:散乱の方向を表すフェーズ関数のパラメータ.-1.0~1.0の範囲の値をとる.g=0のとき等方散乱,g>0のとき前方散乱,g<0のとき後方散乱になる.
*7:10万円くらいするみたいですね.Labsphere Spectralon, Diffuse Reflectance.
レンジファインダによる3次元計測
概要
カメラとプロジェクタのペアを使って,物体の3次元計測を行いました.プロジェクタから投影するパターンはグレイコードを使いました.
レンジファインダ
3次元計測を行う手法としては2台のカメラを用いたステレオ法が有名です.2台のカメラの視差を利用することで,三角測量の原理に基づき距離を算出することができます.この手法では,テクスチャのない部分では対応点付けが困難なため,距離計測が不安定になります.
レンジファインダは,カメラとプロジェクタのペアで距離を計測できます.プロジェクタから光のパターンを投影して,カメラで撮影します.すると,テクスチャのない物体でも,対応点付け問題が簡単になります.
3次元計測の手順
カメラとプロジェクタの対応関係の獲得
3次元計測を行うためには,プロジェクタから出力された光によって光っている物体上の点が,カメラの画像上のどの座標で撮影されるかという対応関係を求める必要があります.
もっとも簡単な方法は,プロジェクタからある1点だけを光らせ,カメラで撮影することです.これを全ての点に対して行うことで,プロジェクタとカメラの対応関係が求まります(スポット光投影法).しかし,この方法では非常に時間がかかります.
計測時間を短縮するための手法として,グレイコードパターンを投影する方法があります.この手法では白黒のパターンを複数枚投影して撮影し,デコードを行うことで,カメラとプロジェクタの対応関係を求めることができます.例えば,横幅が1024ピクセルのプロジェクタであれば,最低10枚(反転パターンを含めると計20枚)のパターンを投影して撮影することで対応関係(カメラの2次元座標とプロジェクタの1次元座標との対応)を求めることができます.
カメラとプロジェクタのキャリブレーション
カメラのキャリブレーションをすると,次式で表せられるカメラパラメータを獲得できます.は世界座標系でのある点で,はその点に対応するカメラ座標系での画像の二次元座標です.
プロジェクタのキャリブレーションをすると,次式で表されるプロジェクタパラメータを獲得できます.は世界座標系でのある点で,はその点に対応するプロジェクタ座標系での軸方向の座標です.
距離の計算
カメラパラメータとプロジェクタパラメータを用いて,行列,,を定義します.
カメラ座標とプロジェクタ座標に対応する物体座標は次式で計算できます.
この計算を画像上の全ての座標で行うことで,物体の3次元座標を求めることができます.
実験結果
グレイコードパターンを投影することで,プロジェクタとカメラの対応点を求め,物体の3次元計測を行いました.グレイコードは,ポジのパターンを11枚とネガのパターンを11枚投影しました.
対象物体は,紙コップとキャリブレーションボックスです.
3次元計測を行なった結果です.
基準立方体を用いたカメラキャリブレーション
概要
立方体を用いてカメラのキャリブレーションを行い,カメラパラメータを求めました.立方体を用いることでワンショットでキャリブレーションができます.
カメラキャリブレーション
幾何学的カメラキャリブレーションの手法としてはZhangのチェスボードを用いる方法が有名です.この手法ではチェスボードを動かしながら複数枚撮影することで,キャリブレーションをすることができます.チェスボードは手軽に用意することができます.また,OpenCVやMATLABでは専用のプログラムが実装されています.
チェスボードを用いない手法としては,形が既知の物体を用いる方法があります.
今回は上の図のような基準立方体を使います.立方体の大きさは8×8×8cmです.チェスボードと比較して,基準立方体を使うメリットは2つあります.
1. ワンショットでキャリブレーションを行うことができる
基準立方体をカメラで撮影すると,3面を同時に撮影することができます.そのため,チェスボードのように動かしながら複数枚撮影する必要がありません.
2. プロジェクタのキャリブレーションにも適用しやすい
プロジェクタのキャリブレーションを行う場合は,パターンを投影してカメラで撮影します.このとき黒い領域では,投影したパターンが暗くなるので観測しにくくなります.この基準立方体では,各面には辺に沿って黒いマーカをつけています.このマーカを対辺どうしで直線で結んだ時の縦線,横線が交わる点を基準点として獲得できます.このとき基準点は全て白い領域なので,投影したパターンを観測しやすいという利点があります.
立方体の世界座標
まず,基準立方体の座標系について設定します.立方体のある頂点を原点として定め,世界座標系でとしました.辺に沿って,x軸,y軸,z軸を設定しました.立方体の大きさは既知なので,各面上の点の座標がわかります.
立方体のカメラ座標の獲得
基準立方体の世界座標と対応するカメラ座標を求めます.
基準立方体を撮影した画像を用意します.背景は模様が無いようにすると,後の処理が楽になります.
撮影した画像を2値化して,黒いマーカがブロブとして検出できるようにします.
ラベリングを行い,黒いマーカの位置を求めます.
対辺どうしのマーカを直線で結んだとした時の縦線,横線が交わる格子点を基準点とします.この立方体では,一辺に7個のマーカがあるので,基準点は一面に49点.それが三面あるので合計で147点数の基準点が得られます.
カメラパラメータの計算
世界座標系でのある点と,カメラ座標系での画像の二次元座標との関係は次式で表すことができます.
この式を展開して,媒介変数を消去すると,
式より,との対応が既知の点が1点あれば2つの方程式を作ることができます.求めたいカメラパラメータは3×4の行列なので,未知数は12個です.そのため最低6組の点があれば方程式を12個作ることができ,カメラパラメータを求めることができます.
実際には6組以上の点を使い,最小二乗法を適用することでパラメータを求めるます.
プロジェクタキャリブレーション
カメラパラメータを求める式を用いることで,プロジェクタのパラメータを求めることができます.このとき必要になるのは,プロジェクタ座標系のある点の座標と,それに対応する世界座標系の点の座標です.プロジェクタは光を出力する装置なので,カメラのように直接撮影して座標を求めることができません.そのため,プロジェクタから投影したパターンをカメラで撮影することで座標の対応関係を獲得する方法がよく使われます.もっとも簡単な方法は,プロジェクタからある1点だけを光らせ,それをカメラで撮影することです.これを全ての点に対して行うことで,プロジェクタとカメラの対応関係を求まります.しかし,この方法では非常に時間がかかるので,グレイコードパターンを投影する方法などが用いられます.
The Imaging Source社のカメラをPythonから動かす
概要
The Imaging Source社のマシンビジョン用のカメラをPythonから動かせたのでメモしておきます.
実行環境
やり方
1.ドライバのインストール
カメラのドライバをインストールします.
https://www.argocorp.com/software/DL/tis/driver.html
2.コントローラのダウンロード
The Imaging Source社のGitHubからコントローラをダウンロードします.
git clone https://github.com/TheImagingSource/IC-Imaging-Control-Samples.git
cd '.¥IC-Imaging-Control-Samples¥Python¥Open Camera, Grab Image to OpenCV¥'
サンプルプログラムを実行します.
python .¥tis-OpenCV.py
実行すると,カメラからキャプチャされた画像が表示されます.
プログラム
自分なりに改造した撮影用プログラムをGitHubに置いておきます.
このプログラムでは,露光時間・ゲインの設定,複数枚撮影によるノイズ低減,簡易のHDR画像撮影機能を備えた自作関数を実装しています.