Pythonで画像に緯度経度情報（ジオタグ）を追加してみた

## 目次
[0.結論](#0-結論)
[1.はじめに](#1-はじめに)
[2.前準備](#2-前準備)
[3.画像へのジオタグの追加](#3-画像へのジオタグの追加)
[4.おわりに](#4-おわりに)

### 0. 結論
Pythonを用い、３６０度画像に緯度経度情報（ジオタグ）の追加が可能。

▼作成したスクリプト
[Add_Geotag_to_Image_From_Address_For_ Qiita.ipynb](https://colab.research.google.com/drive/1tNLittx1ZjNZCBHbWGr9hj8L98o-_0_Z?usp=sharing)

▼作成されるジオタグ追加画像
住所：香川県高松市常磐町１丁目３－１
ジオタグ：緯度: 34° 20’ 19.278” N
　　　　　経度: 134° 3’ 9.184” E
![香川県高松市常磐町１丁目３－１.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764845/6b3d2d56-fab4-f6fd-524c-2a59d2a1bea2.jpeg)


### 1. はじめに
撮影した画像をGoogleMAPへスムーズにアップロードしたいと思っています。
そのため、前段階として画像（今回は360度画像）にジオタグを追加してみます。

▼参考サイト
[Pythonで場所名や住所から緯度経度を求める方法](https://chantastu.hatenablog.com/entry/2023/04/22/230203)
[piexif を使って画像にジオタグを追加する方法](https://www.gis-py.com/entry/py-geotag)

なお開発環境ですが**Google Colaboratory**を利用しています。

▼参考サイト
[【Google Colab】GPUが無料で使える!? 基本的な使い方](https://sci-by-py.com/hpc/google-colab/)

### 2. 前準備
ここでは、前準備としてGoogleドライブのマウントとテストする画像のDLについて記載しております。

今回は画像の名前に住所を登録し、その住所の緯度経度情報をジオタグとして画像に追加します。

```Python:
#Googleドライブのマウント（画像を自分で準備するときはGoogleドライブ使うとよい）
from google.colab import drive
drive.mount('/content/drive')
```

```Python:
#テストする画像のダウンロード
!wget https://www.megasoft.co.jp/3dofficepro10/img/panorama/01.jpg
!wget https://www.megasoft.co.jp/3dofficepro10/img/panorama/02.jpg

#画像の名前を住所にする
import os
test_address1 = '香川県高松市浜ノ町１−２０'#高松駅
os.rename('01.jpg', test_address1 + '.jpg')
test_address2 = '香川県高松市常磐町１丁目３－１'#瓦町駅
os.rename('02.jpg', test_address2 + '.jpg')
```

### 3. 画像へのジオタグの追加
ここでは、作成したスクリプトのメインの部分となる画像へのジオタグの追加処理について紹介していきたいと思います。

まずはジオタグ処理用のライブラリである**piexif**をインストールします。

```Python:
#ジオタグ書き込み用
!pip install piexif
from fractions import Fraction
import piexif
from PIL import Image
```

その他必要なライブラリをインストールします。
```Python:
import requests
import urllib
import os
import glob
```
以下にて取得した緯度経度を10進数から60進数に変換する関数の定義を行なっています。

なお緯度経度の10進数、60進数表記については以下のサイトを確認してみてください。

▼参考サイト
[緯度経度の表記方法とは？10進法と60進法の違いや変換方法について解説](https://gisaca.net/decimal-and-sexagesimal-systems/)


```Python:
#緯度、経度を10進法→60進法(度分秒)に変換
def to_deg(value, loc):
    if value < 0:
        loc_value = loc[0]
    elif value > 0:
        loc_value = loc[1]
    else:
        loc_value = ''
    abs_value = abs(value)
    deg =  int(abs_value)
    t1 = (abs_value-deg)*60
    min = int(t1)
    sec = round((t1 - min)* 60, 5)
    return (deg, min, sec, loc_value)
```

以下にて60進数に変換した緯度経度を有理数に変換する関数の定義を行なっています。
```Python:
#有理数に変換
def change_to_rational(number):
    f = Fraction(str(number))
    return (f.numerator, f.denominator)
```

以下にてジオタグを追加した画像を保存する関数の定義を行なっています。
```Python:
#ジオタグを貼り付けた画像を作成
def create_picture_geotag(exif_bytes):
    im = Image.open(name)
    im.save(name, exif = exif_bytes)
```

以下にて上記３つの関数の実行を行う関数の定義を行なっています。
```Python:
#ジオタグに追加する情報を作成
def atattch_geotag(file_name, lat, lng):
    lat_deg = to_deg(lat, ['S', 'N'])
    lng_deg = to_deg(lng, ['W', 'E'])

    # 緯度、経度を10進法→60進法(度分秒)に変換
    exiv_lat = (change_to_rational(lat_deg[0]), change_to_rational(lat_deg[1]), change_to_rational(lat_deg[2]))
    exiv_lng = (change_to_rational(lng_deg[0]), change_to_rational(lng_deg[1]), change_to_rational(lng_deg[2]))

    gps_ifd = {
        piexif.GPSIFD.GPSVersionID: (2, 0, 0, 0),
        piexif.GPSIFD.GPSLatitudeRef: lat_deg[3],
        piexif.GPSIFD.GPSLatitude: exiv_lat,
        piexif.GPSIFD.GPSLongitudeRef: lng_deg[3],
        piexif.GPSIFD.GPSLongitude: exiv_lng,
    }

    exif_dict = {'GPS': gps_ifd}
    exif_bytes = piexif.dump(exif_dict)

    # ジオタグ付きの画像を作成
    create_picture_geotag(exif_bytes)
```

以下にて国土地理院のAPI利用した住所から緯度経度情報を入手する関数の定義を行なっています。
```Python:
#住所から緯度経度情報を入手（国土地理院のAPI利用）
def get_gis_info(address, gis):
  makeUrl = 'https://msearch.gsi.go.jp/address-search/AddressSearch?q='
  s_quote = urllib.parse.quote(address)
  response = requests.get(makeUrl + s_quote)
  gis.append(response.json()[0]['geometry']['coordinates'])
  return gis
```

以下にて作成した関数を実行し、画像にジオタグを追加しています。
```Python:
address_name = []
address_name_jpg = []
for name in glob.glob('*県*.jpg'):
  address_name.append(name.replace('.jpg', ''))
  address_name_jpg.append(name)

gis = []
for address in address_name:
  gis = get_gis_info(address, gis)

for name, test in zip(address_name_jpg, gis):
  atattch_geotag(name, test[1],test[0])
```

### 4. おわりに
画像にジオタグを追加するスクリプトを作成しました。

これ以降の処理としては、GoogleMAPのAPIを利用することで、ジオタグを追加した画像を自動でGoogleMAPへのアップロードできると思っています。

ぜひ、本スクリプトを活用してみてください！

長い文章を最後までお読みいただき、ありがとうございました！！