GoogleのStreetViewを動画にするHyperlapseを使ってみる


過去記事(2013/11/12)のリニューアル版です


GoogleのStreetViewはとっても便利ですが、あの矢印マークをいちいちクリックするのが面倒です。

で、Hyperlapseです。

これはStreetViewの地点間のパノラマ画像を自動で取得して動画として再生してくれます。

Time Lapseという動画の手法を使っています。

例えば、映画なんかで風景の移動を高速で見せているというやつです。

こんな感じ。

Hyperlapseは2013年にリリースされたオープンソースのプロジェクトなのでGitHubからDLしてコードをいじることができます(MIT License)。

現在開発は停止していますが、ソースコードはGitHubに残っていますし、クオリティは2017年現在でも十分高いです。

Hyperlapse(GitHub)

*
同じHyperlapseという名前でInstagramのチームがiOS向けのアプリを出してます。
これはカメラ画像をタイムラプスにするアプリ。ここで紹介するHyperlapseはTeehan+Lax が作ったもの。
両者は….たぶん無関係……だと思われます。

参照するコードはexamplesフォルダーに入っています。

ただ、あまりに距離が離れた地点間は端折られますし、長距離だとアニメーション化という作業に時間がかかります。

また画像は最短経路を元に取るようですので、思ったような道順にならないかもしれません。

Hyperlapseのドキュメント
Hyperlapse.js
Hyperlapse
HyperlapsePoint

試しに、大阪の万博記念競技場の公園東口からEゲートの方面へ向かう経路でやってみます。

経路の移動をGoogle Mapsで追跡してみます。

Maps上のマーカー移動のやり方は、examplesのコードを少し変えてみました。

こっちの方が簡単かもしれません。

Hyperlapse:公園東口からEゲートの方面へ向かう(万博記念競技場)

動画再生中はステータスに座標が表示されます。

それに伴って右のMapsのアイコンも移動。

「Pause」ボタンで一時停止。

「Next」ボタンで1フレームごとに移動。

「Prev」ボタンで1フレームごとに戻ります。

「image」ボタンで現在表示している部分のパノラマ画像を表示。
画像はCanvas要素として取り出せます。
こんな感じ。

pegmanをカメラアイコンの辺りにドラッグするとStreetViewの経路が青く出ます。 適当な辺りにドロップすれば、MapsはStreetViewに変わります。

Mapsに戻る場合は、右上のバッテンをクリック。


基本コードはexamplesのsimple.htmlをベースにしています。

StreetViewの存在する場所の2点を始点・終点に指定する。
StreetViewの存在の有無は、Mapsなどのペグマン(黄色い人型アイコン)をクリックしたまま、ちょっとMap上に出すと表示されます。

変更点は以下の部分。

Google Mapsを同時表示。

var hyperlapseをinitの外に出しています(外部でhyperlapseを制御するため)。
var map, geocoderを追加(geocoderは未使用)。

onFrameでgetCurrentPointを使って、位置情報を抽出。

動画の制御

Play:hyperlapse.play()
Pause:hyperlapse.pause()
Prev:hyperlapse.prev()
Next:hyperlapse.next()

【JavaScriptの抜粋】

function init() {
    init_pano();
    init_map();
}


function init_pano() {
    
    hyperlapse = new Hyperlapse(document.getElementById('pano'), {
        lookat: new google.maps.LatLng(34.81046439863342,135.54278864373018),
        zoom: 1,
        use_lookat: true,
        elevation: 50
    });

    hyperlapse.onError = function(e) {
        document.getElementById("stat").value = "error";
        console.log(e);
    };

    hyperlapse.onRouteComplete = function(e) {
        document.getElementById("stat").value = "route complete:もうすぐですよぉ";
        hyperlapse.load();
    };

    hyperlapse.onLoadComplete = function(e) {
        document.getElementById("stat").value = "load complete:準備できました";
    };
    
    hyperlapse.onFrame = function(e) {
        var ido = hyperlapse.getCurrentPoint().location.lat();
        var keido = hyperlapse.getCurrentPoint().location.lng();
        document.getElementById("stat").value = ido + "," + keido;
        
        camera_icon.setPosition(new google.maps.LatLng(ido,keido));
    };
    
    // Google Maps API stuff here...
    var directions_service = new google.maps.DirectionsService();

    var route = {
        request:{
            origin: new google.maps.LatLng(34.8109665019401,135.54000451077272,37),
            destination: new google.maps.LatLng(34.81131885331175,135.54204298962404),
            travelMode: google.maps.DirectionsTravelMode.DRIVING
        }
    };

    directions_service.route(route.request, function(response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            document.getElementById("stat").value = "direction status:ただいま準備中";
            hyperlapse.generate( {route:response} );
        } else {
            
            document.getElementById("stat").value = status;
        }
    });

}

function init_map() {
    var mapOpt = { 
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        center: new google.maps.LatLng(34.8109665019401,135.54000451077272),
        zoom: 17
    };
    
    map = new google.maps.Map(document.getElementById("map"), mapOpt);
    geocoder = new google.maps.Geocoder();
    
    
    camera_icon = new google.maps.Marker({
        position: new google.maps.LatLng(34.8109665019401,135.54000451077272),
        icon:'img/camera.png',
        map: map
    });
    
}

 

 

 

 

 

 

Be the first to comment

Leave a Reply

Your email address will not be published.


*