国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

使用百度地圖路書為騎行視頻添加同步軌跡

這篇具有很好參考價值的文章主要介紹了使用百度地圖路書為騎行視頻添加同步軌跡。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

問題背景

使用 gopro 記錄騎行過程 (參考《使用二手 gopro 做行車記錄儀 》),事后將視頻文件導(dǎo)出來回顧整個旅程,會發(fā)現(xiàn)將它們與地圖對應(yīng)起來是一件困難的事。想要視頻和地圖對應(yīng),首先需要上報每個時刻的位置,gopro 本身是支持的,然而要到版本 5 才可以,我的 3+ 太老了沒這能力。為此我配備了專門的 GPS 定位器來記錄騎行軌跡 (e.g. 途強定位),在官網(wǎng)上是可以看到整個騎行軌跡,像下面這樣:

使用百度地圖路書為騎行視頻添加同步軌跡

這個界面也可以回放軌跡,回放速度還能調(diào)整:

使用百度地圖路書為騎行視頻添加同步軌跡

不過即使調(diào)到最慢,速度相對視頻還是快,更最要命的是,這個回放看起來并不參考 GPS 時間,僅僅是按順序播放。舉例來說,間隔 10 秒的兩個點和間隔 10 分鐘的兩個點,播放時沒有差別,都是相同的速度播放。

所幸 GPS 軌跡數(shù)據(jù)是可以導(dǎo)出的:

使用百度地圖路書為騎行視頻添加同步軌跡

如果能用導(dǎo)出的軌跡數(shù)據(jù),根據(jù) GPS 時間精準的制作騎行軌跡,是不是就能和視頻同步了?抱著這個想法,有了下面的探索過程。

可行性研究

DashWare

根據(jù) GPS 數(shù)據(jù)制作騎行軌跡并不算一個新鮮需求,早期玩極限運動的各位先驅(qū)早已經(jīng)探索的明明白白,也有專業(yè)的軟件支持這種需求,DashWare 就是其中的佼佼者。之前看到 B 站上一個旅游區(qū) UP,他就介紹過一種基于 DashWare 給國外徒步旅行的游記視頻加軌跡路線的方法 (參考附錄 15),整個過程可以總結(jié)為三步:

  • 抽取視頻的 GPX 信息
  • 編輯 GPX 然后快速跳轉(zhuǎn)地圖截圖
  • 用 Dashware 套用作者的模板生成軌跡路徑

這個過程嚴重依賴視頻記錄的 GPX 信息,而我的硬件設(shè)備不支持,放棄。如果你的設(shè)備可以支持,其實用 DashWare 還是蠻方便的。

曬一下我自己配的 GPS 定位器:

使用百度地圖路書為騎行視頻添加同步軌跡

這種硬件不太方便的地方是需要單獨供電并插流量卡,后者只保兩年,兩年以后需要自己續(xù)費或買流量卡應(yīng)付。GPS 數(shù)據(jù)量不大,據(jù)客服說一直不停上報大約需要 22M/月,我騎的少 3M 就夠用,最后在某寶上配的 5M/月 的移動流量卡大約 8.7 元,給各位做個參考。流量查詢和續(xù)費可以通過公眾號進行:

使用百度地圖路書為騎行視頻添加同步軌跡

百度路書

根據(jù) GPS 數(shù)據(jù)繪制軌跡,其實國內(nèi)各大地圖服務(wù)商都提供了解決方案,偶然的一個機會看到使用百度地圖的路書可以方便快捷的制作行駛軌跡 (參考附錄 1),最終效果和我的場景非常相似:

使用百度地圖路書為騎行視頻添加同步軌跡

源碼不過寥寥一百行,其中關(guān)鍵的就是下面這幾十行:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>百度地圖顯示車輛運行軌跡(靜態(tài))</title>
        <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=你在百度地圖開放平臺申請的ak"></script>
        <!--  你在百度地圖開放平臺申請的ak -->
        
        <!-- 路書功能 -->
        <script type="text/javascript" src="http://api.map.baidu.com/library/LuShu/1.2/src/LuShu_min.js"></script>
    </head>
    <body>
        <div id="allmap" style="position: absolute; width: 100%; top: 0px; bottom: 0px"></div>
        <script type="text/javascript">
...
        //顯示車輛軌跡線
        //車輛軌跡坐標
        var latLngArray = [
            "113.408984,23.174023",
            "113.406639,23.174023",
            "113.403944,23.173566",
            "113.400827,23.17394",
            "113.397468,23.174496",
            "113.391494,23.174513",
            "113.389032,23.174588",
            "113.388736,23.173217",
            "113.388511,23.171888",
            "113.388592,23.170501",
            "113.38861,23.170219",
            "113.38861,23.168342",
            "113.388574,23.165218"
        ];
...
        var pois = [];
        for(var i = 0; i < latLngArray.length ; i++) {
            var latLng = latLngArray[i];
            var pointArray = latLng.split(",");
            pois.push(new BMap.Point(pointArray[0], pointArray[1]));
        }
...
        var polyline = new BMap.Polyline(pois, {
            enableEditing: false,//是否啟用線編輯,默認為false
            enableClicking: true,//是否響應(yīng)點擊事件,默認為true
            icons: [icons],
            strokeWeight: '8',//折線的寬度,以像素為單位
            strokeOpacity: 0.8,//折線的透明度,取值范圍0 - 1
            strokeColor: "#18a45b" //折線顏色
        });
        map.addOverlay(polyline);
...
        var lushu = new BMapLib.LuShu(map,pois,{
            defaultContent: trackContent,
            autoView:false,//是否開啟自動視野調(diào)整,如果開啟那么路書在運動過程中會根據(jù)視野自動調(diào)整
            icon: icon_gps_car_run,
            speed: 100,
            enableRotation:true,//是否設(shè)置marker隨著道路的走向進行旋轉(zhuǎn)
        });
        lushu.start(); 
        </script>
    </body>    
</html>

梳理一下其中的關(guān)鍵點:

  • html header 中聲明百度地圖的 ak (申請方式原作者有說明)
  • body 中創(chuàng)建 GPS 坐標數(shù)組 (latLngArray) 并轉(zhuǎn)化為路書能接受的格式 (pois)
  • 創(chuàng)建軌跡總覽線 (polyline)
  • 制作小車移動軌跡 (lushu.start)

可以看到核心功能其實都是通過百度地圖 js 類 BMapLib.LuShu 實現(xiàn)的,下面好好研究一下它的接口。

BMapLib.LuShu

這個類的官方文檔可參考附錄 16,提供的方法主要如下:

  • constructor
  • start
  • stop
  • pause

非常簡潔。其中 start / stop / pause 都不再提供參數(shù),所以想進行更復(fù)雜的控制只能事先在構(gòu)造函數(shù)中指定了:

BMapLib.LuShu(map, path, opts)
LuShu類的構(gòu)造函數(shù)

參考示例:
var lushu = new BMapLib.LuShu(map,arrPois,{defaultContent:"從北京到天津",landmarkPois:[]});

參數(shù):
{Map} map
    Baidu map的實例對象.
{Array} path
    構(gòu)成路線的point的數(shù)組.
{Json Object} opts
    可選的輸入?yún)?shù),非必填項??奢斎脒x項包括:
    {
    "landmarkPois" : {Array} 要在覆蓋物移動過程中,顯示的特殊點。格式如下:landmarkPois:[
    {lng:116.314782,lat:39.913508,html:'加油站',pauseTime:2},
    {lng:116.315391,lat:39.964429,html:'高速公路收費站,pauseTime:3}]

    "icon" : {Icon} 覆蓋物的icon,
    "speed" : {Number} 覆蓋物移動速度,單位米/秒

    "defaultContent" : {String} 覆蓋物中的內(nèi)容
    "autoView" : {Boolean} 是否自動調(diào)整路線視野,默認不調(diào)整
    "enableRotation" : {Boolean} 是否開啟marker隨路走向旋轉(zhuǎn),默認為false,即不隨路走向旋轉(zhuǎn)
    }

除 map、path 是必需參數(shù)外,其它均為可選參數(shù)。下面對各個選項做個簡單說明:

  • speed:用于控制小車移動的速度,單位是 m/s,示例中給的值是 100,相當于 360 km/h,那是相當快了,如果按 72 km/h 算的話,才 20 m/s
  • autoView:隨著小車的移動,自動調(diào)整地圖位置,以保證小車位于視野之內(nèi),一般是在小車走出視野邊緣后進行調(diào)整。推薦打開,除非是鷹眼視圖
  • icon:小車的圖形,可以指定本地文件
  • defaultContent:對軌跡的文字說明,跟隨在小車左右
  • enableRotation:是否旋轉(zhuǎn)小車圖形以對準前進方向。推薦打開,以獲取更好的演示效果
  • landmarkPois:設(shè)置的途經(jīng)點數(shù)組,及在途經(jīng)點的經(jīng)停時間,單位為秒,這個選項在示例中未使用

梳理了一遍 LuShu 的功能,發(fā)現(xiàn)即使能將小車移動速度調(diào)整到與實際平均速度一致,地圖與視頻仍然對不上。原因與之前一樣,LuShu 中根本沒有輸入 GPS 時間參數(shù)的地方,所以它完全沒有坐標點與時間對照的概念,所有坐標之間的時間間隔都是一致的,唯一可調(diào)節(jié)的地方就是 speed 參數(shù),它用來控制這個間隔的大小。

回過頭來看途強在線的界面,基本可以確認,這也是基于 LuShu 改的,所以它們的問題是相通的。

定時器

現(xiàn)在問題的關(guān)鍵就變成如何等待真實的時間間隔。一開始想手動 pause 和 start,寫了個定時器來做這個事情:

...
        var lushu = new BMapLib.LuShu(map,pois,{
            defaultContent: trackContent,
            autoView:false,//是否開啟自動視野調(diào)整,如果開啟那么路書在運動過程中會根據(jù)視野自動調(diào)整
            icon: icon_gps_car_run,
            speed: 100,
            enableRotation:true,//是否設(shè)置marker隨著道路的走向進行旋轉(zhuǎn)
        });
        lushu.start();

        let is_pause=false
        setInterval(function(){
            if (is_pause) {
                lushu.start(); 
            } else { 
                lushu.pause(); 
            }
            is_pause = !is_pause; 
        }, 1000);   
 ...

先簡單的設(shè)置成每秒一次,后面可以根據(jù)實際的時間差來控制等待時間。運行時發(fā)現(xiàn),第一次定時器到期后小車暫停,然后就沒有然后了…小車再也沒有啟動過。在定時器函數(shù)中加了一些日志進一步觀察:

interval false, count 1
after true
interval true, count 2
interval true, count 3
interval true, count 4
interval true, count 5
interval true, count 6
interval true, count 7
interval true, count 8
interval true, count 9
interval true, count 10
interval true, count 11

發(fā)現(xiàn)函數(shù)結(jié)尾處只被調(diào)用了一次 (after true),之后就再也沒打印,且 is_pause 的值一直為 true,可以確認反轉(zhuǎn) is_pause 值的代碼沒有被執(zhí)行。

為了確認是否是變量作用域的問題,增加了一個全局變量 count,每次在函數(shù)入口處自增并打印它的值,可以看到能正常遞增,排除 js 變量作用域的問題。

經(jīng)過這番折騰,基本可以確認問題是出在了 start 接口,看現(xiàn)象再次調(diào)用它貌似沒有返回,懷疑這個接口是不能重入的,或者就不能這樣用,定時器方案走不下去了,放棄。

landmarkPois

正所謂“踏破鐵鞋無覓處,柳暗花明又一村” ??,之前看 LuShu 構(gòu)造函數(shù)時,有個 landmarkPois 參數(shù)里有經(jīng)停時間,這個和我的場景非常吻合,能不能拿來用呢?仔細的研究了一下這個 landmarkPois,它的本意是提供 speed 參數(shù)控制外的時間間隔處理,例如在服務(wù)區(qū)休息、加油站加油等等,去掉這些耗時較大的坐標點位,剩余的軌跡就能比較真實的反映實際的行走過程。

我的想法比較簡單粗暴,直接將每個 GPS 坐標作為一個經(jīng)停點放在這個參數(shù)里,這樣在每個 GPS 上報點都能停留相應(yīng)的時間間隔,是不是就能和視頻同步起來了?不過這個參數(shù)的本意是放少量數(shù)據(jù)點,像我這種放大量數(shù)據(jù)進去會不會有什么副作用,還得試一試才知道。說干就干,用之前的 demo 驗證下:

...
        var landmarks = [
            {lng:113.408984,lat:23.174023,html:'1',pauseTime:1},
            {lng:113.406639,lat:23.174023,html:'1',pauseTime:1},
            {lng:113.403944,lat:23.173566,html:'1',pauseTime:1},
            {lng:113.400827,lat:23.17394,html:'1',pauseTime:1},
            {lng:113.397468,lat:23.174496,html:'1',pauseTime:1},
            {lng:113.391494,lat:23.174513,html:'1',pauseTime:1},
            {lng:113.389032,lat:23.174588,html:'1',pauseTime:1},
            {lng:113.388736,lat:23.173217,html:'1',pauseTime:1},
            {lng:113.388511,lat:23.171888,html:'1',pauseTime:1},
            {lng:113.388592,lat:23.170501,html:'1',pauseTime:1},
            {lng:113.38861,lat:23.170219,html:'1',pauseTime:1},
            {lng:113.38861,lat:23.168342,html:'1',pauseTime:1},
            {lng:113.388574,lat:23.165218,html:'1',pauseTime:1}
        ];
...
        var lushu = new BMapLib.LuShu(map,pois,{
            defaultContent: trackContent,
            autoView:false,//是否開啟自動視野調(diào)整,如果開啟那么路書在運動過程中會根據(jù)視野自動調(diào)整
            icon: icon_gps_car_run,
            speed: 100,
            enableRotation:true,//是否設(shè)置marker隨著道路的走向進行旋轉(zhuǎn)
            landmarkPois: landmarks
            });
        lushu.start();
...

landmarks 變量使用的坐標與 pois 完全一樣,經(jīng)停時間全部設(shè)置為 1 秒,顯示內(nèi)容也為 1 (html 字段)。下面是運行效果:

使用百度地圖路書為騎行視頻添加同步軌跡

能行!雖然小車移動沒之前那么平滑了,但為了能和視頻同步上,這點兒瑕疵可以接受!

研究了下 landmarkPois 與 speed 之間的關(guān)系:當 speed 值不是特別大時,小車在兩個相鄰經(jīng)停點幾乎是瞬移過去的,沒有動畫,即使將 speed 設(shè)置的非常小也是如此,例如 0;當 speed 值特別大時,小車不移動 (> 10W)、或者遺漏部分經(jīng)停點 (> 2W),最終我設(shè)置的 speed 值是 1000,這樣可以保證小車移動,同時也避免了如果 LuShu 在經(jīng)停點之間也有動畫時浪費時間的問題。關(guān)于 speed 設(shè)置太大導(dǎo)致部分經(jīng)停點遺漏的問題,后面還會詳細說明。

解決方案

雖然有了技術(shù)路線,但每次制作軌跡視頻,都需要把原始數(shù)據(jù)導(dǎo)入 html,特別是經(jīng)停點還要根據(jù)相鄰兩點的 GPS 時間計算一個經(jīng)停時間 (e.g. 10:00:58 到 10:01:05 相隔 7 秒),當騎行距離比較遠時,工作量就比較大了。于是想到可以將上面的過程做成一個工具,它一鍵導(dǎo)入 GPS 數(shù)據(jù)生成軌跡動畫;如果再輔以 mac 上的截圖工具,就可以直接出軌跡視頻了;而后這個視頻可以作為小窗導(dǎo)入騎行視頻,從而得到同步的地圖軌跡展示,效果就類似下面這樣:

使用百度地圖路書為騎行視頻添加同步軌跡

csv

正式開始前,先了解下“途強在線”導(dǎo)出的 GPS 數(shù)據(jù)格式:

序號,定位時間,接收時間,經(jīng)度/緯度,速度(km/h),方向,定位類型,上報模式,位置
...
267,2022-11-19 11:24:20,2022-11-19 11:24:37,116.092747/40.103613,26km/h,西南向(方向數(shù): 219),衛(wèi)星定位,拐點上傳,"北京市海淀區(qū)龍泉寺北路,鳳凰嶺自然風景區(qū)東南1228米"
268,2022-11-19 11:24:22,2022-11-19 11:24:37,116.092693/40.103498,26km/h,正南向(方向數(shù):173),衛(wèi)星定位,拐點上傳,"北京市海淀區(qū)鳳凰嶺路,鳳凰嶺自然風景區(qū)東南1226米"
269,2022-11-19 11:24:25,2022-11-19 11:24:37,116.0928/40.103289,32km/h,東南向(方向數(shù):151),衛(wèi)星定位,拐點上傳,"北京市海淀區(qū)鳳凰嶺路,鳳凰嶺自然風景區(qū)東南1240米"
270,2022-11-19 11:24:29,2022-11-19 11:24:37,116.092933/40.103062,17km/h,正南向(方向數(shù):190),衛(wèi)星定位,拐點上傳,"北京市海淀區(qū)鳳凰嶺路,鳳凰嶺自然風景區(qū)東南1257米"
271,2022-11-19 11:25:19,2022-11-19 11:25:42,116.092747/40.10296,0km/h,正西向(方向數(shù):252),衛(wèi)星定位,從運動變靜止狀態(tài)補傳最后一個有效定位點,"北京市海淀區(qū)鳳凰嶺路,鳳凰嶺自然風景區(qū)東南1244米"
272,2022-11-19 11:25:39,2022-11-19 11:25:42,116.091991/40.102782,21km/h,正西向(方向數(shù):255),衛(wèi)星定位,定時上報,"北京市海淀區(qū)鳳凰嶺路,鳳凰嶺自然風景區(qū)東南1188米"
273,2022-11-19 11:25:49,2022-11-19 11:25:50,116.09144/40.102653,16km/h,正西向(方向數(shù):256),衛(wèi)星定位,定時上報,"北京市海淀區(qū)鳳凰嶺路,鳳凰嶺自然風景區(qū)東南1147米"
274,2022-11-19 11:25:59,2022-11-19 11:26:05,116.091164/40.10256,7km/h,西南向(方向數(shù): 215),衛(wèi)星定位,定時上報,"北京市海淀區(qū)鳳凰嶺路,鳳凰嶺自然風景區(qū)東南1128米"
275,2022-11-19 11:26:23,2022-11-19 11:26:24,116.091236/40.102373,15km/h,西北向(方向數(shù):93),衛(wèi)星定位,拐點上傳,"北京市海淀區(qū)鳳凰嶺路,鳳凰嶺自然風景區(qū)東南1141米"
276,2022-11-19 11:26:26,2022-11-19 11:26:27,116.091422/40.1024,18km/h,西北向(方向數(shù):71),衛(wèi)星定位,拐點上傳,"北京市海淀區(qū)鳳凰嶺路,鳳凰嶺自然風景區(qū)東南1155米"
277,2022-11-19 11:27:23,2022-11-19 11:27:26,116.091698/40.102489,0km/h,西北向(方向數(shù):68),衛(wèi)星定位,從運動變靜止狀態(tài)補傳最后一個有效定位點,"北京市海淀區(qū)鳳凰嶺路,鳳凰嶺自然風景區(qū)東南1174米"

標題行已經(jīng)對各個列做了說明,這里用到的只有時間、坐標、速度三個列,其中

  • 時間取的是定位時間,因為接收時間會有明顯延遲,不能反映真實的"位置-時間"對應(yīng)關(guān)系
  • GPS 坐標在這里是一列 (116.092747/40.103613),后面需要拆分為獨立的經(jīng)緯度 (116.092747, 40.103613)
  • 速度用于設(shè)置 landmarkPois 的 html 字段,顯示在小車左近,用于展示瞬時 GPS 速度

gps

最終不論是 landmarks 變量還是 latLngArray 變量,都需要坐標數(shù)據(jù),所以首先需要將 csv 中的 GPS 坐標提取出來,csv2gps.sh 就是用來做這個的:

...
while :
do
    read -r line
    if [ $? -ne 0 -a -z "${line}" ]; then
        # last line without LF will trigger read return error
        # so here check content of 'line', too
        break;
    fi

    if [ $n -ne 0 ]; then
        # skip csv header
        echo "${line}" | awk -F',' '{print $4}' | awk -F'/' '{print $1,$2}'
    fi

    n=$((n+1))
done < "${file}"

通過 awk 提取 csv 第四列并將其拆分為兩列保存在新文件 data.gps 中:

...
116.092747 40.103613
116.092693 40.103498
116.0928 40.103289
116.092933 40.103062
116.092747 40.10296
116.091991 40.102782
116.09144 40.102653
116.091164 40.10256
116.091236 40.102373
116.091422 40.1024
116.091698 40.102489

坐標轉(zhuǎn)換

直接用 gps 坐標在百度地圖上繪制,會發(fā)現(xiàn)和真實的位置偏差了一些:

使用百度地圖路書為騎行視頻添加同步軌跡

經(jīng)過一番研究,發(fā)現(xiàn)原來每個地圖服務(wù)商都有自己的大地坐標系,例如百度使用的是百度坐標系 BD09,高德、QQ、谷歌使用的是火星坐標系 GCJ02,而 GPS 數(shù)據(jù)一般是地球坐標系 WGS84。因此需要將 GPS 坐標轉(zhuǎn)換后才能在百度地圖中展示,網(wǎng)上有批量轉(zhuǎn)換的工具 (參考附錄 11):

使用百度地圖路書為騎行視頻添加同步軌跡

取第一個點查看轉(zhuǎn)換結(jié)果:

使用百度地圖路書為騎行視頻添加同步軌跡

發(fā)現(xiàn)還是有明顯差別的。經(jīng)過轉(zhuǎn)換的坐標和實際位置就差不多了:

使用百度地圖路書為騎行視頻添加同步軌跡

在線工具雖然好用,但一不能自動執(zhí)行,二批量轉(zhuǎn)換還要收取會員費,幸好百度地圖提供了坐標轉(zhuǎn)換的接口 (參考附錄 7):

https://api.map.baidu.com/geoconv/v1/?coords=114.21892734521,29.575429778924&from=1&to=5&ak=你的密鑰 //GET請求

其中多個坐標以分號 (;) 分隔,最多一次可以請求 100 個。返回的內(nèi)容為 json,形式如下:

{
  "status": 0,
  "result": [
    {
      "x": 116.28841472033484,
      "y": 40.21235883074968
    }
  ]
}

result 是個數(shù)組,當有多個請求坐標時,將返回多個轉(zhuǎn)換后的坐標。

有了接口,就可以用腳本 (gps2bd.sh) 自動轉(zhuǎn)換啦,下面先上單個轉(zhuǎn)換的版本:

...
while :
do
    read -r line
    if [ $? -ne 0 -a -z "${line}" ]; then 
        # last line without LF will trigger read return error
        # so here check content of 'line', too
        break; 
    fi

    # delete spaces
    # line="${line// /}"
    # replace space to ','
    line="${line/ /,}"
    # echo "${line}"
    resp=$(curl -gs "https://api.map.baidu.com/geoconv/v1/?coords=${line}&from=1&to=5&ak=${BAIDU_MAP_AK}")
    # echo "${resp}"
    if [ ! -z "${resp}" ]; then 
        x=$(echo "${resp}" | jq '.result[0].x')
        y=$(echo "${resp}" | jq '.result[0].y')
        echo "\"$x,$y\","
    fi
done < "${file}"

簡潔明了但是性能低,數(shù)據(jù)量大的時候,足足能等一顆煙的功夫,下面上批量版本:

while [ ${end} -eq 0 ];
do
    while [ $n -lt 100 ];
    do
        read -r line
        if [ $? -ne 0 -a -z "${line}" ]; then
            # last line without LF will trigger read return error
            # so here check content of 'line', too
            end=1
            break;
        fi

        # delete spaces
        # line="${line// /}"
        # replace space to ','
        line="${line/ /,}"
        # echo "${line}"
        if [ $n -eq 0 ]; then
            data="${line}"
        else
            data="${data};${line}"
        fi

        n=$((n+1))
    done

    if [ $n -gt 0 ]; then
        resp=$(curl -gs "https://api.map.baidu.com/geoconv/v1/?coords=${data}&from=1&to=5&ak=${BAIDU_MAP_AK}")
        # echo "$n: ${resp}"
        if [ ${IS_MAC} -eq 0 ]; then
            echo "${resp}" | jq -r '.result[]|.x,.y' | sed -n '{N;s/\n/ /p}' | awk '{printf "\"%s,%s\",\n",$1,$2}'
        else
            echo "${resp}" | jq -r '.result[]|.x,.y' | gsed -n '{N;s/\n/ /p}' | awk '{printf "\"%s,%s\",\n",$1,$2}'
        fi
    fi

    n=0
done < "${file}"

為了提升效率,每 100 個點請求一次,注意解析響應(yīng)時的技巧,jq 會將坐標 x、y 分為兩行,sed/gsed 將它們合并成一行,awk 再次將它們改造為后面 js 能接受的形式:

...
"116.10568842325927,40.11056701573591",
"116.10579500660829,40.11035775778459",
"116.10592816947326,40.11013058608767",
"116.10574200140061,40.11002872275517",
"116.10498588059896,40.10985140314029",
"116.104434547854,40.10972328042703",
"116.10415815632084,40.1096308424909",
"116.10423031248894,40.109443479731034",
"116.10441655222886,40.109470198714",
"116.10469264841298,40.109558635595626",

這種形式和之前 latLngArray 的內(nèi)容很像,就是為了便于直接插入到最終的 html 中。

計算等待時間

到目前為止,我只處理了坐標數(shù)據(jù),GPS 時間及相鄰點的時間差還沒有計算,這是 landmarks 中 pauseTime 字段所需要的,這一步來搞定它 (bd2land.sh):

while :
do
    read -r line
    if [ $? -ne 0 -a -z "${line}" ]; then 
        # last line without LF will trigger read return error
        # so here check content of 'line', too
        break; 
    fi

    if [ $n -ne 0 ]; then
        # skip csv header
        time=$(echo "${line}" | awk -F',' '{print $2}')
        if [ ${IS_MAC} -eq 1 ]; then 
            timestamp=$(date -j -f "%Y-%m-%d %H:%M:%S" "${time}" "+%s")
        else
            timestamp=$(date -d "${time}" "+%s")
        fi
    
        # read coodinate from data.bd instead of data.csv to prevent data incorrect
        #data=$(echo "${line}" | awk -F',' '{print $4}' | awk -F'/' '{print "lng:",$1,",lat:",$2}')
        # note, sed index is 1 based, and csv file have a header take line 0, so it just match..
        data=$(sed -n "${n}p" "${bdfile}")
        x=$(echo "${data}" | awk -F',|"' '{print $2}')
        y=$(echo "${data}" | awk -F',|"' '{print $3}')
        # echo "data:${data},x:$x,y:$y"
        label=$(echo "${line}" | awk -F',' '{print $5}')
    
        if [ $n -eq 1 ]; then 
            # insert a 10 second stay for first record
            echo "{lng:$x,lat:$y,html:'${label}',pauseTime:10},"
        else
            # compute elapse from second record
            elapse=$((timestamp - prevstamp))
            echo "{lng:$x,lat:$y,html:'${label}',pauseTime:${elapse}},"
        fi
    
        prevstamp=${timestamp}
    fi

    n=$((n+1))
done < "${csvfile}"

純粹的 shell,整合了以下命令

  • date:獲取 GPS 時間對應(yīng)的 epoch 時間戳值,這樣兩個相鄰時間相減就可以得到時間間隔了
  • sed:獲取 csv 文件第 n 條記錄對應(yīng)的 bd 文件中的數(shù)據(jù)
  • awk:獲取 bd 文件中的 x、y 值;獲取 csv 文件中的速度信息作為經(jīng)停點標簽

需要注意的是 date 命令在 mac 和 linux 上不同的語法,這方面信息可參考之前的文章:《使用 shell 腳本自動獲取發(fā)版指標數(shù)據(jù)》、《使用 shell 腳本自動申請進京證 (六環(huán)外)》、《[apue] 一圖讀懂 Unix 時間日期例程相互關(guān)系》。

經(jīng)過計算輸出的 land 文件大概長這樣:

...
{lng:116.10568842325927,lat:40.11056701573591,html:'26km/h',pauseTime:2},
{lng:116.10579500660829,lat:40.11035775778459,html:'32km/h',pauseTime:3},
{lng:116.10592816947326,lat:40.11013058608767,html:'17km/h',pauseTime:4},
{lng:116.10574200140061,lat:40.11002872275517,html:'0km/h',pauseTime:50},
{lng:116.10498588059896,lat:40.10985140314029,html:'21km/h',pauseTime:20},
{lng:116.104434547854,lat:40.10972328042703,html:'16km/h',pauseTime:10},
{lng:116.10415815632084,lat:40.1096308424909,html:'7km/h',pauseTime:10},
{lng:116.10423031248894,lat:40.109443479731034,html:'15km/h',pauseTime:24},
{lng:116.10441655222886,lat:40.109470198714,html:'18km/h',pauseTime:3},
{lng:116.10469264841298,lat:40.109558635595626,html:'0km/h',pauseTime:57},

看起來已經(jīng)非常適合作為元素插入 landmarks 變量聲明中了,哈哈。

揉合在一起

在瀏覽最終的 facade 腳本之前,先看看對 html 做的手腳:

...

var latLngArray = [
    //BD_DATA_PLACETAKER
]; 

var pois = [];
for(var i = 0; i < latLngArray.length ; i++) {
    var latLng = latLngArray[i];
    var pointArray = latLng.split(",");
    pois.push(new BMap.Point(pointArray[0], pointArray[1]));
}

carCenterPoint = pois[0]; 
console.log("center:"+carCenterPoint.lng+","+carCenterPoint.lat); 

var landmarks = [
    //LAND_DATA_PLACETAKER
];
...

latLngArray 留空并設(shè)置了插入標識 BD_DATA_PLACETAKER,這里將是 bd 文件插入的位置;landmarks 留空并設(shè)置了插入標識 LAND_DATA_PLACETAKER,這里將是 land 文件插入的位置。

start.sh 將一切揉合起來:

#! /bin/sh

if [ ! -f data.csv ]; then 
    echo "please put gps data into 'data.csv' first!"
    exit 1
fi

if [ ! -f data.gps ]; then 
    echo "start generate file: data.gps, extract gps from csv data"
    sh csv2gps.sh data.csv > data.gps
    # data.bd need re-generate
    rm data.bd
else 
    echo "use file: data.gps"
fi 

if [ ! -f data.bd ]; then 
    echo "start generate file: data.bd, convert gps to baidu coordinate"
    sh gps2bd.sh data.gps > data.bd
    # index.data.html need re-generate
    rm data.land
else 
    echo "use file: data.bd"
fi

if [ ! -f data.land ]; then 
    echo "start generate file: data.land, extract land and time from csv & baidu coordinate"
    sh bd2land.sh data.csv data.bd > data.land
    # final file need re-generate
    rm index.data.html
else 
    echo "use file: data.land"
fi 

if [ ! -f index.data.html ]; then 
    echo "start generate file: index.data.html, the final file"
    sed '/BD_DATA_PLACETAKER/ r data.bd' index.html | sed '/LAND_DATA_PLACETAKER/ r data.land' > index.data.html
else 
    echo "use file: index.data.html"
fi

open index.data.html

輸入 data.csv 文件,依次生成以下文件:

  • data.gps????????? <= data.csv
  • data.bd?????????? <= data.gps
  • data.land???????? <= data.bd & data.csv
  • index.data.html <= index.html & data.bd & data.land

最后打開 index.data.html 展示軌跡動畫。下面是一次完整的生成過程:

> sh start.sh
start generate file: data.gps, extract gps from csv data
start generate file: data.bd, convert gps to baidu coordinate
start generate file: data.land, extract land and time from csv & baidu coordinate
start generate file: index.data.html, the final file

每一步都會判斷目標文件是否已經(jīng)存在,存在則跳過,避免重復(fù)生成;如果目標是新生成的,刪除依賴它的文件以保證下個流程能更新數(shù)據(jù)。

錄屏

mac 自帶的截屏就非常好用:

使用百度地圖路書為騎行視頻添加同步軌跡

默認生成 mov 格式的錄屏文件。其它任何商業(yè)錄屏軟件都可以,例如 Kap,它除了可以生成 gif (本文中的 gif 就是出自它手),還能生成 mp4,壓縮比比 mov 還高。不過目測這個工具也只有 mac 版的,windows 和 linux 用不了。

生成好的軌跡視頻最終要和第一視角的視頻同步,還需要在視頻制作軟件中做對齊,只要找到那么幾個參考點 (e.g. 標志建筑、彎道、交叉路口...),來回調(diào)幾次,基本就差不多啦!視頻編輯軟件眾多,這里就不做推薦了,因為我一般發(fā) B 站,所以用"必剪"多一點,PC 版比較適合我這種視頻比較大的場景。

結(jié)語

本文探索了一種與視頻同步的軌跡展示方案,所有代碼均可以在下面的 github 倉庫找到:

https://github.com/goodpaperman/roadbook

會不定時更新,歡迎關(guān)注以獲取最新 patch 喲~

?文章來源地址http://www.zghlxwxcb.cn/news/detail-602406.html

下面是用這個工具制作的一個樣例:

使用百度地圖路書為騎行視頻添加同步軌跡

(點擊圖片觀看完整視頻)

說了這么多 LuShu 的好處,它有沒有不足的地方呢?有!沒有指南針插件算一個:

使用百度地圖路書為騎行視頻添加同步軌跡

打開百度地圖,在放大縮小按鈕上面,有個改變方向的指南針,可以指定非北方向上。這在制作長直騎行路線時特別有用,可以將南北方向形成的縱向騎行路線改為橫向,更加有利于將導(dǎo)航視頻鋪在騎行視頻底部。希望 LuShu 以后可以支持。

后記

一開始我將 speed 設(shè)置的盡量大——當然不能超過上限 (10W),否則小車壓根不移動——這樣做是出于一種擔憂,考慮一下一個長度 10km 的騎行過程,如果設(shè)置 speed 為 100 (m/s),則整個視頻播下來,浪費在中間動畫的時間將是 10km / 100 = 100s,對于軌跡與視頻同步來說,那是一個相當大的延遲了,視頻播到尾部,軌跡會慢上視頻足足一百秒,這是不可接受的。因此就想著盡量通過提高 speed 值來減少這種誤差,例如設(shè)置 speed 為 10000,累計延遲將減少到 1s。

然而實際運行過程中,發(fā)現(xiàn) speed 變大后,生成的軌跡視頻不僅不延遲了,還比原視頻更快了:視頻還沒播完,軌跡就已經(jīng)到終點了,真是咄咄怪事。當時還不知道 LuShu 有遺漏經(jīng)停點這一說,只能想辦法對比軌跡動畫與 land 文件內(nèi)容,看每次經(jīng)停的標簽和文件中的記錄是否對得上。這種做法非??简炑哿Γ瑢?jīng)停時間也不能準確判斷,例如記錄中是經(jīng)停 10s,動畫是否真的經(jīng)停了 10s 只能判斷個大概,還是存在實際經(jīng)停時間小于文件記錄的可能性,最麻煩的是前后兩次車速一樣的情況下,只根據(jù)標簽判斷就很容易漏掉記錄。

為此,專門制作了一個模擬經(jīng)停過程的小工具,用來 debug 上述問題簡直就是神器,廢話不多說,直接上圖看效果:

使用百度地圖路書為騎行視頻添加同步軌跡

底部是工具輸出,頂部是動圖輸出,兩相比照,看起來非常直觀。下面是調(diào)大速度后遺漏經(jīng)停點的現(xiàn)象:

使用百度地圖路書為騎行視頻添加同步軌跡

具體什么原因,沒看過 LuShu 源碼不得而知,不過這里給一個合理的推斷:LuShu 坐標計算在速度比較大的時候,計算的累計誤差增大,導(dǎo)致坐標相等判斷失效,從而錯過經(jīng)停點。

下面來看下模擬工具的實現(xiàn),其實 land 文件中已經(jīng)提供了經(jīng)停時間和標簽,將它們抽取出來就是工具很好的食材了 (land2wait.sh):

awk -F",|:|}" '{print $8,$6}' "${landfile}"

簡約而不簡單,回顧下 land 文件內(nèi)容:

...
{lng:116.10568842325927,lat:40.11056701573591,html:'26km/h',pauseTime:2},
{lng:116.10579500660829,lat:40.11035775778459,html:'32km/h',pauseTime:3},
{lng:116.10592816947326,lat:40.11013058608767,html:'17km/h',pauseTime:4},
{lng:116.10574200140061,lat:40.11002872275517,html:'0km/h',pauseTime:50},
{lng:116.10498588059896,lat:40.10985140314029,html:'21km/h',pauseTime:20},
{lng:116.104434547854,lat:40.10972328042703,html:'16km/h',pauseTime:10},
{lng:116.10415815632084,lat:40.1096308424909,html:'7km/h',pauseTime:10},
{lng:116.10423031248894,lat:40.109443479731034,html:'15km/h',pauseTime:24},
{lng:116.10441655222886,lat:40.109470198714,html:'18km/h',pauseTime:3},
{lng:116.10469264841298,lat:40.109558635595626,html:'0km/h',pauseTime:57},

同時使用 ',' / ':' / '}' 分割后,標簽位于 $6,經(jīng)停時間位于 $8,將其提取出來就形成了 wait 文件:

...
2 '26km/h'
3 '32km/h'
4 '17km/h'
50 '0km/h'
20 '21km/h'
10 '16km/h'
10 '7km/h'
24 '15km/h'
3 '18km/h'
57 '0km/h'

再用 wait.sh 提取等待時間和標簽,循環(huán) sleep 即可:

while :
do
    read -r line
    if [ $? -ne 0 -a -z "${line}" ]; then
        break;
    fi

    sec=$(echo "${line}" | awk '{print $1}')
    echo "sleep ${line}"
    sleep ${sec}
done < "${waitfile}"

最后是驅(qū)動腳本 simulate.sh:

#! /bin/sh

if [ ! -f data.wait ]; then
    sh land2wait.sh data.land > data.wait
else
    echo "use data.wait"
fi

sh wait.sh data.wait
echo "simulate done!"

這里引入了一個新的依賴:

  • data.wait?????? => data.land

所以在 data.land 發(fā)生變化時,start.sh 也會刪除 data.wait 文件以便下次運行 simulate.sh 可以更新數(shù)據(jù):

...
if [ ! -f data.land ]; then
    echo "start generate file: data.land, extract land and time from csv & baidu coordinate"
    sh bd2land.sh data.csv data.bd > data.land
    # final file need re-generate
    rm index.data.html
    rm data.wait
else
    echo "use file: data.land"
fi
...

參考

[1].?百度地圖顯示車輛運行軌跡(動態(tài)軌跡回放功能)

[2]. 百度地圖開放平臺

[3]. 路書 JavaScript 參考

[4].?linux shell sed 在一個文件中插入另一個文件

[5]. JS文件處理—讀取本地文件(必須通過input控件才能實現(xiàn)) 及 下載文件

[6].?如何在 JavaScript 中讀取 JSON 文件

[7]. 百度地圖 API - 坐標轉(zhuǎn)換服務(wù)

[8]. 百度地圖 JavaScript API v2.0類參考?

[9].?如何用javascript將.txt文件的內(nèi)容作為數(shù)組讀取?

[10].?curl: (3) [globbing] bad range specification in column XXX

[11].?如何批量實現(xiàn)地圖坐標系轉(zhuǎn)換

[12].?Linux shell字符串截取、替換、刪除以及trim

[13].?百度地圖 Web 服務(wù) API

[14]. Shell 時間與時間戳相換(Mac)

[15]. GoPro游記視頻加上地圖導(dǎo)航HUD教程——怎么玩轉(zhuǎn)GPS

[16]. BMapLib.LuShu

[17].?JS定時器:setTimeout和setInterval

[18].?關(guān)于百度地圖坐標轉(zhuǎn)換接口的研究

[19].?百度路書實現(xiàn)軌跡回放(標準)

?

到了這里,關(guān)于使用百度地圖路書為騎行視頻添加同步軌跡的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • vue中使用百度地圖

    3.在頁面使用 4.百度地圖初始化函數(shù)及批量生成自定義圖標點 5.需求1:切換中心點 6.需求2:鼠標滑過自定義圖標改變 需求3:鼠標滑過展示信息窗口

    2024年02月14日
    瀏覽(35)
  • 百度地圖API的使用

    百度地圖API的使用

    這篇文章主要想讓讀者掌握: 百度地圖官網(wǎng) API 百度地圖JavaScript API 當前的位置在網(wǎng)頁中顯示,插入地圖 拖拽 點擊事件。 應(yīng)用場景:網(wǎng)頁插入百度地圖 注意:不關(guān)注定位、距離、公交,這些功能一般結(jié)合移動端GPS實現(xiàn) 第一步:進入官網(wǎng) 百度地圖JavaScript API 直接搜百度地圖

    2024年02月14日
    瀏覽(435)
  • vue 使用百度地圖記錄

    vue 使用百度地圖記錄

    參考文檔 https://lbsyun.baidu.com/index.php?title=jspopular3.0/guide/infowindow https://lbsyun.baidu.com/cms/jsapi/reference/jsapi_reference_3_0.html#a0b0 參考鏈接:https://api.map.baidu.com/library/MarkerClusterer/1.2/docs/symbols/BMapLib.MarkerClusterer.html 下載這個js

    2024年02月13日
    瀏覽(19)
  • 【QT--使用百度地圖API顯示地圖并繪制路線】

    【QT--使用百度地圖API顯示地圖并繪制路線】

    先吐槽一下下,本身qt學(xué)的就不咋滴,誰想到第一件事就是讓寫一個上位機工具,根據(jù)CAN總線傳來的位置信息,在地圖上去繪制路線,并獲取當前路段的限速信息等。當聽到這個需求的時候,第一時間是有點懵逼的。自己原本是沒接觸過這方面的知識,而且qt學(xué)的也特別的垃圾

    2024年01月24日
    瀏覽(96)
  • 在小程序中使用百度地圖

    在小程序中使用百度地圖

    進入百度開放平臺官網(wǎng),點擊右上角“API控制臺”,注冊成為百度地圖開發(fā)者。 進入控制臺,創(chuàng)建一個新應(yīng)用。填寫相應(yīng)信息時,應(yīng)用類型選擇【微信小程序】,APPID填寫小程序開發(fā)者ID。 點擊提交后,即可在查看應(yīng)用頁面看到申請成功的密鑰(AK)。 在項目根目錄下新建一

    2023年04月09日
    瀏覽(23)
  • 乾坤框架中子系統(tǒng)使用百度地圖三維地圖無法顯示的問題

    乾坤框架子系統(tǒng)調(diào)用百度地圖,使用vue-baidu-map組件只有衛(wèi)星和普通模式,沒法實現(xiàn)三維地圖,所以只能改為原始的加載百度地圖的api,這里最好使用懶加載方式,創(chuàng)建一個BMPGL.js。 頁面引用import { BMPGL } from \\\"@/api/map/bmapGL.js\\\"; 方法調(diào)用 如此在子應(yīng)用中就能夠正常顯示百度三維

    2024年02月10日
    瀏覽(82)
  • 百度地圖API的使用(附案例)

    百度地圖API的使用(附案例)

    百度地圖JavaScript API是一套由JavaScript語言編寫的應(yīng)用程序接口,可幫助您在網(wǎng)站中構(gòu)建功能豐富、交互性強的地圖應(yīng)用,支持PC端和移動端基于瀏覽器的地圖應(yīng)用開發(fā),且支持HTML5特性的地圖開發(fā)。 在控制臺里選擇創(chuàng)建應(yīng)用 選擇瀏覽器端,白名單輸入* 我們直接把文檔內(nèi)的代碼

    2024年02月06日
    瀏覽(141)
  • vue項目中使用百度地圖(一)

    vue+百度地圖的基礎(chǔ)使用。 首先,第一步申請key,保存好這個密鑰。 鏈接:jspopular | 百度地圖API SDK (baidu.com) 使用百度地圖有兩種方式:1.javaScript API? ? 2.直接引用組件。 以2.0版本為例。 方法1:百度地圖javaScript API 引入方式有兩種。 方法1:index.html中引用 在想要展示地圖的

    2024年02月12日
    瀏覽(26)
  • vue3 中使用百度地圖

    vue3 中使用百度地圖

    最近一個項目要用到地圖,因為微信小程序用的也是百度地圖,所以想著網(wǎng)頁端也用百度地圖,在網(wǎng)上查了很多方法,包括引入百度地圖第三方庫,還是有問題,發(fā)現(xiàn)最簡單的方法就是在index.html中引入script,然后直接在相關(guān)頁面肝就完事。 在百度開發(fā)者平臺上面申請,其他

    2023年04月17日
    瀏覽(22)
  • vue3使用百度地圖(詳)

    vue3使用百度地圖(詳)

    提示:該博客vue采用vue3,使用百度地圖通過組件 vue-baidu-map-3x : 組件官網(wǎng):https://map.heifahaizei.com/doc/baidu-map.html 下面會從頭開始介紹如何使用百度地圖以及常用組件功能(附帶遇到的問題和解決方案) 步驟:1. 進入百度地圖開放平臺 | 百度地圖API SDK | 地圖開發(fā)?2.打開頂部控制

    2024年02月06日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包