PythonでGPSログをmp4のアニメーション動画に変換する(gpxpy,staticmap,cv2,numpy,pillow)
当サイトではアフィリエイト広告を利用しています
インラインスケート滑走時のGPSログであるgpxファイルに対して、Pythonを使ってmp4形式のアニメーション動画化してみました。
利用したライブラリはgpxpy,staticmap,cv2,numpy,pillowになっています。
GPSログのアニメーション化
普段インラインスケートを行う際は、RunKeeperを用いてGPSログを記録しています。
このGPSログはgpxというフォーマットで記録されており、こちらをPythonで動画化してみることにしました。
利用したライブラリは以下になります。
- gpxpy: gpxファイルのパース
- staticmap: OpenStreetMapを使って経路などの画像化
- pillow: staticmapの戻り値の画像形式
- cv2: mp4ファイルの生成
- numpy: pillowとcv2の画像形式変換
プログラムの流れ
- gpxpyでGPSログをパース、緯度経度を経路リスト化
- 経路リストを100段階に分割
- 分割経路をstaticmapで画像化(pillow)
- numpyでpillow画像をcv2画像に変換
- cv2でmp4動画を生成
なお、経路の場所がわかりやすいよう、あわせて広い区画からズームしていくような動画を前半に作成しています。
Pythonスクリプト
以下が実際に記述したPythonスクリプトになります。
import gpxpy
import staticmap
import cv2
import numpy as np
GPX_FILE = "data/gps-log.gpx"
MP4_FILE = "out/gpx-movie.mp4"
ITER_NUM = 100
ZOOM_START = 3
ZOOM_LEVEL = 13
ZOOM_ITER = 4
IMG_WIDTH = 800
IMG_HEIGHT = 600
MP4_FPS = 10
def pil2cv(imgPIL):
imgCV_BGR = np.array(imgPIL)[:, :, ::-1]
return imgCV_BGR
def main():
gpx_file = open(GPX_FILE, "r")
gpx = gpxpy.parse(gpx_file)
map = staticmap.StaticMap(IMG_WIDTH, IMG_HEIGHT)
coordinates = [] # [(lon, lat)]
for track in gpx.tracks:
for segment in track.segments:
for point in segment.points:
# print(
# f"Point at ({point.latitude},{point.longitude}) -> {point.elevation}"
# )
coordinates.append((point.longitude, point.latitude))
length = len(coordinates)
# images for movie
zoom_images = []
images = []
# zoom movie
cen = staticmap.CircleMarker(coordinates[0], "#ffffff00", 1)
map.add_marker(cen)
for z in range(ZOOM_START, ZOOM_LEVEL + 1):
image = map.render(zoom=z)
zoom_images.append(image)
map.markers.clear()
# track movie
for i in range(ITER_NUM):
end = int(length * (i + 1) / ITER_NUM)
coords = coordinates[0:end]
pos = coords[-1]
mark_ol = staticmap.CircleMarker(pos, "#ffffff", 18)
mark = staticmap.CircleMarker(pos, "#0000ff", 16)
# line_ol = staticmap.Line(coords, "#ffffffaa", 8)
line = staticmap.Line(coords, "#0000ff80", 6)
map.add_marker(mark_ol)
map.add_marker(mark)
# map.add_line(line_ol)
map.add_line(line)
# max zoom=20
# https://wiki.openstreetmap.org/wiki/Zoom_levels
image = map.render(zoom=ZOOM_LEVEL)
images.append(image)
map.lines.clear()
map.markers.clear()
# gen mp4
codec = cv2.VideoWriter_fourcc(*'mp4v')
video = cv2.VideoWriter(MP4_FILE, codec, MP4_FPS, (IMG_WIDTH, IMG_HEIGHT))
for img in zoom_images:
img = pil2cv(img)
# Zoom動画は時間延ばすために何回か追加する
for _ in range(ZOOM_ITER):
video.write(img)
for img in images:
img = pil2cv(img)
video.write(img)
video.release()
if __name__ == "__main__":
main()
動画のスクリーンショット
生成した動画のスクリーンショットは以下になります。
生成した動画を使った例
実際にインラインスケートで取得したGPSログからアニメーション化した動画が、以下の動画の序盤10秒あたりに組み込まれています。
以下の記事で滑走した際のGPSログですね。
まとめ
- PythonでGPSログ(gpxフォーマット)をmp4動画化
- gpxpy,staticmap,cv2,numpy,pillowを利用
- 前半にズーム動画を追加して経路の場所をわかりやすくしている