OpenCVとPyQt5でGPXファイルの軌跡を動画として保存する

QGraphicsViewにGPXファイルの軌跡を描画するプログラムと、QGraphicsViewに描画した内容をOpenCVで動画として保存するプログラムを組み合わせてGPXファイルの移動した軌跡を動画にするプログラムを作ってみました。

描画と動画フレーム作成の処理

GPXファイルの処理は以前作成したプログラムと同様に処理しています。

描画の処理はQGraphicsSceneに、QGraphicsPolygonItemとQGraphicsEllipseItemを追加するという処理です。QGraphicsPolygonItemは全軌跡の描画で、QGraphicsEllipseItemはそのフレームの軌跡上の点でフレームが進むとQGraphicsEllipseItemが移動するように表示しています。

出力された動画

ソースコード

import cv2
import gpxpy
import numpy as np
import sys
from PyQt5 import QtWidgets, QtCore, QtGui

def pixmap_to_cv(pixmap):
    qimage = pixmap.toImage()
    w, h, d = qimage.size().width(), qimage.size().height(), qimage.depth()
    bytes_ = qimage.bits().asstring(w * h * d // 8)
    arr = np.frombuffer(bytes_, dtype=np.uint8).reshape((h, w, d // 8))
    im_bgr = cv2.cvtColor(arr, cv2.COLOR_BGRA2BGR)
    return im_bgr

def main():
    gpx_file = open('track-1155.gpx', mode='r', encoding='utf8')
    gpx = gpxpy.parse(gpx_file)

    segment = gpx.tracks[0].segments[0]
    array = np.array([ [p.longitude for p in segment.points], [p.latitude for p in segment.points] ])
    
    lon_def, lat_def = array[0] - min(array[0]), array[1] - min(array[1])
    if max(lon_def) > max(lat_def):
        ratio = 480 / max(lon_def)
    else:
        ratio = 480 / max(lat_def)
    array[0], array[1] = (lon_def) * ratio, 480 - (lat_def) * ratio

    polygon = QtGui.QPolygonF()
    for lat, lon in zip(array[0], array[1]):
        polygon.append( QtCore.QPointF(lat, lon) )

    app = QtWidgets.QApplication(sys.argv)
    view = QtWidgets.QGraphicsView()
    view.setFrameShape(QtWidgets.QFrame.NoFrame)
    scene = QtWidgets.QGraphicsScene(0, 0, 640, 480, view)
    view.setScene(scene)

    codec = cv2.VideoWriter_fourcc(*'mp4v')
    video = cv2.VideoWriter('temp.mp4', codec, 60.0, (view.size().width(), view.size().height()))

    size = 10
    for i in range(len(array[0])):
        for item in scene.items():
            scene.removeItem(item)
        
        item = QtWidgets.QGraphicsPolygonItem(polygon)
        item.setPen( QtGui.QPen(QtGui.QColor(255, 100, 100)) )

        x, y = item.polygon().at(i).x(), item.polygon().at(i).y()
        ellipse = QtWidgets.QGraphicsEllipseItem()
        ellipse.setRect(x - size/2, y - size/2, size, size)

        scene.addItem(item)
        scene.addItem(ellipse)

        pixmap = view.grab()
        frame = pixmap_to_cv(pixmap)
        video.write(frame)
    
    video.release()

if __name__ == '__main__':
    main()

記事の共有

関連記事

コメント

comments powered by Disqus