水中写真による地図(1)

海底写真

やっていていくつか特有の注意があるので書きます。

GoProにGPSデータの補完

GOProを水中に沈めて写真を撮る場合、水中では微弱なGPS電波の到達の期待は無理ですから、当然ながら写真のGPSはアテになりません。
GOPro 12からはGPSそのものが搭載されていません。

水上ドローンの場合、幸いにしてフライトコントローラーはGPSデータを持っています。 ですから、[カメラシャッターをきったタイミングで同時にGPSデータを保管し、陸上にあがってから取得したGPSデータを撮った写真に書き込めばいい]でしょう。

Drone kitを使ってGPSデータを取得するプログラムは以下。(gps.py)


from dronekit import connect as connection
from logging import getLogger

def getlocation():
    log = getLogger("gopro-fc2")

    """
       以下はテレメトリー接続しないとテストできない。
    """
    connectstring = "tcp:127.0.0.1:5762" # sitl pre-defined
    #connectstring = "/dev/ttyACM0,115200" #USB
    vehicle = connection(connectstring, wait_ready=False)
    vehicle.wait_ready('autopilot_version')
    log.debug("connected Flight Controller")
    # if failed, terminate program by ConnectionRefusedError
    lat = vehicle.location.global_frame.lat
    lon = vehicle.location.global_frame.lon
    alt = vehicle.location.global_frame.alt
direction = vehicle.heading log.info("location: lat="+str(lat)+" lon="+str(lon)+ " alt="+str(alt)) vehicle.close() return(lat, lon, alt, direction) if __name__ == "__main__": x = getlocation() print(x[0]) print(x[1]) print(x[2])
print(x[3])

得たデータは撮影したJpegファイルに書き込むこともできます。 次のとおり


"""
exifの時刻情報を書き込む
"""
from GPSPhoto import gpsphoto

# 入力ファイル定義
listfile = "./piclist/20240508.txt" # 位置情報とファイルのリスト
imagefolder = "./100GOPRO/"  # 写真のあるフォルダー


if __name__ == '__main__' :
    # 属性リストを入手
    with open(listfile, 'r') as f:
        for line in f:
            items = line.split(',')
            l_date = items[0]
            l_filename = items[1]
            l_lat = items[2]
            l_lon = items[3]
            l_alt = items[4]

            imagefile = imagefolder+l_filename
    
            photo = gpsphoto.GPSPhoto(imagefile)
                            
            new_info = gpsphoto.GPSInfo((float(l_lat), float(l_lon)), alt=0)
            
            new_filename = imagefolder+"n_"+l_filename
            
            photo.modGPSData(new_info, new_filename)
            
            print("New file generated: %s" % new_filename)    

上のプログラムの場合だと、新しく”n_”のついた写真が作られます。EXIFの緯度経度データは変更されています。高度(altitude)は水上写真なのですべて0にしています。 EXIFデータの書き換えはいろいろな方法がありますが、GPSPhotoモジュールを使う方法がもっともシンプルだと思います。 Github検索していて、このモジュールをみつけた時はうれしかったな。
ただし、現在、私は書き込んでいません。理由はせっかくGPSデータのファイルがあるのにわざわざEXIFを読み込む必要がないからです。

それとGPSデータでは方位について必ずしも単位が統一されていないようです。

海底地図は既存の写真地図生成プログラムでは作れない

空を飛ぶドローンで空中から写真を取り、地図を作るという試みは極めてスタンダードになされています。
Ardupilotのドキュメント(3D Mapping)は読むべきページです。

Ardupilotでよく使われているものについては3D MappingのページにあるとおりODM(Open Drone Map)かAgisoftのMetashapeでしょう。

同じ方法を水中で行い、海底の状況の地図を作ることを考えます。 Ardupilotの3d mappingのページで紹介されているプログラムはいずれもGPSデータが写真に正しく書き込まれていることを前提としています。 AgisoftはGPSデータがなくてもマップを作れるとありますが、試すとメチャクチャでした。

オープンソースのWebODMを使ってみました。 ODMのドキュメントはこちら 。WebODMについてはWindows, Mac, LinuxそれぞれDockerを使ったインストールの方法が乗っているので、そのとおりやればOKです。

しかし、どのソフトウェアでも写真から地図を作ることはできませんでした。GPSデータは写真に書き込んでいるにもかかわらず、です。
数時間考え込んだ後、放りだします。

理由を説明します。写真から地図を作るアルゴリズムは、一枚の写真の特異点を抽出することから始まります。その特異点を他の写真でも抽出し、同じならば重ねるというやり方です。したがってマップを作る場合、写真は十分な重複が必要となります。70%から80%重なっていることが推奨されるのです。

このアルゴリズムの限界は特異点のほとんどない写真ばかりだと地図を作ることができないことを意味しています。おそらく平坦な砂漠の空撮をしてもマップは作れないと思われます。同様に海底は代わり映えしません。特異点を抽出することが困難なのです。
これらのソフトはGPSデータを重視していません。

ですから、海底を写真で地図製作する場合、上で検討したような地図作成ソフトは使えないことは重要な情報として共有しておきます。

地図にイメージを貼る

Googleサービスは適さない

誰もが夢想する方法は「Googleマップ、Googleアースに撮影した空中写真、海底写真を貼る」です。しかしこの方法は私が試した限りではできませんでした。Googleアースを使って航空写真を貼った例はあるのですが、そもそも航空写真は上記で議論した方法で可能ですから、著作権の制限のあるGoogleのサービスを使う必要はありません。

さらにGoogleだと地図の大きさが制限されていて一定以上拡大できませんでした。写真を取っているエリアってだいたい100メートル四方もありません。地図からするとごくごく狭い範囲なのです。これも海底写真の特徴でしょう。
結局、次の方法を取りました。

Javascriptの地図

このブログに記録したずいぶん前の議論ブラウザーに地図表示で国土地理院の地図を利用してJavascriptで表示することができることを試しました。Leafletパッケージは10年以上前に書かれたものらしいですが、メンテナンスされ続けていて、いまでも地図表示ではデファクトではないでしょうか?

これを利用することにします。
前節で書いたようにドローンは写真の緯度経度、向いている方向を記録しているので、この情報を元に地図上に表示すればいいことになります。

 

 

タイトルとURLをコピーしました