OpenCVとPyQt5でGPXファイルの軌跡を動画として保存する
2020/10/26 categories:PyQt5| tags:Python|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()