ChatGPTさんに疑似点群計測ツールがないか聞いたところ,Blensorに加えてこれも紹介されたので実装.
公式Github:https://github.com/3dgeo-heidelberg/helios
スタンドアロン版もあるが「ファイルが見つからない」とエラーメッセージが出るため,Anaconda promptでインストールと実行する方法を採用した.
余談だが,機能を試すだけなら必要ない開発目的のコンパイルをしようとChatGPTさんとドツボにはまって,数時間ひたすらエラーメッセージを貼り付けまくり,そのたびChatGPTさんに「あと少しですから頑張りましょう!!」と励まされていた.英語だからと解読を放棄してAIに丸投げするのはよくない.
Anacondaの環境構築
公式GithubがMinicondaを推奨していたのでそれをダウンロードする.
https://www.anaconda.com/docs/getting-started/miniconda/main にアクセスし,右上の「Download」をクリック.
その後あたかもメールアドレスによる登録が必要そうな画面を出してくるが,無視してページの下側まで行き,「Download Miniconda Installer」をクリックする.
Miniconda InstallersのWindows版インストーラーをダウンロードする.



pipを使ってpythonのパッケージを管理していて,それと競合したくなかったので,インストーラーでの設定は以下のように行った.

インストールが完了したら,スタートメニューに「Anaconda prompt」が追加されているので起動する.PowerShellと普通のプロンプトがあるが,後者の方が扱いやすかった.

Anaconda Promptを用いたheliosのインストール
Anaconda promptを起動し,以下のコマンドを実行する.
初めの2行はpipも使っているため競合防止で仮想環境を構築するためのコマンド.ChatGPTさん曰く,他の依存ライブラリとの競合を考えたら最も安定するのがpython3.10とのことなのでそのように指定している.
conda create -n helios-env python=3.10
conda activate helios-env
conda install -c conda-forge helios
C:\Users\(ユーザー名)\miniconda3\envs\helios-env\Lib\site-packages\pyhelios にhelios関係のファイルが生成される.
Githubのサンプルデータを使いたい際はGithubからzipファイルをダウンロード・解凍し,helios-main\dataの中身をC:\Users\(ユーザー名)\miniconda3\envs\helios-env\Lib\site-packages\pyhelios\data内に複製しておく.
Anaconda Promptとxmlファイルを用いたheliosでの疑似点群データ計測
Anaconda promptを起動し,仮想環境内で実装した場合は「conda activate helios-env」といった仮想環境の有効化を先に行ってから,以下のコマンドを実行すると,Anaconda prompt実行時のカレントディレクトリ/outputに計測点群データのxyzファイルが保存される.
helios survey.xml
xmlファイルについて
xmlファイルは「survey」「scene」「platform」「scanner」の4つが必要.
以下はサンプルデータをコピーした後のC:\Users\(ユーザー名)\miniconda3\envs\helios-env\Lib\site-packages\pyhelios\dataの中身.

「scanner」はレーザースキャナの特性で,上記では「scanners_als.xml」と「scanners_tls.xml」が該当.
「platform」は三脚や車など,レーザースキャナの搭載手段で,「platforms.xml」が該当.
scannerとplatformのxmlファイルは基本サンプルデータのものを使えばよい.自作したい場合は編集方法を後述している.
「scene」は計測対象を構成するxmlファイルで,「scenes/demo」フォルダ内にいくつかサンプルxmlファイルがある.このxmlファイル内で3Dモデルを配置する.配置できる3Dモデルはobjファイルのみで,「sceneparts」フォルダ内にいくつかサンプルファイルがある.
「survey」は上記3つのxmlファイルを取りまとめている.「surveys/demo」フォルダ内にいくつかサンプルxmlファイルがある.
scannerのxmlファイル解説
<?xml version="1.0"?>
<document>
<scanner
id="my_scanner" <!--XML内の他のファイルから参照される一意の識別子(半角英数字)-->
name="My Scanner" <!--説明用の名前(自由記述 半角英数字)-->
accuracy_m="0.01" <!--測距の精度(メートル)-->
beamDivergence_rad="0.0003" <!--ビームの開き角(rad)-->
optics="rotating" <!--光学機構のタイプ(rotating, risle, oscillatingなど)-->
pulseFreqs_Hz="100000" <!--パルス周波数(Hz) 複数ある場合カンマ区切り-->
pulseLength_ns="5" <!--パルス幅(ナノ秒単位)-->
rangeMin_m="1.0" <!--最小測距距離(メートル)-->
scanAngleMax_deg="90" <!--仮想的な最大スキャン角度(度)-->
scanFreqMax_Hz="100" <!--最大スキャン周波数(Hz)-->
headRotatePerSecMax_deg="60"> <!--回転型の場合は必須 1秒あたりの最大回転角速度-->
<beamOrigin x="0" y="0" z="0.2"> <!--ビームの出発点の位置と回転方向(survey.xmlで設定するplatformSettingsでの座標+platform.xmlで設定するscannerMountでの座標を原点としたローカル座標系)-->
<rot axis="x" angle_deg="0" /> <!--ビームの出発点の回転方向(survey.xmlで設定するplatformSettingsでの座標+platform.xmlで設定するrot axisでの座標を原点としたローカル座標系)-->
</beamOrigin>
</scanner>
<scanner></scanner> <!--複数定義可能-->
</document>
コード例
よく使っている据え置きレーザースキャナLeica RTC360をChatGPTさんに再現していただいたもの
<scanner
id="leica_rtc360"
name="Leica RTC360"
accuracy_m="0.003"
beamDivergence_rad="0.0025"
optics="rotating"
pulseFreqs_Hz="1000000,2000000"
pulseLength_ns="4"
rangeMin_m="0.5"
rangeMax_m="130"
scanAngleMax_deg="300"
scanAngleEffectiveMax_deg="300"
scanFreqMin_Hz="10"
scanFreqMax_Hz="100"
headRotatePerSecMax_deg="60"
wavelength_nm="1550"
>
<FWFSettings beamSampleQuality="3"/>
<beamOrigin x="0" y="0" z="0.2">
<rot axis="x" angle_deg="0" />
</beamOrigin>
<headRotateAxis x="0" y="0" z="1"/>
</scanner>
platformのxmlファイル解説
<?xml version="1.0"?>
<document>
<platform
id="tripod" <!--XML内の他のファイルから参照される一意の識別子(半角英数字)-->
name="TLS Tripod" <!--説明用の名前(自由記述 半角英数字)-->
type="static"> <!--プラットフォームの種類(static, linearpath, multicopter, groundvehicleなど)-->
<scannerMount x="0" y="0" z="1.5"> <!--スキャナの設置位置(survey.xmlで設定するplatformSettingsでの座標を原点としたローカル座標系)-->
<rot axis="x" angle_deg="40 /> <!--スキャナの向き(survey.xmlで設定するplatformSettingsでの座標を原点としたローカル座標系)-->
</scannerMount>
</platform>
<platform></platform> <!--複数定義可能-->
</document>
コード例
三脚にセットする場合
<platform id="tripod" name="TLS Tripod" type="static" drag="0">
<scannerMount x="0" y="0" z="1.5">
</scannerMount>
</platform>
車にセットする場合
<platform id="vmx-450-car-left" name="RIEGL VMX-450 Car Left" type="linearpath">
<scannerMount x="-0.18" y="-2.2" z="2.2">
<rot axis="x" angle_deg="40" />
<rot axis="z" angle_deg="150" />
</scannerMount>
</platform>
UAVにセットする場合
<platform id="quadcopter" name="Quadrocopter UAV" type="multicopter"
drag="0.01" engine_max_force="0.1"
speedup_magnitude="2.0" slowdown_magnitude="2.0" slowdown_distance="5.0"
base_pitch_deg="-5.0"
roll_speed_deg="28.65" pitch_speed_deg="85.94" yaw_speed_deg="85.94"
roll_offset_deg="25.0" pitch_offset_deg="35.0">
<scannerMount x="0" y="0" z="0.2">
<rot axis="x" angle_deg="180" />
<rot axis="z" angle_deg="180" />
</scannerMount>
</platform>
sceneのxmlファイル解説
<?xml version="1.0" encoding="UTF-8"?>
<document>
<scene
id="arbaro_demo" <!--XML内の他のファイルから参照される一意の識別子(半角英数字)-->
name="Arbaro Demo"> <!--説明用の名前(自由記述 半角英数字)-->
<part id="0"> <!--オブジェクトを個々に定義し,idで区別-->
<filter type="objloader">
<param type="string" key="filepath" value="data/sceneparts/basic/groundplane/groundplane.obj"/> <!--objファイル読み込み-->
</filter>
<filter type="translate"> <!--オフセットしないなら不要-->
<param type="vec3" key="offset" value="0;15;0" />
</filter>
<filter type="scale"> <!--拡大縮小しないなら不要-->
<param type="double" key="scale" value="100" />
</filter>
</part>
<part id="1"></part> <!--複数定義可能-->
<part id="2"></part> <!--複数定義可能-->
</scene>
</document>
surveyのxmlファイル解説
<?xml version="1.0" encoding="UTF-8"?>
<document>
<scannerSettings
id="profile1" <!--テンプレート名(半角英数字)-->
active="true"
pulseFreq_hz="100000" <!--1秒あたりの発射パルス数(点密度に影響)-->
scanFreq_hz="120" <!--垂直方向のスキャンレート-->
scanAngle_deg="100" <!--垂直視野(上限60° + 下限40° = 100°)-->
headRotatePerSec_deg="10.0"/> <!--水平方向のスキャナ回転速度-->
<survey
name="arbaro_demo_tls" <!--説明用の名前(自由記述 半角英数字)-->
scene="data/scenes/demo/arbaro_demo.xml#arbaro_demo" <!--sceneのxmlパスとid-->
platform="data/platforms.xml#tripod" <!--platformのxmlパスとid-->
scanner="data/scanners_tls.xml#riegl_vz400"> <!--scannerのxmlパスとid-->
<FWFSettings binSize_ns="0.2" beamSampleQuality="3" /> <!--波形情報-->
<leg> <!--スキャンポイント-->
<platformSettings x="1.0" y="25.5" onGround="true" /> <!--設置個所-->
<scannerSettings template="profile1" verticalAngleMin_deg="-40.0" verticalAngleMax_deg="60" headRotateStart_deg="100" headRotateStop_deg="225" trajectoryTimeInterval_s="1.0"/> <!--設置角度-->
</leg>
<leg></leg> <!--複数定義可能-->
</survey>
</document>
出力ファイルの構成
data\surveys\demo\tls_arbaro_demo.xmlを実行してxyzファイルを出力したところ,1行目は
-12.9882 23.0131 0.0018 598212.6622 0.0000 1 1 289 0 0 50852.008090000
となっていた.初めの3列は座標として,他が分からずChatGPTさんに聞いたところ,以下のような構成らしい.色や法線はつかないと見ていい.
1: X座標 (m) | |
2: Y座標 (m) | |
3: Z座標 (m) | |
4: 時間 (ns) または GPS時間 | 通常、パルス送信時間(相対) |
5: 受信強度(Intensity) | 通常 0~1 の範囲 |
6: エコー番号 | 同一パルス中のエコー(例:1番目) |
7: エコー数 | このパルスにおける全エコー数(例:1/1) |
8: パルスID | 一意なパルス番号(スキャナ側の識別) |
9: チャネル番号 | マルチチャネルスキャナ用(Velodyneなど) |
10: ストリップID | 連続スキャンの分割単位、なければ 0 |
11: GPS時間またはナノ秒 | 出力モードにより意味が重複していることも |
また,出力時のコマンドで以下のようにオプションをつけると,lasファイルでも出力できる.
helios survey.xml --lasOutput
CloudCompareでデータ構成を覗いたところ以下のとおり.読み込んだら色と法線がない点群データが読み込まれていた.
