ある元栃木の工業人.jp

電子工作、機械設計、ロボットなどのモノづくりから宇都宮まで色々 ※2021:画像消失につき、c.yimgからマイニング&整備中

カスタムストリートビューの作成方法 - Google Maps Api Custom Street View

<2020追記>

この記事は古いので、あまり参考にしないでください。
APIキーあたりの仕様が変わっています。


ある程度のWebサイトの知識があれば作れるレベルで解説します。
また、このページのHTMLやJavascriptをコピペし、解説通り画像を用意すると作れるようになってます。


カスタムストリートビューGoogle Maps Api内のストリートビューの表示機能を自由にカスタマイズして利用でき、自分で撮影したパノラマ画像の表示や、複数のパノラマ画像を使えば自作ストリートビューも作成する事が出来ます。例として私が作成したものがこいつです。

UK School View.beta

最低限の機能を載せたプログラムを例として、HTML→Javascript→画像→フォルダ構成 の順で必要な部分だけ解説していきます。また、最後に今回の例を丸ごとZIPとして載せますので参考にしてください。



HTML


まずHTML。
Google Maps Apiを実現させるためにGoogleが提供した外部ファイルや、カスタムストリートビューに関する外部ファイルの読み込み設定のほか、ストリートビューの表示範囲となるDIVコンテナを設定します。

<html>
  <head>
    <script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false" type="text/javascript"></script>
    <script src="js_gsv.js" type="text/javascript"></script>
    <title>タイトル</title>
    <style type="text/css"> 
        <!--
        body { 
            height: 100%;
        }
        #streetview_canvas {
            margin: 0 auto;
            width: 900px;
            height: 500px;
        }
        -->
    </style> 
  </head>
  <body>
    <div id="streetview_canvas"></div>
  </body>
</html>

 

<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false" type="text/javascript"></script>
<script src="js_gsv.js" type="text/javascript"></script>

一行目はGoogle Maps Apiを機能させるのに必要な一文です。googleが用意した外部のJavascriptファイルを読み込みます。
二行目は、後述するカスタムストリートビューに関連するJavascriptファイルです。js_gsv.js というのはそのファイルの名前になります。タイトルにはこのページの題名を書きます。検索結果に表示されるタイトルですね。

width: 900px;
height: 500px;

ストリートビューを表示させる領域の大きさを指定します。

<div id="streetview_canvas"></div>

ストリートビューを表示させる領域のDIVコンテナです。
streetview_canvasというのは後述するJavascript内で指定するものです。



Javascript


つぎにjavascript。上のHTMLをコピペして使用する場合、こちらを「js_gsv.js」で保存してください。
このプログラムの概要として、初期表示のパノラマ画像と視点およびコントロールバーなどの表示の設定と、視野に従って、いくつかのブロックに分割されたパノラマ画像を逐次読み込むシステムの設定になります。またこのとき、複数のパノラマ画像でストリートビューを構築する場合は、周辺へのリンクを表示する設定や、パノラマ画像などの情報に関するデータベースも設定します。

var streetView;

function initialize() {
  //ストリートビューの全体的な設定
  var streetViewOptions = {
    pov: { heading: 0,pitch: 0,zoom: 1 },        //初期表示の方角:仰角:視野(ズーム)
    pano : "pano_01",                            //初期表示するのパノラマ画像のパノラマID
    panControl : false,
    panoProvider : getCustomPanorama
  };
  //ストリートビューを表示するHTML内のDIVコンテナを設定
  var streetViewDiv = document.getElementById("streetview_canvas");

  streetView = new google.maps.StreetViewPanorama(streetViewDiv, streetViewOptions); //ここ根幹
  //リンクの登録
  google.maps.event.addListener(streetView, "links_changed", createCustomLink);
}

function getCustomPanoramaTileUrl(panoID, zoom, tileX, tileY) {                //タイル画像読み込み
  return 'pano_images/' + panoID + '/' + panoID + '_' + tileX + '_' + tileY + '.jpg';
}

function getCustomPanorama(panoID) {
  //基本パノラマデータ定義
  var streetViewPanoramaData = {
    links: ,
    copyright: "(C) 2013 Created by hogehoge",        //著作者表示
    tiles: {
        tileSize: new google.maps.Size(512, 512),         //各タイルサイズ
        worldSize: new google.maps.Size(4096, 2048),     //全面サイズ(タイルサイズとイコールで一枚表示
        centerHeading: 0,                //初期方角
        getTileUrl: getCustomPanoramaTileUrl
    }
  }

  //各パノラマデータ登録
  switch(panoID) {
    case "pano_01":
    streetViewPanoramaData["location"] = {
        pano: "pano_01",                                                      //パノラマID
        description: "西パノラマ",                                           //パノラマ表示名
        latLng: new google.maps.LatLng(36.552575, 139.870435)     //パノラマの座標
    };

    break;
    case "pano_02":
    streetViewPanoramaData["location"] = {
        pano: "pano_02",
        description: "中央パノラマ",
        latLng: new google.maps.LatLng(36.552325, 139.870465)
    };

    break;
    case "pano_03":
    streetViewPanoramaData["location"] = {
        pano: "pano_03",
        description: "北パノラマ",
        latLng: new google.maps.LatLng(36.551927, 139.870502)
    };

    break;
  }

  return streetViewPanoramaData;
}

function createCustomLink() {
  var links = streetView.getLinks();         //現在のリンクの取得
  var panoID = streetView.getPano();        //現在のパノラマID取得

  switch(panoID) {
    case "pano_01": //pano_01のときに表示するリンク
    links.push({                    //links.push()は複数設置可
        description : "中央",    //リンク表示名
        pano : "pano_02",        //リンク先パノラマID
        heading : 90,              //リンク方角
    });

    break;
    case "pano_02":
    links.push({
        description : "西",
        pano : "pano_01",
        heading : 270,
    });
    links.push({
        description : "",
        pano : "pano_03",
        heading : 0,
    });

    break;
    case "pano_03":
    links.push({
        description : "中央",
        pano : "pano_02",
        heading : 180,
    });

    break;
  }
}

google.maps.event.addDomListener(window, 'load', initialize); //initializeを一度のみ実行

 

  var streetViewOptions = {
    pov: { heading: 0,pitch: 0,zoom: 1 },        //初期の方角:仰角:視野
    pano : "pano_01",                            //初期のパノラマID
    panControl : true,                            //パノラマ操作のコントローラ表示するか
    panoProvider : getCustomPanorama
  };

pov:で初期表示の視野と方向を設定します。heading:は北を0として時計回りに359まで方角を設定できます。pitch:は水平を0として、真上へ90、真下へ-90の範囲で設定できます。zoom:はそのまま拡大ですが、使い難いので1が基本で良いかと。
pano : "pano_01"はページを開いて最初に表示するパノラマ画像を設定します。pano_01は表示するパノラマ画像の名前で、一般にpanoIDと呼びます。このプログラムでは、panoIDがそのままパノラマ画像のファイル名(panoID.jpg)となります。
panControl :はパノラマ操作に使うコントロールの表示の有無を決めます。trueで表示、falseで非表示。
panoProvider : getCustomPanoramaはパノラマ画像の画像データや情報を呼び出すものです。

var streetViewDiv = document.getElementById("streetview_canvas");

HTMLのDIVコンテナを指定します。ここではstreetview_canvasというidをもつDIVコンテナを指定してます。

google.maps.event.addListener(streetView, "links_changed", createCustomLink);

複数のパノラマ画像で自作ストリートビューとする場合に必要な一文です。streetView内で"links_changed"というイベントが発生したらcreateCustomLinkという関数を実行する、というような意味になります。links_changedはリンクの変更、つまりパノラマ画像を切り替えた時に相当し、createCustomLink関数は、切り替えた先のパノラマ画像のpanoIDをもとに、その周辺のパノラマ画像へのリンクを探して表示するものです。

'pano_images/' + panoID + '/' + panoID + '_' + tileX + '_' + tileY + '.jpg';

ここで読み込む画像のアドレスを設定します。「panoID」は表示しようとするパノラマ画像名、「tileX」が左から何番目か、「tileY」が上から何番目かを意味します。この三つのパラメータは、ユーザの操作に応じて自動的に指定されます。なお、panoIDがパノラマ画像のファイル名というのはここでそのように設定されているからです。例えば「pano_01」というpanoIDを持つパノラマを表示させるとき、上のプログラムは下記のようにパノラマ画像のアドレスを指定します。

pano_images/pano_01/pano_01_0_0.jpg

このように、pano_imagesというフォルダ内のpano_01というフォルダ内にある「pano_01_0_0.jpg」というブロック画像が指定されることになります。

 

  var streetViewPanoramaData = {
    links: ,
    copyright: "(C) 2013 Created by hogehoge",        //著作者表示
    tiles: {
        tileSize: new google.maps.Size(512, 512),         //各タイルサイズ
        worldSize: new google.maps.Size(4096, 2048),   //全面サイズ(タイルサイズとイコールで一枚表示
        centerHeading: 0,                                      //初期方角
        getTileUrl: getCustomPanoramaTileUrl
    }
  }

copyright:はパノラマ画像の表示の際に、右下で著作者として表示されるものです。HTMLのタグも使えるので、うまく利用すればいろいろ使えます。
tileSizeとworldSizeは画像の大きさを設定します。

例えばworldSizeが(4096, 2048)で、tileSizeが(512, 512)であれば、横方向に8つ、縦方向に4つのブロックとして表示されます。左上から順に表示するので、割り切れない数値に設定すると、当然ですが南方向もしくは真下の画像の辻褄が合わなくなります。
centerHeading: とは、パノラマ画像の位置をズラします。補正機能のようなもので、用意したパノラマ画像の中央が北を向いている場合、これは0にして構いません。もしパノラマ画像の中央が東を向く場合、これを90にすればパノラマ画像が右方向に90度移動して表示されます。これは視点を設定するheading:の方角パラメータとは異なり、パノラマ画像を移動させるだけということに注意してください。
getTileUrl: getCustomPanoramaTileUrlは、分割されたブロック画像を呼び出すものです。

switch(panoID) {
    case "pano_01":
    streetViewPanoramaData["location"] = {
        pano: "pano_01",                                                      //パノラマID
        description: "西パノラマ",                                           //パノラマ表示名
        latLng: new google.maps.LatLng(36.552575, 139.870435)     //パノラマの座標
    };

    break;
    - - - - - - - -

パノラマ画像のpanoIDが初期設定やリンクを押して選択されたとき、このswitch case文が実行され、選択されたpanoIDに関する設定を読み込みます。pano:はこのパノラマ画像のpanoID、description:はこのパノラマ画像の名称、例えば駅前のパノラマ画像の名称を「駅前」とすれば、そのパノラマ画像が表示された際、左上に「駅前周辺」と表示されます。latLng:はパノラマが撮影された座標です。
用意したパノラマ画像の数だけ、このcase文を用意してそれぞれ設定してあげます。

  switch(panoID) {
    case "pano_01": //pano_01のときに表示するリンク
    links.push({                    //links.push()は複数設置可
        description : " ",         //リンク表示名
        pano : "pano_02",        //リンク先パノラマID
        heading : 90,              //リンク方角
    });
    break;

パノラマ画像のpanoIDがリンクを押して選択されたとき、このswitch case文が実行され、選択されたpanoIDに表示されるリンクの設定を読み込みます。links.push()がひとつのリンクに対応しており、複数のリンク(例えば交差点のパノラマのときなど)が必要な際はこのlonks.push()を複数用意してもよいです。description:はリンクに表示する名称です。リンクを押した先のパノラマ画像の名称を書いたりします。pano :はリンクを押した先のパノラマ画像のpanoIDを設定します。間違えると異なるパノラマ画像に飛んでしまうので注意です。heading:は視点と同じく北を0として時計回りに359度の方角を設定でき、リンクの矢印方向を設定します。
用意したパノラマ画像でリンクを用いる画像の数だけ、このcase文を用意し、case内ではそのパノラマ画像で表示するリンクの数だけlinks.push()をそれぞれ設定します。

google.maps.event.addDomListener(window, 'load', initialize);

これを必ずプログラムの最後に置きます。
すべて読み込んだらプログラム(initialize関数)を実行するという意味です。



パノラマ画像


次にパノラマ画像について。
パノラマ画像を用意します。パノラマ画像の作り方は以下を参照してください。

縦横無尽にパノラマ写真を作成 hugin - ITpro

単純な画像の合成であればMicrosoft ICEが操作が簡単なのでオススメですが、Microsoft ICEは複雑な画像の合成に関しては手動による補正も行えないので苦手です。なのでhuginというソフトがオススメです。
パノラマ画像は横4096px、縦2048pxにする事を薦めます。後述する分割ソフトでリサイズも可能です。

このパノラマ画像を分割しないでも、js.gsv.jsのtileSizeの設定によっては表示することが出来ますが、ネット上のサーバで公開した際にはデータ受信速度がローカルより圧倒的に遅いため、一枚表示するのに20秒くらい掛かることがあります。そこで、いくつかに分割することで圧倒的な高速表示ができるため、ネット上で公開する予定であれば分割する事をオススメします。

しかし分割するにしても一枚だけならまだペイントソフトで加工すれば良いですが、ストリートビューのように複数、または多量のパノラマ画像の処理の場合は手作業では絶望的なほど時間が掛かってしまいます。そこでprocessingを用いた自動分割ソフトを作成しました。下のURLからダウンロードし、ZIPを解凍してください。説明はreadme.txtを読んでもらうとしてここでは省く事にします。

GSVcutter - Skydrive

このソフトではパノラマ画像ごとに自動的にフォルダが作成され、ここに分割したブロック画像が規則どおりの名前で収納されます。このフォルダを後述するフォルダ構成でそのまま用います。

例:
     パノラマ画像「pano.jpg」

               ↓分割ソフト GSVcutter

    「pano」フォルダ生成、フォルダ内に「pano_0_0.jpg」~「pano_7_3.jpg」生成



フォルダ構成


最後にフォルダ構成について。
これまでパノラマ画像のブロックや、HTML、Javascriptを解説しましたが、これらは場所を間違えると正しく機能しません。ので、ここでしっかり見ておきましょう。

例えばCustomStreetViewというフォルダに、HTMLとJavascript、パノラマ画像を全てまとめた場合とします。
このとき、パノラマ画像3つ(pano_01.jpg、pano_02.jpg、pano_03.jpg)を用意し、それぞれ分割したとします。

-CustomStreetView(フォルダ)
                 |--pano_images(フォルダ)
                 |             |--pano_01(フォルダ)
                 |             |          |--pano_01_0_0.jpg(ブロック画像)
                 |             |          |--pano_01_0_1.jpg
                 |             |          |--pano_01_0_2.jpg
                 |             |          |--pano_01_0_3.jpg
                 |             |          |--pano_01_1_1.jpg
                 |             |          |--pano_01_1_2.jpg
                 |             |          |--     /略/    .jpg
                 |             |
                 |             |--pano_02(フォルダ)
                 |             |          |--pano_02_0_0.jpg
                 |             |          |--pano_02_0_1.jpg
                 |             |          |--     /略/    .jpg
                 |             |
                 |             |--pano_03(フォルダ)
         |            |--pano_03_0_0.jpg
         |            |--pano_03_0_1.jpg
                 |                        |--     /略/    .jpg
                 |
                 |--index.html
                 |--js_gsv.js



例のZIP


これで、単純なストリートビューを作ることが出来る筈です。
とはいえ、やっぱり間違えてしまう人は少なからず居ますので、今回用いた例を、丸ごとZIPにして配ります。

CustomStreetView - Skydrive

このZIPファイル内のプログラムはフリーとしますが、画像の著作権および著作者人格権は全てkazu.に帰属します。あくまで例から学ぶタイプの方へ向けて学習用に渡すだけであって、公開する場合は画像を流用する事の無い様、己の良心とモラルに従って常識の範囲内で使ってください。


 - kazu.