end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

jpegのexif情報からGPS座標を抽出し、逆ジオコーディング

http://blog.livedoor.jp/dankogai/archives/51262202.html

EXIFは何となく知っていましたが、GPS座標も定義されていることには驚きました。

http://en.wikipedia.org/wiki/Exchangeable_image_file_format
http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
http://cachu.xrea.jp/perl/ExifTAG.html

そこで、私の携帯電話(au Walkman(R) Phone, Premier3 )で撮影した写真から、緯度/経度を抽出し、更に逆ジオコーディングで住所を表示してみました。

尚、exifからの緯度/経度抽出には Image::ExifTool 、逆ジオコーディングには、google map apiを使用しています。

※Image::ExifTool
http://search.cpan.org/perldoc?Image::ExifTool
google map api
http://code.google.com/intl/en/apis/maps/documentation/geocoding/index.html

#!/usr/local/bin/perl
use strict;
use warnings;
use Encode;
use Encode::Guess qw/shift-jis euc-jp utf-8/;
use Image::ExifTool;
use LWP::UserAgent;
use XML::Simple;
use Data::Dumper;

my $GMAP_API = 'http://maps.google.com/maps/geo?output=xml';
my $GMAP_KEY = "";

main(@ARGV);

sub main {
    my($jpeg_image) = @_;

    #jpegにあるEXIFに含まれる緯度/経度を抽出
    my $lon_lat = get_jpeg_gps_pos($jpeg_image);
    return undef if (ref($lon_lat) ne "ARRAY" or @$lon_lat != 2);

    #緯度/経度から逆geocodingで住所を取得
    my $geo = reverse_geocode($lon_lat);
    print $geo;
}

sub reverse_geocode {
    my($lon_lat) = @_;

    my $ua  = LWP::UserAgent->new();
    my $xml = XML::Simple->new();

    my $res = $ua->get("$GMAP_API&key=$GMAP_KEY&q=$lon_lat->[1],$lon_lat->[0]");
    unless ( $res->is_success ){
	print STDERR "fail http get rev geocode:$lon_lat->[1],$lon_lat->[0]";
	return undef;
    }

    my $xml_str = $res->content;
    $xml_str = decode("Guess", $xml_str);
    my $geo = $xml->XMLin( $xml_str );

    if (not defined($geo->{Response}->{Placemark}->{p1}->{address})){
	return undef;
    }
    return $geo->{Response}->{Placemark}->{p1}->{address};
}

#Image::ExifToolで、jpegにあるEXIFに含まれる緯度/経度を抽出
sub get_jpeg_gps_pos {
    my($image) = @_;

    my $tool = Image::ExifTool->new;
    my $exif = $tool->ImageInfo( $image );

    my $lon = dms2deg( $exif->{GPSLongitude});	#ex. 10 deg 23' 40.20" E
    my $lat = dms2deg( $exif->{GPSLatitude});	#ex. 43 deg 43' 24.00" N
    return undef if (not defined($lon) or not defined($lat));
    return [$lon,$lat];
}

#緯度/経度を度分秒→度に変換
sub dms2deg {
    my($dms) = @_;

    my @dms_elms = $dms =~ /(\d+)\D*(\d+)\D*(\d+\.\d+)\D*([NSEW])/o;
    return undef if (@dms_elms < 4);

    my $deg = $dms_elms[0] + $dms_elms[1]/60 + $dms_elms[2]/3600;
    return $deg * -1 if ($dms_elms[3] eq "S" or $dms_elms[3] eq "W");
    return $deg;
}

実行結果

??丁目????東恋ケ窪, Kokubunji City, Tokyo Metropolis, Japan

逆ジオコーディングの日本語対応は、まだのようですが、十分使えると言う感じ