GIS奮闘記

現役GISエンジニアの技術紹介ブログ。主にPythonを使用。

スポンサーリンク

piexif を使って画像に付与されているジオタグからポイントを作成して Shape ファイルとして出力する方法

さて、本日は前回のエントリーに続きジオタグのお話です。前回は画像にジオタグを追加する方法を紹介しましたが(以下エントリー参照)、今回は画像に付与されているジオタグを抽出する方法を紹介しようと思います。また、その緯度経度を使用してポイントを作成しShape ファイルとして出力してみようと思います。

www.gis-py.com

使用するライブラリ

piexif
GDAL

piexif で画像に付与されているジオタグを抽出して、その情報を GDAL を使ってポイントを作成し、Shapeファイルとして抽出してみようと思います。なお、ポイント作成とShape 出力の部分は以下エントリーをベースに書いてみようと思います。

www.gis-py.com

使用する画像

こんなサイトがあったので、使ってみました。

www.geoimgr.com

世界各地の風景写真を掲載しているサイトですね。これは京都の桂川の写真らしいです。

f:id:sanvarie:20191026144148p:plain

緯度経度も設定されていることがわかります。

f:id:sanvarie:20191027085913p:plain

こんな感じにデータを格納してみました。これらのジオタグを抽出して、ポイントとして Shape ファイルを作成してみようと思います。

f:id:sanvarie:20191026142150p:plain

実行環境

Windows 10
Python 3.6.6
piexif 1.1.3
GDAL 2.1.1
ArcGIS Pro 2.4

サンプルコード

import os
from glob import glob
import piexif
import osgeo.ogr as ogr

folder = r"D:\data\picture"
shape_file = r"D:\data\shape\geotag.shp"

def make_shape_for_point(info):
    """ポイントShapeファイルを作成"""

    # shapefileドライバ
    driver = ogr.GetDriverByName("ESRI Shapefile")

    # Shape出力先を設定
    data_source = driver.CreateDataSource(shape_file)

    # レイヤ作成
    layer = data_source.CreateLayer("geotag",  geom_type= ogr.wkbPoint)

    # フィールド追加
    field_name = ogr.FieldDefn("file_name", ogr.OFTString)
    field_name.SetWidth(24)
    layer.CreateField(field_name)

    layer.CreateField(ogr.FieldDefn("longitude", ogr.OFTReal))
    layer.CreateField(ogr.FieldDefn("latitude", ogr.OFTReal))

    # Shape作成
    for l in info:
      # フィーチャ作成
      feature = ogr.Feature(layer.GetLayerDefn())

      # 属性を設定
      feature.SetField("file_name", l[2])
      feature.SetField("longitude", l[1])
      feature.SetField("latitude", l[0])

      # 作成するポイントに緯度経度をセット
      wkt = "POINT(%f %f)" %  (float(l[1]) , float(l[0]))

      # ポイント作成
      point = ogr.CreateGeometryFromWkt(wkt)
      feature.SetGeometry(point)
      layer.CreateFeature(feature)
      feature = None

    data_source = None

def conv_deg(v):
    """緯度、経度を60進法(度分秒)→10進法に変換"""

    d = float(v[0][0]) / float(v[0][1])
    m = float(v[1][0]) / float(v[1][1])
    s = float(v[2][0]) / float(v[2][1])
    return d + (m / 60.0) + (s / 3600.0)

def read_geotag():
    """画像を読み込んで緯度経度を取得"""

    info = []

    # 指定するフォルダ内のjpgを取得
    for jpg in glob(folder + "\*.jpg"):

        # 画像を読み込む
        exif_dict = piexif.load(jpg)

        if (len(exif_dict["GPS"]) > 0):

            # 緯度、経度を60進法(度分秒)→10進法に変換
            lat = conv_deg(exif_dict["GPS"][2])
            lon = conv_deg(exif_dict["GPS"][4])

            # ファイル名を取得
            file_name = os.path.basename(jpg)

            info.append([lat, lon, file_name])

    return info

make_shape_for_point(read_geotag())

結果を確認するとこのように Shape ファイルが出力されたことがわかります。

f:id:sanvarie:20191026143502p:plain

出力された Shape ファイルを ArcGIS Pro で読み込んでみると、それっぽい場所にポイントが作成されていることがわかります。

f:id:sanvarie:20191026143133p:plain

京都の桂川のデータを確認してみると、場所は問題なさそうです。また、属性もしっかり格納されていますね。

f:id:sanvarie:20191026144259p:plain

このように piexif を使用すれば前回のようにジオタグを画像に追加したり、今回のように画像に付与されているジオタグを抽出することが簡単にできます。また、 GDAL を使用すれば、その抽出した情報からポイントを作成し、Shape ファイルとして出力することも簡単にできます。

二回連続でジオタグに関して書いてみましたが、いかがでしたでしょうか?もし他に何か知りたいことなどがありましたらコメントしていただければと思います。本日は以上です。