LoginSignup
6
5

More than 3 years have passed since last update.

【Python】写真の位置情報のタグ(JPGファイルのGPS Exif)の読み書き

Last updated at Posted at 2020-08-08

はじめに

これも自分用のメモです。python を使うと楽にできます。注意点として、

  • 緯度経度は度分秒なので60進数
  • 値は実数ではなく、分数で。(有理数、というのかな)

いくつか関係するライブラリがあります。どれか一つに統一したほうがよいのですが、とりあえず動いたものメモです。(おい)

仕様書?

下記の文献を見つけました。

これによるとGPS Info IFDは以下のように定義されているようです。

image.png

たくさんありますが、私が扱ったファイルでは0 - 6 までのタグのみでした。GPSの緯度、経度、高さが読み書きできたので、とりあえずは十分でした。ここでGPSLatitudeRefは一文字の'N'か'S'で北緯、南緯を表します。GPSLatitudeは分数で表します。

python で読み書きする

Pillow で緯度経度を読む

Pillow を使用しました。準備で苦労したかは覚えていません。

pip3 install pillow

下記で緯度経度を読めました。

read_gpsexif.py
from PIL import Image
infile = "test.JPG"
img = Image.open( infile )
exif = img._getexif()
for k, v in exif.items():
    if k==34853:
        print(v)

これで

{0: b'\x02\x00\x00\x00',
 1: 'N',
 2: (35.0, 20.0, 53.51123),
 3: 'E',
 4: (137.0, 9.0, 17.83123),
 5: b'\x00', 6: 256.123}

のような結果を得ます。先の仕様書のGPS INfo IFD の定義と見比べると意味が分かると思います。度分秒なので、10進法にするには変換が必要です。例えば


deg,minu,sec = 35.0, 20.0, 53.51366
deg + minu/60.0 + sec/3600.0

35.34819823888889 を得ます。

piexif でGPS Exif の緯度経度を書き換える

piexifを利用しました。
度分秒と分数への変換を関数にし、Gps exif を読んで書き換える作戦です。

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                                                                                                                                      
    minu = int(t1)                                                                                                                                                
    sec = round((t1 - minu)* 60, 5)
    return (deg, min, sec, loc_value)                                                                                                                                                                                                                                                                                     

import Fraction
def _change_to_rational(number):
    f = Fraction(str(number))                                                                                                                                    
    return (f.numerator, f.denominator)     

を用いて、以下を実行します。

write_gpsexif.py
import piexif
lat, lng, altitude = 39.123, 139.123, 50.123
jpg_filepath = "test.JPG"

lat_deg = to_deg(lat, ["S", "N"])
lng_deg = to_deg(lng, ["W", "E"])
                                                                                                                            exif_lat = (change_to_rational(lat_deg[0]), change_to_rational(lat_deg[1]), change_to_rational(lat_deg[2]))
exif_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.GPSAltitudeRef: 0,
    piexif.GPSIFD.GPSAltitude: change_to_rational(round(altitude, 3)),
    piexif.GPSIFD.GPSLatitudeRef: lat_deg[3],
    piexif.GPSIFD.GPSLatitude: exif_lat,
    piexif.GPSIFD.GPSLongitudeRef: lng_deg[3],
    piexif.GPSIFD.GPSLongitude: exif_lng,
}

gps_exif = {"GPS": gps_ifd}
exif_data = piexif.load(jpg_filepath)
exif_data.update(gps_exif)
exif_bytes = piexif.dump(exif_data)
piexif.insert(exif_bytes, file_name)

これは確かStackOverflow を参考にさせていただいたと思うのですが、linkを無くしてしまいました。見つけたら追加します。

まとめ・雑感

必要にせまらて写真のGPSExif の読み書きをした時のメモです。

  • Pillow, piexif を利用したが、何となくどちらかに統一して正しく使うのがよさそう。

えいやの作業メモなので、拡充させていきたい、、、という投稿でした。最近雑だな。。^^; (2020/08/08)

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5