概要
写真のExif情報から位置情報を取得できることを知ったので
その応用ということで、現在地から取得した位置情報へのルートをDirections APIで取得してみようと思いました。
ついでに、Exif情報から逆ジオコーディングを行って地理情報を同時に表示させます。
素人にも扱えるなんて、Googleさんは素晴らしいですなぁ。。
Exif情報についてはwikiを参照してください。
以下、引用文。
カメラの機種や撮影時の条件情報を画像に埋め込んでいて、ビューワやフォトレタッチソフトなどで参照、応用することができる。
逆ジオコーディングについては以下を参照してください。
以下、引用文。
経度緯度から住所を取得する方法を「リバースジオコーディング」や「逆ジオコーディング」と言います。
完成系
ただローカルで動かす程度なので、フロントには全くこだわっていません。
簡単に説明しますと、以下の処理を組んでいます。
①ホームディレクトリ/
から写真を/upload
にアップロード(POST)
②flaskのルーティングメソッドで写真のオブジェクトを取得
③写真のExif情報からgps情報(緯度・経度)を取得
④取得した緯度・経度から逆ジオコーディングによって地理情報を取得
⑤gps情報・地理情報を地図表示ページに渡す
⑥地図表示ページでgooglemapを展開し、現在地と写真の撮影地とをルートマップとして表示する。またマップの上部に写真の地理情報を箇条書きで表示する。
スクショで表すとこうなります。(位置情報や地図情報は念のため隠しました。(;^ω^))
A...現在地 B...目的地
です。
工夫したこと・勉強になったこと
①地図の中心位置は、両者の中間地点にした!
google maps apiに渡すパラメータのうち、center(いわゆる地図の中心位置となるgps情報)を渡す必要があるが、単に現在地と写真の位置を足して2で割った値を中心にすると綺麗に地図が表示されるようになった。
function successRoute(position) {
var latitude = position.coords.latitude;//緯度
var longitude = position.coords.longitude;//経度
// 位置情報(現在地)
var latlng_local = new google.maps.LatLng( latitude , longitude ) ;
// 位置情報(写真)
var latlng_photo = new google.maps.LatLng( photo_data[0] , photo_data[1] ) ;
// mapの中心
center_lat = (latitude + photo_data[0]) / 2
center_lng = (longitude + photo_data[1]) / 2
const center = {lat: center_lat, lng: center_lng };
const options = {zoom: 7, scaleControl: true, center: center};
②Pyモジュールからjavascriptに変数を渡す工夫
こちらの記事を参考にしました。
順序通り説明すると、以下の流れになります。
①app.pyモジュール側にて、渡したい変数(今回はgps情報と地理情報)をリストに格納する。(地理情報はString型で受け取るのでリストに入れ直す必要がある。)
②最終的に変数を渡したいRoute.jsを司っている、map.htmlファイルにリスト化した変数を渡す。
③map.htmlの<script>
タグ内で、jinja2受け取った変数をjsonにエンコードしたものとして再定義する。
④再定義した<script>
タグの下に<script>
タグを用意し、Route.jsをソースとして定義する。
この流れを組むと、無事js内で変数が使えるようになりました。
以下に、コードの一部を掲載しておきます。
# コードは一部を抜粋
input_data = []
photo_info = []
@app.route('/upload', methods=['POST'])
def upload():
# Exifからgps情報を取得する(image_pathはアップロードした写真のパス)
# exif_gps.pyのget_gps関数による処理で緯度経度を取得
photo_lat, photo_lng = exif_gps.get_gps(image_path)
# gps情報をリストに格納
input_data = [photo_lat, photo_lng]
# 逆ジオコーディング処理で地理情報を取得する
photo_info_tmp = exif_gps.revgeo(photo_lat, photo_lng)
# photo_info_tmpはカンマを含む文字列(String)なので
# photo_info_tmpに含まれた文字数分インクリメントしながら
# カンマ以外の文字列をリストに格納する(ココ重要)
num = 0
note = ""
for i in photo_info_tmp:
if i != ',':
note += i
continue
else:
photo_info.insert(num, note)
num += 1
note = ""
# map.htmlに変数を渡す
return render_template('map.html', data=input_data, info=photo_info)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>位置情報取得サンプル</title>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=XXX:bow:X"></script>
<script type="text/javascript">
// 変数を渡す
var photo_data= {{ data | tojson }}
var map;
</script>
<script src="{{ url_for('static', filename='js/Route.js') }}"></script>
</head>
参考にさせて頂いたサイト
◆google maps 導入手順
http://toa.in.net/googlemap/
◆参考書籍
https://www.socym.co.jp/book/1251
◆Exifから緯度経度の取得に対するエラー
https://stackoverflow.com/questions/64405326/django-exif-data-ifdrational-object-is-not-subscriptable
◆Directions Service 導入手順
http://www.googleappsscript.info/2018-03-21/map_route_guidance.html
◆Exifの取得
https://geocoder.readthedocs.io/providers/OpenStreetMap.html