本稿では LIDAR システムによるタイム オブ フライト (TOF) 測定のユーザー解析を ZOS-API によって作ります。
この解析では、 ZRD ファイルを読み込み、データを抽出し、ディテクタにヒットした光線のタイムオブフライト (光線飛行時間) をプロットします。
著者 Sandrine Auriol
Downloads
ユーザー解析とは
ZOS-API (Application Programming Interface) により OpticStudio との通信やカスタマイズが可能になります。OpticStudio とアプリケーション プログラムとの通信には4つのモードがありますが、以下の2つのカテゴリーに分けられます。
1) フル コントロール (スタンドアロン又はユーザー拡張機能モードがこれにあたります。) このカテゴリーではユーザーは、レンズ設計とユーザー インターフェイスに対する一般的なフル コントロールの権限を持っています。
2) 制限アクセス (ユーザー オペランド又はユーザー解析モードがこれにあたります。) このカテゴリーではユーザーは、既存のレンズ ファイルのコピーを使用して作業することしかできない様に機能がロックされています。
ユーザー解析モードはカスタム解析でのデータを取り込むために使用されます。表示されるデータは、ほとんどの分析に OpticStudio で提供される最新のグラフィックを使用しています。このモードでは、現在のレンズ システムまたはユーザー インターフェイスを変更することはできません (つまり、このモードではシステムのコピーへの変更のみが許可されます) 。ユーザー解析は、 C++ (COM) または C# (.NET) を使用して作成できます。この記事のユーザー解析は C# で書かれています。
ユーザー解析機能についてのより詳細な情報については、 OpticStudio のヘルプ ファイル中の プログラミング タブ → ZOS-API について → ユーザー解析 の項を確認してください。
新しいボイラープレート テンプレートを開く方法
それでは、 C# で新しいユーザー解析を作ってみましょう。
下記の通り、プログラミング タブ → ZOS-API .NET アプリケーション ビルダー グループ → C# アイコン → ユーザー解析 を選択してクリックします。
すると、ウィンドウズ エクスプローラでソリューション フォルダ (デフォルトでは 「..\Documents\Zemax\ZOS-API Projects\CSharpUserAnalysisApplication1 」 です。) が開きます。同様に Visual Studio で新しいソリューションが開きます。ソリューションには、ユーザー解析の基盤として使用できるテンプレートであるボイラープレート コードが含まれています。Visual Studio では、ユーザー解析が実行可能ファイルとしてコンパイルされます。この実行可能ファイルは 「\Zemax\ZOS-API\User Analysis 」 フォルダにコピーされて、 OpticStudio で使用可能となります。
LIDAR ファイルを開く方法
「Flash_NSC_Final.zar」 というファイルを、本稿の添付ファイルのリンクからダウンロードしてください。このファイルには Flash LIDAR を表すシステムが含まれています。LIDAR はバンの上部にあります。バンは道路にあり、2人の歩行者とグリーン カーテンが前方にあります。
LIDAR は、この風景にに向けてレーザー パルスを発射します。
光は周囲のオブジェクトによって散乱されます。その散乱された光の一部は、 LIDAR のディテクタに戻ってきます。
例えば以下の様に、赤い歩行者によって散乱した光の一部は LIDAR のディテクタに到達します。
LIDAR は、信号が戻ってくるまでの時間を記録します。それがタイムオブフライト (飛行時間)です。タイムオブフライト は距離に変換されます。ピクセルは入射光の方向を示します。
両方の値から、散乱光はバンから 10 m のところに立つ赤い歩行者から来ることを示しています。 OpticStudio は実際に時間を測定するのではなく光線の経路長を測定するため、オブジェクトとディテクタの間の距離を測定しています。
ディテクタ ビューアでは、ディテクタの放射測定の結果を表示できますが、 LIDAR 光源から LIDAR のディテクタに戻る光線の経路長は表示できません。そんなときに ZOS-API が役立ちます!ユーザー解析を構築して、オブジェクトまでの距離データを表示し、タイムオブフライト の情報を反映させることができます。
光線データベース ビューアを使って ZRD ファイルを開く方法
光線の光路長の長さは、光線データベース ファイルである ZRD ファイルで読み取ることができます。
光線追跡を実行し、 ZRD ファイルに光線を保存してみましょう。
以下の様に解析タブ → 光線追跡解析グループ → 光線データベース ビューアでは、ディテクタ 17 にヒットした光線の光路長を表示させることができます。「フィルタを適用」 の項で 「H17」 と入力することによって、ディテクタ 17 にヒットした光線のみ選別するフィルタを設定することができます。
たとえば、光線 1 のセグメント 8 はディテクタ 17 にヒットしますが、その光線の光路長はすべてのセグメントの光路長の合計であり、 4 × 10^4 mm 、つまり 40 m です。光線は物体に到達し、ディテクタに戻りました。オブジェクトまでの距離は光路長の半分なので、 20 m です。
したがって、ディテクタに到達する各光線の光路長を読み取ることで、ディテクタまでのオブジェクトの距離を見つけることができます。この操作は、ZOS-API を使用して自動的に実行できます。
ZOS-API を使って ZRD ファイルを開く方法
ZOS-API を使用して新しいプロジェクトを開始するとき、以下のプログラミング タブ → ZOS-API .NET アプリケーション グループ → ZOS-API ヘルプ アイコン → ZOS-API シンタックス ヘルプ の中の例を確認することを習慣にするとよいでしょう。
ここでは、どのように ZRD ファイルを読み込むかということを示すため、「ZRD ファイルの解析」という Example 05 ファイルを参照することができます。
このユーザー解析コードは以下のコマンドが含まれています。
- OpenRayDatabaseReader: 光線データベース ビューアを開きます。ZRD ファイルを読み込み、結果を得ます。
IZRDReader ZRDReader = TheSystem.Tools.OpenRayDatabaseReader();
ZRDReader.ZRDFile = ‘<path>\Flash_LIDAR_NSC.ZRD’;
ZRDReader.RunAndWaitForCompletion();
var ZRDResult = ZRDReader.GetResults();
- ReadNextResult: それぞれの光線を読み込みます。
success_NextResult = ZRDResult.ReadNextResult(out rayNumber, out waveIndex, out wlUM, out numSegments);
- ReadNextSegmentFull: それぞれの光線のそれぞれのセグメントを読み込みます。
success_NextSegmentFull = ZRDResult.ReadNextSegmentFull(out segmentLevel, out segmentParent, out hitObj, out hitFace, out insideOf,
out RayStatus, out x, out y, out z, out l, out m, out n, out exr, out exi, out eyr, out eyi, out ezr, out ezi, out intensity, out pathLength, out xybin, out lmbin, out xNorm, out yNorm, out zNorm, out index, out startingPhase, out phaseOf, out phaseAt);
それぞれの光線でセグメント毎に以下のデータが読み込まれます。
-
-
out pathLength: それぞれのセグメントの光路長です。この値を合算すれば、光線の光路長を求めることができます。
-
out x, out y, out z: 最後のセグメントの X、Y、Z 位置です。これにより光線がどのピクセルにヒットしたかが分かります。
- out intensity: 最後のセグメントでの光線強度です。
-
データを配列に格納する方法
結果は2次元の配列 (ディテクタの X と Y ピクセル) に格納されます。
Array (pixel x, pixel y) = data
配列内のデータは光線の光路長や強度等を取ることができます。
光線をピクセルに割り当てるために、ディテクタの光線の最後のセグメント座標 (x_LastSegment,y_LastSegment ) を GetMatrix を使用してグローバル座標からディテクタのローカル座標に変換します。
TheSystem.NCE.GetMatrix(detector, out double R11, out double R12, out double R13, out double R21, out double R22, out double R23, out double R31, out double R32, out double R33, out double Xo, out double Yo, out double Zo);
こうして、光線の最後のセグメントをディテクタのピクセル (i,j) に割り当てることができます。
4つの結果配列があります。
- array_OPL [i,j] はピクセル (i,j) にヒットした光線の光路長の平均値を2で割った値です。この値はオブジェクトとディテクタの間の距離です。
- array_TOF [i,j] はタイムオブフライト データです。光路長を時間に変換した値です。空気中の光速は 299792 km/s なので、タイムオブフライトの値は array_OPL 中の光路長の2倍を光速で割ったものになります。
この場合の光路長は、読み取られた光路長の近似値であり、実際の光路長の長さではなく屈折率を省略した物理的な光路長の長さです。ただし、オブジェクトまでの距離の値は光学部品を通る間の光路長よりもはるかに大きいため、この仮定は有効とみなせます。
- array_nb_hit [i,j] はピクセル (i,j) にヒットした光線の本数です。
- array_flux [i,j] はピクセル (i,j) にヒットした光線の光束の合計値です。
ディテクタ ピクセルの光束 array_flux [i,j] の値が MinFlux で定義された制限より小さい場合、ノイズと見なされるためディテクタの光束の値はゼロに設定されます。
//Define (declare and initialize arrays)
double[,] array_OPL = new double[ypixels, xpixels];
double[,] array_TOF = new double[ypixels, xpixels];
double[,] array_nb_hit = new double[ypixels, xpixels];
double[,] array_flux = new double[ypixels, xpixels];
ディテクタの -X ピクセルにヒットする光は、+X の視野から来ます。ユーザー解析で画像が反転しないように、結果配列には +X から -X および +Y から -Y のデータが含まれます。
結果をプロットする方法
ユーザー解析で配列のプロットを作ることができます。
現在、計算および表示できるデータには以下の4種類があります。2D ライン プロット、2D グリッド プロット、2D RGB グリッド プロット、およびテキスト データです。
「タイムオブフライト」 解析は、 MakeGridPlot
を使用して 2D グリッド プロットを作成します。結果は配列に保存されます。X 軸とY 軸はディテクタのピクセルであり、 Z 軸はオブジェクトまでの距離、飛行時間、ヒット数、または光束のいずれかです。 IUserGridData
インターフェイスの SetDataSafe 関数は、配列を入力として受け取ります。
IUserGridData gridPlot = TheAnalysisData.MakeGridPlot("Time of Flight");
gridPlot.XLabel = "Pixel X coordinate value";
gridPlot.YLabel = "Pixel Y coordinate value";
gridPlot.SetDataSafe(array_OPL);
ユーザー解析毎に許可されるデータの形式は1つのみであることに注意してください。
このユーザー解析では、保存された ZRD ファイルと特定のディテクタの結果が表示されます。結果はオブジェクトからディテクタまでの距離、タイムオブフライト、ディテクタのピクセルにヒットする光線の数、またはディテクタのピクセル上の光束の4つの配列のいずれかになります。
これらのオプションはすべて、前述のフォーム コントロールや表示オプションを含む設定ダイアログの一部になります。
設定を作る方法
ユーザー解析には、ユーザー解析をより汎用的にする設定ダイアログを含めることができます。設定は、キーと値のペアで構成されるディクショナリに保存されます。これは、特定のタイプが関連付けられているユーザー定義の文字列キーを介して各設定が参照されることを意味します。解析が最初に起動されたとき、ディクショナリは空です。設定ディクショナリに追加されたエントリは、更新と更新の間に保存され、セッションとともに保存できます。次のタイプを設定に保存できます:整数、浮動小数点 (32ビット)、倍精度浮動小数点 (64ビット)、ブール、文字列、バイトです。
ディクショナリの宣言は Program.cs ファイルで行われます。次に、設定と解析の間で変数が渡されます。 タイムオブフライト ユーザー解析のキーのディクショナリは次のとおりです。
//declare public variables called keys to pass between settings and analysis
public const string S_filter = "filter";
public const string S_ShowAs = "ShowAs";
public const string S_ZRDFile = "ZRDFile";
public const string S_FirstTime = "FirstTime";
public const string S_ShowData = "ShowData";
public const string S_MinFlux = "MinFlux";
これらのキーは S_FirstTime キー以外は設定です。S_FirstTime キーは、このユーザー解析が初めて起動されたかどうかを記録するために使用されます。false の場合、設定が設定されていません。最初に設定を選択するようユーザーに求めるメッセージが表示されます。
// Basic checks
if (!FirstTime)
{
IUserTextData userText = TheAnalysisData.MakeText();
userText.Data = "Run the settings first";
return;
}
設定は、 AnalysisSettingsForm
と呼ばれる別のクラスで定義されます。AnalysisSettingsForm クラスは、ユーザー解析テンプレートの一部です。そのクラスは、設定ウィンドウのデザインと同様にデフォルト値とを定義します。
ユーザー解析テンプレートは、空の設定ウィンドウを作成します。ツール ボックスを使用すると、 Windows フォームを手動で追加して設定を定義できます。たとえば、 ZRD ファイルの選択は、 ZRD ファイルのドロップダウン リストを表示するコンボボックスを使用して行われます。 ディテクタの番号は テキストボックスです。
ユーザー解析テンプレートには、 Program.cs ファイルに ShowUserAnalysisSettings という関数が含まれています。その関数は設定を変更するためのフォームを表示し、設定を取得します。
このコードでは、 AnalysisSettingsForm クラスのインスタンスである SettingsForm というオブジェクトが定義されているため、フォームが表示されます。ユーザーが設定を定義して 「OK 」 をクリックすると、キーに値が割り当てられます。
TheSettings.SetStringValue(S_filter, SettingsForm.filter);
TheSettings.SetStringValue(S_ZRDFile, SettingsForm.ZRDFile);
TheSettings.SetStringValue(S_ShowAs, SettingsForm.ShowAs);
TheSettings.SetStringValue(S_ShowData, SettingsForm.ShowData);
TheSettings.SetStringValue(S_MinFlux, SettingsForm.MinFlux);
TheSettings.SetBooleanValue(S_FirstTime, true);
たとえば、コードの SettingsForm.ShowData である 「Show As (表示方法)」 設定が読み取られます。次に、値が S_ShowData キーに設定されます。
ユーザー解析を実行するとき、 Program.cs ファイルの RunUserAnalysis 関数もともに実行され、 S_ShowData キーが読み取られ、 ShowData という変数に値が割り当てられます。
// Read the public variables / keys
// Define new variables (out) and assign a value to those variables
TheSettings.GetBooleanValue(S_FirstTime, out bool FirstTime);
TheSettings.GetStringValue(S_filter, out string filter);
TheSettings.GetStringValue(S_ShowAs, out string ShowAs);
TheSettings.GetStringValue(S_ZRDFile, out string ZRDFile);
TheSettings.GetStringValue(S_ShowData, out string ShowData);
TheSettings.GetStringValue(S_MinFlux, out string MinFlux);
設定と ShowData の値に応じて、異なる出力が表示されることになります。
switch (ShowData)
{
case "Distance to Object":
gridPlot.ValueLabel = "Distance to Object: Half Path length in m";
gridPlot.SetDataSafe(array_OPL);
break;
case "Number of Hits":
gridPlot.ValueLabel = "Number of Hits";
gridPlot.SetDataSafe(array_nb_hit);
break;
case "Time Of Flight":
gridPlot.ValueLabel = "Time of Flight in us";
gridPlot.SetDataSafe(array_TOF);
break;
default:
gridPlot.ValueLabel = "Flux in W";
gridPlot.SetDataSafe(array_flux);
break;
}
保存、ビルドして実行可能形式にする方法
ソリューションはリリース モードでビルドできます。デバッグ時には、デバッグモードを使用するのが良いでしょう。ただし、ユーザー解析をプラグインとして配布するには、デバッグ ライブラリは再配布できないため、リリース モードに設定します。
実行可能ファイルはその後、ソリューション フォルダ ( 「…Documents\Zemax\ZOS-API Projects\...」内) から「... Documents\Zemax OpticStudio\ZOS-API\User Analysis」 にコピーすることができます。
ユーザー解析を実行する方法
タイムオブフライト ユーザー解析を確認するには、 OpticStudio を起動し、レンズ ファイル 「Flash_LIDAR_NSC.zar」 を開きます。プログラミング タブ → ZOS-API .NET アプリケーション グループ → ユーザー解析アイコンの下に、新しく作成された解析があるはずです。
最初に設定を定義します。
[OK] をクリックすれば、周囲のオブジェクトの距離を示すプロットを生成します。
より高度な解析のヒント : 時間依存解析
今回の例では、ディテクタは光の経路長を読み取っていますが、時間あたりという概念はありません。これは、 ZOS-API を使用して実行できることです。
LIDAR 光源はパルス レーザーです。解析については以下のことが可能です。
- パルス レーザーとして光を送る
- 与えられた時間間隔の頻度で ZRD ファイルを記録する
- 結果の表示/処理
KA-01800
コメント
記事コメントは受け付けていません。