Drogger MJpegで抽出した画像をPIX4Dmaticで扱えるようにする
課題
Drogger MJpegで抽出した画像をPIX4Dmaticで処理する場合に、MJpegの設定によっては画像を読み込むことができない。また、画像の回転方向はフライトログから読み込む必要があるが、現状のMJpegフライトログはRealityScanに寄せてあるため、そのままではPIX4Dmaticで扱うフォーマットと適合しない。
解決策
MJpegの設定を適切なものにする。
Pythonスクリプト等で、フライトログをPIX4Dmaticに適したフォーマットに整形する。
注意点
以下は、とりあえず処理できる、といった程度の仮の設定。
実用上は、検証点との比較などを行い、さらに設定を詰める必要がある。
また、今後のDrogger MJpegのアップデートによっても変更が予想される。
以下は、Drogger GパッケージにGoProをマウントしたハードウェアセッティングを想定している。Droggerとカメラの位置関係次第で、回転角の符号等が異なる場合がある。
MJpegのバージョンはVer 0.4.0を想定している。
Ver 0.3.0以前を使用した場合、抽出された画像の向きが適切でない場合がある。
MJpegでの処理設定
出力タブ
出力座標系は任意だが、PIX4Dmaticでのフライトログのインポート時に適切な座標系を選択する必要がある。
以下では、フライトデータ --> 出力座標系「WGS84」、高さにJPGEO2024の標高を使うを「オフ」として進める。
GパッケージとGoProの組み合わせでは、通常、「Yaw方向を180°回転させる」を有効にする。
外部プログラムタブ
exiftoolを使用 --> カメラメーカーとカメラモデルを指定
Ver 0.4.0 現在、GoProと一部スマホ以外は、MJpegでカメラモデルの書き込みができない。それ以外のカメラを使用する場合は、後から自分で書き込む必要がある(または、GoPro以外でもGoProと書き込んでしまって通るかもしれない)。
flightlog.txtの改変
フライトログをPix4Dmaticに読み込むために、適切なフォーマットに変更する。
変更点は以下の通り。
水平精度をまとめる
PIX4Dmaticでは、画像の位置精度はX,Yそれぞれではなく、単一の水平精度として読み込む。
`LongitudeAccuracy, LatitudeAccuracy`を、`Horizontal accuracy`(ヘッダー名は適当)などとしてひとつにする。
MJpegで出力される水平精度はX,Yで同じ値なため、整形の際にどちらかを破棄すれば良い。
Pitch角を整形する
MJpegで出力される値とPIX4Dmaticで扱うPitch角の基準が異なるため、Pitchの値を(X)としたときに、f(x) = 90 - (x) になるようにPitchの値を書き換える。
それぞれのPitch角は次のようになっている。
MJpegでは、真下が +90°、水平が 0°、真上が -90°
ただし、Droggerとカメラの剛体接続の方法によって異なる。PIX4Dmaticにいったん読み込んだあと、3Dビューでカメラの姿勢を確認しながら、現地のカメラ姿勢と近くなるPitch角の値を探すと良い。
PIX4Dmaticは、真下が 0°、水平が +90°、真上が +180°
これはカメラによって変更は無い(と思う)。
上記で改変した値を含め、フライトログの列を以下のように並べ替える。
`Name, Latitude, Longitude, Altitude, Yaw, Pitch, Roll, Horizontal accuracy, AltitudeAccuracy`
処理するためのPythonスクリプト
# ChatGPT o3
import csv
from pathlib import Path
INFILE = Path("flightlog.txt")
OUTFILE = Path("flightlog_reformatted.txt")
with INFILE.open(newline="", encoding="utf-8") as fin, \
OUTFILE.open("w", newline="", encoding="utf-8") as fout:
reader = csv.reader(fin)
writer = csv.writer(fout)
# ---- 1. ヘッダを解析 -------------------------------------------------
header_raw = next(reader)
if not header_raw or not header_raw[0].lstrip().startswith("#"):
raise RuntimeError("First line must be a header beginning with '#'.")
header = [h.lstrip("# ").strip() for h in header_raw]
# 列インデックスを取得
idx = {name: header.index(name) for name in (
"Name", "Longitude", "Latitude", "Altitude",
"LongitudeAccuracy", "LatitudeAccuracy", "AltitudeAccuracy",
"Yaw", "Pitch", "Roll"
)}
# ---- 2. 目的のヘッダ順を定義 ----------------------------------------
new_header = [
"# Name", # 先頭だけ "# " を再付与
"Latitude",
"Longitude",
"Altitude",
"Yaw",
"Pitch",
"Roll",
"Horizontal accuracy", # 改名
"AltitudeAccuracy"
]
writer.writerow(new_header)
# ---- 3. 各行を変換して書き出す --------------------------------------
for row in reader:
if not row: # 空行はスキップ
continue
# Pitch の数値変換と置き換え -------------------------------------
try:
pitch_val = float(row[idx["Pitch"]])
new_pitch = 90.0 - pitch_val
row[idx["Pitch"]] = f"{new_pitch:g}" # 余分な 0 を付けない書式
except ValueError:
# 数値でなければ(例:空文字やヘッダ行など)そのまま出力
pass
new_row = [
row[idx["Name"]],
row[idx["Latitude"]], # Longitude / Latitude を実質的に入れ替え
row[idx["Longitude"]],
row[idx["Altitude"]],
row[idx["Yaw"]],
row[idx["Pitch"]], # 変換済み
row[idx["Roll"]],
row[idx["LongitudeAccuracy"]], # Horizontal accuracy
row[idx["AltitudeAccuracy"]]
]
writer.writerow(new_row)
print(f"Done! Output written to: {OUTFILE.resolve()}")PIX4Dmaticでの処理手順
フライトログの読み込み
画像をインポート
"ファイル --> インポート --> 画像の位置と向き" から、上記で改変したフライトログを指定して読み込む。
今回の場合、水平座標系は「WGS84 EPSG:4326」、鉛直座標系は「Ellipsoidal height over WGS 84」とする。
MJpegの設定で平面直角座標等を指定した場合は、それに応じた設定にする。
キャリブレーション
テンプレート
「PIX4Dcatch」や「3Dモデル」などを選択
パイプライン
「信頼性の高い位置と向き情報」「スケーラブル標準」などを選択
それぞれ、フライトログで読み込んだ値に対する重み付けが異なる。
カメラ内部パラメータ
撮影機材に準じた値にする。
実際と乖離しすぎるとキャリブレーション不良の原因となる。
