여덟째 날: 지오코딩과 역지오코딩

저자

@keedi - Seoul.pm 리더, Perl덕후, 거침없이 배우는 펄의 공동 역자, keedi.k at gmail.com

시작하며

지난 기사인 여섯째 날: 너무 간단한 지도 그리기에서는 Perl을 이용해 지도를 화면에 그리는 방법을 알아보았습니다. 원하는 지점을 지도에 나타내기 위해 주소를 입력하기도 했고, 위도(씨줄. 緯度, latitude)경도(날줄. 經度, longitude) 좌표를 입력하기도 했죠. 생각해보면 이 둘은 무언과 분명히 상관 관계가 있어 보입니다. 보통 우리는 나라에서 공식적으로 지정해서 사용하는 주소 체계에 익숙합니다. 대부분은 주소만 들어도 대충 "아~ 거기~"라고 인지하죠. 하지만 이 주소를 지도상에 컴퓨터로 표시하려면 좀 문제가 있습니다. 지도는 평면적으로 넓게 펼쳐놓고 보았을 때 일종의 2차원 그래프로 X축과 Y축 단 두 개의 좌표만 있으면 아주 손쉽게 특정 위치를 지정할 수 있죠. 이 X축과 Y축이 경도와 위도 정보입니다. 하지만 주소로 특정 위치를 찾는 일은 쉽지 않기에 이 주소 정보에 해당하는 위도와 경도 정보를 안다면 훨씬 쉽게 지도 상에 해당 위치를 표시할 수 있겠죠. 역으로 GPS 장비가 시시각각 위도와 경도 좌표를 저장한다면, 사실 이 소숫점을 포함한 복잡하고 긴 수치를 보았을 때 여기가 어디인지 파악하는 것은 현실적으로 불가능하죠. 이 때는 대부분의 평범한 사람은 해당 위도와 경도 좌표가 해당하는 주소를 보았을 때야 "아~ 여기였구나~"할 것입니다. 이 때 필요한 것이 바로 지오코딩(geocoding)과 역지오코딩(reverse geocoding)입니다. Perl을 이용해 가장 널리 사용하는 구글맵지오코딩을 사용해보죠.

준비물

필요한 모듈은 다음과 같습니다.

직접 CPAN을 이용해서 설치한다면 다음 명령을 이용해서 모듈을 설치합니다.

$ sudo cpan Geo::Coder::Google

사용자 계정으로 모듈을 설치하는 방법을 정확하게 알고 있거나 perlbrew를 이용해서 자신만의 Perl을 사용하고 있다면 다음 명령을 이용해서 모듈을 설치합니다.

$ cpan Geo::Coder::Google

Google Maps API 키

구글 지도 보여 줄 때와 마찬가지로 지오코딩을 하기 위해서도 Google Maps API 키가 필요합니다. API 키를 발급받는 방법은 지난 기사인 여섯째 날: 너무 간단한 지도 그리기를 참고하세요.

실전 지오코딩

지오코딩(geocoding)"서울 종로구 세종로 1"와 같은 주소를 37°35'11.9"N 126°58'36.4"E와 같은 지리 좌표로 변환하는 작업입니다. 반대로 역지오코딩은 지리 좌표를 주소로 변환하는 것입니다. 우선 지오코딩을 위해서는 Geo::Coder::Google 모듈 객체를 생성해야 합니다.

use utf8;
use strict;
use warnings;
use feature qw( say );

use Geo::Coder::Google;

my $geocoder = Geo::Coder::Google->new(
    apidriver => 3,
    api_key   => "AIzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHkY",
);

구글은 더이상 구글맵 API 버전2를 지원하지 않기 때문에 버전3을 써야하므로 딱히 선택의 여지는 없습니다. API 버전은 apidriver 인자를 이용해서 명시하고, 발급받은 키는 api_key 인자로 명시합니다. 이제 지오코딩을 할 모든 준비는 끝났습니다.

my @locations = $geocoder->geocode(
    location => "서울 종로구 세종로 1",
);
die "failed to geocode\n" unless @locations;

geocode() 메소드를 이용해서 실제 지오코딩을 실행하며, 지오코딩을 결과를 배열로 반환 받습니다. 이 때 결과 배열의 첫 번째 항목이 가장 정확하게 일치된 항목이며, 이후 항목은 근접한 후보 항목을 반환합니다. 스칼라 문맥으로 반환받을 경우 배열로 반환 받을 때의 가장 첫 번째 항목을 반환합니다.

my $location = shift @locations;
say "$location->{geometry}{location}{lat}, $location->{geometry}{location}{lng}";

if (@locations) {
    say "candidate:";
    for my $candidate (@locations) {
        say "  $candidate->{geometry}{location}{lat},$candidate->{geometry}{location}{lng}";
    }
}

실행 결과는 다음과 같습니다.

$ ./geocoding.pl
37.586652,126.9767701
$

이번에는 역지오코딩을 해볼까요? 지오코딩과 대동소이합니다.

my $result = $geocoder->reverse_geocode( latlng => "37.586652,126.9767701" );
die "failed to reverse geocode\n" unless $result;
say $result->{formatted_address};

역지오코딩을 하기 위해서는 reverse_geocode() 메소드를 사용합니다. 이 때 인자는 latlng이며, 위도와 경도 정보를 쉼표를 이용해 조합한 문자열을 전달합니다. 결과는 해시 참조(reference)를 반환하며 여기에 저장된 항목은 크게 다음과 같은 구조를 가집니다.

우리가 흔히 필요로 하는 최종 결과물은 formatted_address에 문자열로 저장되어 있거나 address_components에 배열 참조로 각각의 주소 체계에 맞는 정보가 저장되어 있습니다. $result->{formatted_address}의 값을 출력하면 일단 우리가 원하는 역지오코딩 결과를 확인할 수 있습니다. 실행 결과는 다음과 같습니다.

$ ./reverse-geocoding.pl
1 Sejongno, Jongno-gu, Seoul, South Korea
$

어라, 결과가 영어로 나오는 군요. 구글은 전세계적으로 서비스를 지원하기 때문에 다양한 언어를 지원하지만 특별히 언어를 설정하지 않은 경우 기본적으로 영어로 결과를 반환하기 때문입니다. Geo::Coder::Google 모듈은 language 속성을 지원하므로 이를 사용해서 한국어로 설정해보죠.

my $geocoder = Geo::Coder::Google->new(
    apidriver => 3,
    api_key   => "AIzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHkY",
    language  => "ko",
);

실행 결과는 다음과 같습니다.

$ ./reverse-geocoding.pl
Wide character in say at ./reverse-geocoding.pl line XX.
대한민국 서울특별시 종로구 세종로 1
$

원하는 결과가 나온 것 같긴한데 Wide character ... 관련 경고가 발생하네요. 이것은 표준 출력의 인코딩을 설정하면 간단히 해결할 수 있습니다.

use Geo::Coder::Google;

binmode STDOUT, ":utf8";

my $geocoder = Geo::Coder::Google->new(
    ...
);

실행 결과는 다음과 같습니다.

$ ./reverse-geocoding.pl
대한민국 서울특별시 종로구 세종로 1
$

이제 정말 잘 되는 것 같네요. :-)

정리하며

비단 구글 지도 뿐만 아니라 네이버 지도카카오(다음) 지도도 지오코딩과 역지오코딩 기능을 지원하니 관심이 있다면 한 번쯤 확인해보세요. 여러분이 인지는 못했겠지만 사실 지오코딩의 역사는 무척 오래되었으며, 컴퓨터를 이용한 무료 지도 서비스와 스마트폰의 지도 서비스가 일상이 되면서 우리는 하루에도 몇 번씩 지오코딩과 역지오코딩 기능을 사용하고 있습니다. 위치 기반 서비스가 일상이 된 지금 지도와 지오코딩 등에 대해서 자세히 알아두면 꽤 유용하겠죠? :-)

EOT

blog comments powered by Disqus