이미지 EXIF 정보 얻기, GPS 정보 얻기
페이지정보
내용
이미지 EXIF(Exchangeable Image File Format) 정보 얻기
스마트폰이나 디지털 카메라로 사진을 찍어서 jpg 포맷으로 저장을 하면, 사진 파일에 메타데이터(파일의 속성이 저장된 데이터)가 저장된다.
이미지를 볼 수 있는 뷰어나 윈도우즈에서 마우스 오른쪽 버튼을 클릭하여 "이미지 속성" 또는 "속성"을 클릭하면 이미지의 메타데이터 즉, EXIF의 정보를 볼 수 있다.
1) faststone 이미지 속성으로 본 화면
2) 윈도우의 속성으로 본 화면
EXIF의 태그는 카메라 제조사(Make), 카메라 모델(Model), 사진을 보정한 날짜(DateTime) 등등이 있다.
EXIF의 태그에 대한 더 많은 정보는 아래에서 확인한다.
https://www.exiv2.org/tags.html
이미지의 EXIF 정보를 얻기 위해서는 image 모듈을 이용한다.
pip install image |
관련모듈:
image : https://pypi.org/project/image/
pillow : https://pypi.org/project/Pillow/
django : https://pypi.org/project/Django/
pytz : https://pypi.org/project/pytz/
sqlparse : https://pypi.org/project/sqlparse/
asgiref : https://pypi.org/project/asgiref/
1. 이미지 파일 준비하기
미리 찍어둔 사진이 있다면, 사진을 로딩한다. 만약 사진이 없다면 아래 첨부된 파일을 다운 받아서 테스트 하면 된다.
2. 이미지 파일 열기
Image 모듈을 import 하고 파일을 열어서 파일에 대한 정보를 확인한다. PIL은 Python Imaging Library를 의미한다.
이미지 파일 열기 코드
image = Image.open("파일이름")
이미지의 exif정보 얻는 코드
info = image._getexif();
from PIL import Image
image = Image.open("20200120_202504246.jpg")
print(info) |
결과
{36864: b'0220', 37121: b'\x01\x02\x03\x00', 37377: (3584, 1000), 36867: '2020:01:20 20:25:05', 36868: '2020:01:20 20:25:05', 37378: (169599, 100000), 37379: (0, 100), 37380: (0, 6), 37381: (169599, 100000), 37383: 2, 37385: 16, 37386: (3950, 1000), 40961: 1, 40962: 4096, 40965: 1854, 41990: 0, 37520: '988735', 37521: '988735', 37522: '988735', 40963: 3072, 272: 'moto g(6)', 531: 1, 271: 'motorola', 33434: (1, 12), 282: (72, 1), 283: (72, 1), 33437: (18, 10), 41729: b'\x01', 34850: 2, 34853: {0: b'\x02\x02\x00\x00', 1: 'N', 2: ((41, 1), (53, 1), (553344, 10000)), 3: 'W', 4: ((87, 1), (37, 1), (234011, 10000)), 5: b'\x00', 6: (471000, 1000), 7: ((2, 1), (25, 1), (4, 1)), 18: 'WGS-84', 27: 'ASCII\x00\x00\x00CELLID', 29: '2020:01:21'}, 41985: 0, 34855: 3224, 296: 2, 41986: 0, 40960: b'0100', 41987: 0, 305: 'ali_amz-user 9 PPSS29.118-15-11-2 76e712 release-keys', 306: '2020:01:20 20:25:05', 41988: (100, 100), 34665: 244, 37500: b'MOT\x00\x01\x01\x01\x01\x00AU\x00\x00\x02\x00\x00\x00\x13\x00\x00\x03\x1aU\x12\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00U\x02\x00\x01\x00\x00\x00\x01\x1a\x00\x00\x00U\x03\x00\x01\x00\x00\x00\x01\x1a\x00\x00\x00U0\x00\x02\x00\x00\x00\x13\x00\x00\x03-U@\x00\x01\x00\x00\x00\x01_\x00\x00\x00UP\x00\x01\x00\x00\x00\x01_\x00\x00\x00U`\x00\x02\x00\x00\x00\x05\x00\x00\x03@f\xff\x00\x03\x00\x00\x00\x01\x00\x00\x00\x00g\x00\x00\x02\x00\x00\x00\x11\x00\x00\x03Eg\x01\x00\x02\x00\x00\x00\t\x00\x00\x03Vg\x02\x00\x02\x00\x00\x00\x0326\x00\x00g\x03\x00\x02\x00\x00\x00\x03SU\x00\x00g\x04\x00\x02\x00\x00\x00\x03NI\x00\x00g\x05\x00\x02\x00\x00\x00\n\x00\x00\x03_g\x07\x00\x02\x00\x00\x00\t\x00\x00\x03ig\x06\x00\x02\x00\x00\x00\x020\x00\x00\x00g\x08\x00\x03\x00\x00\x00\x01\x00\x00\x00\x00g\t\x00\x03\x00\x00\x00\x01\x9f\x80\x00\x00g\n\x00\x03\x00\x00\x00\x010@\x00\x00g\x0c\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00fA\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00U\xe7\x00\x03\x00\x00\x00\x01\x00\xc1\x00\x00U\xe8\x00\x03\x00\x00\x00\x01\x02~\x00\x00U\xe5\x00\x03\x00\x00\x00\x01\x00\x7f\x00\x00U\xe6\x00\x03\x00\x00\x00\x01\x02\xc0\x00\x00f\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00f\x01\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00f\x02\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00f@\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00f\x04\x00\x03\x00\x00\x00\x01\x00\x00\x00\x00f\x06\x00\x02\x00\x00\x00\x05\x00\x00\x03rf\x12\x00\x03\x00\x00\x00\x01\x02\x00\x00\x00f\x13\x00\x03\x00\x00\x00\x01\x03I\x00\x00f\x14\x00\x03\x00\x00\x00\x01\x03F\x00\x00f\x15\x00\x03\x00\x00\x00\x01\x02E\x00\x00fB\x00\x03\x00\x00\x00\x01\x01\xe9\x00\x00fC\x00\x03\x00\x00\x00\x01\x033\x00\x00fD\x00\x03\x00\x00\x00\x01\x035\x00\x00fE\x00\x03\x00\x00\x00\x01\x020\x00\x00fN\x00\x01\x00\x00\x00\x01\n\x00\x00\x00fO\x00\x03\x00\x00\x00\x01\x00@\x00\x00fP\x00\x03\x00\x00\x00\x01\x00@\x00\x00fQ\x00\x03\x00\x00\x00\x01\x00@\x00\x00fR\x00\x03\x00\x00\x00\x01\x00@\x00\x00fT\x00\x03\x00\x00\x00\x01$\xf9\x00\x00fU\x00\x03\x00\x00\x00\x01*\xab\x00\x00fV\x00\x03\x00\x00\x00\x01\x00\x00\x00\x00f]\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00fS\x00\x02\x00\x00\x00\x03QC\x00\x00d\x00\x00\x02\x00\x00\x00\x05\x00\x00\x03wd3\x00\x02\x00\x00\x00\x020\x00\x00\x00d4\x00\x02\x00\x00\x00\x020\x00\x00\x00dQ\x00\x02\x00\x00\x00\x040.8\x00d\x10\x00\x02\x00\x00\x00\x03NO\x00\x00q\x0e\x00\x02\x00\x00\x00%\x00\x00\x03|q\x10\x00\x02\x00\x00\x00\x0f\x00\x00\x03\xa1U\x11\x00\x04\x00\x00\x00\x01\x00\x00\x00\xa5q\x0f\x00\x02\x00\x00\x00\x10\x00\x00\x03\xb0q\x14\x00\x02\x00\x00\x00\x10\x00\x00\x03\xc0q\x16\x00\x02\x00\x00\x00\x03{}\x00\x00q\x17\x00\x02\x00\x00\x00\x05\x00\x00\x03\xd0d\xd0\x00\x02\x00\x00\x00$\x00\x00\x03\xd5f^\x00\x02\x00\x00\x00\x16\x00\x00\x03\xf9d \x00\x02\x00\x00\x009\x00\x00\x04\x0f\x00\x00\x00\x00PPSS29.118-15-11-2\x00continuous-picture\x00auto\x00000000001f120a01\x0028c21723\x0028Apr2018\x001f120a01\x005000\x00AUTO\x006.07223; 6.07223; 6.07223; 6.07223; \x00FOCUSED_LOCKED\x00892704156139028\x00399054777269147\x00NONE\x00Low_Light_Frame_Stack_State_Machine\x00back-main-mot_ov12a10\x00Scene: LL|MorphoPSv4: Merge: SUCCESS, AlgResult: OK, 4/4\x00'} |
3. EXIF 정보의 TAG를 이용하여 정보 정리하기
Image._getexif() 메서드로 이미지의 메타데이터를 얻었지만, 알아보기가 어렵다. 따라서 메타데이터를 TAG 이름을 이용하여 보기 좋게 정리한다.
2번에서 얻은 메타데이터를 살펴보면, 메타데이터는 딕셔너리 형태로 출력되는 것을 알 수 있다. 따라서 각 딕셔너리의 key:value값을 추출하여 숫자로 된 key값을 알기 쉬운 TAG 이름으로 변경해준다.
TAG 이름으로 변경하기 위해서는 아래의 모듈을 import 한다.
from PIL.ExifTags import TAGS
그리고 메타데이터의 숫자로 된 키를 TAGS 이름으로 변경하여 다시 딕셔너리로 저장한다.
TAG decimal 코드를 TAG 키네임으로 변경하는 코드는 아래와 같다.
TAGS.get(tag, tag)
전체코드
from PIL import Image from PIL.ExifTags import TAGS
image = Image.open("20200120_202504246.jpg")
# 새로운 딕셔너리 생성 taglabel = {}
for tag, value in info.items():
print(taglabel)
print(taglabel['DateTimeOriginal']) |
결과
{'ExifVersion': b'0220', 'ComponentsConfiguration': b'\x01\x02\x03\x00', 'ShutterSpeedValue': (3584, 1000), 'DateTimeOriginal': '2020:01:20 20:25:05', 'DateTimeDigitized': '2020:01:20 20:25:05', 'ApertureValue': (169599, 100000), 'BrightnessValue': (0, 100), 'ExposureBiasValue': (0, 6), 'MaxApertureValue': (169599, 100000), 'MeteringMode': 2, 'Flash': 16, 'FocalLength': (3950, 1000), 'ColorSpace': 1, 'ExifImageWidth': 4096, 'ExifInteroperabilityOffset': 1854, 'SceneCaptureType': 0, 'SubsecTime': '988735', 'SubsecTimeOriginal': '988735', 'SubsecTimeDigitized': '988735', 'ExifImageHeight': 3072, 'Model': 'moto g(6)', 'YCbCrPositioning': 1, 'Make': 'motorola', 'ExposureTime': (1, 12), 'XResolution': (72, 1), 'YResolution': (72, 1), 'FNumber': (18, 10), 'SceneType': b'\x01', 'ExposureProgram': 2, 'GPSInfo': {0: b'\x02\x02\x00\x00', 1: 'N', 2: ((41, 1), (53, 1), (553344, 10000)), 3: 'W', 4: ((87, 1), (37, 1), (234011, 10000)), 5: b'\x00', 6: (471000, 1000), 7: ((2, 1), (25, 1), (4, 1)), 18: 'WGS-84', 27: 'ASCII\x00\x00\x00CELLID', 29: '2020:01:21'}, 'CustomRendered': 0, 'ISOSpeedRatings': 3224, 'ResolutionUnit': 2, 'ExposureMode': 0, 'FlashPixVersion': b'0100', 'WhiteBalance': 0, 'Software': 'ali_amz-user 9 PPSS29.118-15-11-2 76e712 release-keys', 'DateTime': '2020:01:20 20:25:05', 'DigitalZoomRatio': (100, 100), 'ExifOffset': 244, 'MakerNote': b'MOT\x00\x01\x01\x01\x01\x00AU\x00\x00\x02\x00\x00\x00\x13\x00\x00\x03\x1aU\x12\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00U\x02\x00\x01\x00\x00\x00\x01\x1a\x00\x00\x00U\x03\x00\x01\x00\x00\x00\x01\x1a\x00\x00\x00U0\x00\x02\x00\x00\x00\x13\x00\x00\x03-U@\x00\x01\x00\x00\x00\x01_\x00\x00\x00UP\x00\x01\x00\x00\x00\x01_\x00\x00\x00U`\x00\x02\x00\x00\x00\x05\x00\x00\x03@f\xff\x00\x03\x00\x00\x00\x01\x00\x00\x00\x00g\x00\x00\x02\x00\x00\x00\x11\x00\x00\x03Eg\x01\x00\x02\x00\x00\x00\t\x00\x00\x03Vg\x02\x00\x02\x00\x00\x00\x0326\x00\x00g\x03\x00\x02\x00\x00\x00\x03SU\x00\x00g\x04\x00\x02\x00\x00\x00\x03NI\x00\x00g\x05\x00\x02\x00\x00\x00\n\x00\x00\x03_g\x07\x00\x02\x00\x00\x00\t\x00\x00\x03ig\x06\x00\x02\x00\x00\x00\x020\x00\x00\x00g\x08\x00\x03\x00\x00\x00\x01\x00\x00\x00\x00g\t\x00\x03\x00\x00\x00\x01\x9f\x80\x00\x00g\n\x00\x03\x00\x00\x00\x010@\x00\x00g\x0c\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00fA\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00U\xe7\x00\x03\x00\x00\x00\x01\x00\xc1\x00\x00U\xe8\x00\x03\x00\x00\x00\x01\x02~\x00\x00U\xe5\x00\x03\x00\x00\x00\x01\x00\x7f\x00\x00U\xe6\x00\x03\x00\x00\x00\x01\x02\xc0\x00\x00f\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00f\x01\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00f\x02\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00f@\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00f\x04\x00\x03\x00\x00\x00\x01\x00\x00\x00\x00f\x06\x00\x02\x00\x00\x00\x05\x00\x00\x03rf\x12\x00\x03\x00\x00\x00\x01\x02\x00\x00\x00f\x13\x00\x03\x00\x00\x00\x01\x03I\x00\x00f\x14\x00\x03\x00\x00\x00\x01\x03F\x00\x00f\x15\x00\x03\x00\x00\x00\x01\x02E\x00\x00fB\x00\x03\x00\x00\x00\x01\x01\xe9\x00\x00fC\x00\x03\x00\x00\x00\x01\x033\x00\x00fD\x00\x03\x00\x00\x00\x01\x035\x00\x00fE\x00\x03\x00\x00\x00\x01\x020\x00\x00fN\x00\x01\x00\x00\x00\x01\n\x00\x00\x00fO\x00\x03\x00\x00\x00\x01\x00@\x00\x00fP\x00\x03\x00\x00\x00\x01\x00@\x00\x00fQ\x00\x03\x00\x00\x00\x01\x00@\x00\x00fR\x00\x03\x00\x00\x00\x01\x00@\x00\x00fT\x00\x03\x00\x00\x00\x01$\xf9\x00\x00fU\x00\x03\x00\x00\x00\x01*\xab\x00\x00fV\x00\x03\x00\x00\x00\x01\x00\x00\x00\x00f]\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00fS\x00\x02\x00\x00\x00\x03QC\x00\x00d\x00\x00\x02\x00\x00\x00\x05\x00\x00\x03wd3\x00\x02\x00\x00\x00\x020\x00\x00\x00d4\x00\x02\x00\x00\x00\x020\x00\x00\x00dQ\x00\x02\x00\x00\x00\x040.8\x00d\x10\x00\x02\x00\x00\x00\x03NO\x00\x00q\x0e\x00\x02\x00\x00\x00%\x00\x00\x03|q\x10\x00\x02\x00\x00\x00\x0f\x00\x00\x03\xa1U\x11\x00\x04\x00\x00\x00\x01\x00\x00\x00\xa5q\x0f\x00\x02\x00\x00\x00\x10\x00\x00\x03\xb0q\x14\x00\x02\x00\x00\x00\x10\x00\x00\x03\xc0q\x16\x00\x02\x00\x00\x00\x03{}\x00\x00q\x17\x00\x02\x00\x00\x00\x05\x00\x00\x03\xd0d\xd0\x00\x02\x00\x00\x00$\x00\x00\x03\xd5f^\x00\x02\x00\x00\x00\x16\x00\x00\x03\xf9d \x00\x02\x00\x00\x009\x00\x00\x04\x0f\x00\x00\x00\x00PPSS29.118-15-11-2\x00continuous-picture\x00auto\x00000000001f120a01\x0028c21723\x0028Apr2018\x001f120a01\x005000\x00AUTO\x006.07223; 6.07223; 6.07223; 6.07223; \x00FOCUSED_LOCKED\x00892704156139028\x00399054777269147\x00NONE\x00Low_Light_Frame_Stack_State_Machine\x00back-main-mot_ov12a10\x00Scene: LL|MorphoPSv4: Merge: SUCCESS, AlgResult: OK, 4/4\x00'}
2020:01:20 20:25:05 |
'36854' decimal 코드를 'ExifVersion'처럼, 이름으로 변경하여 볼 수 있으므로 메타데이터를 좀 더 수월하게 사용할 수 있다.
4. EXIF 정보의 GPSInfo 이용하여 사진 위치 구하기
위도와 경도에 대한 정보는 아래와 같다.
위도(씨줄. 緯度,latitude)는 지구상에서 적도를 기준으로 북쪽 또는 남쪽으로 얼마나 떨어져 있는지 나타내는 위치이며, 흔히 그리스 문자 φ로 쓴다. 위도의 단위는 도(°)이며, 위도 0°는 적도이다. 북극점을 나타내는 90° N(북위 90도)부터 남극점을 나타내는 90° S(남위 90도)까지의 범위 안에 있다. 위도에는 지리 위도, 천문 위도, 지심 위도 등이 있다.
경도(날줄. 經度,longitude)는 지구상에서 본초 자오선을 기준으로 동쪽 또는 서쪽으로 얼마나 떨어져 있는지 나타내는 위치이다. 경도의 단위는 도(°)이며, 180° E(동경 180도)부터 180° W(서경 180도)까지의 범위 안에 있다. 자연스럽게 적도를 기준으로 잡는 위도와는 달리, 경도의 경우 자연적인 기준이 없기 때문에 임의적으로 하나의 기준이 필요했다. 이 기준은 한동안 지역에 따라 달랐으나 1884년에 국제 회의에서 그리니치 천문대를 지나는 본초 자오선을 표준으로 삼기로 결정했다.
출처 : https://ko.wikipedia.org/wiki/%EC%9C%84%EB%8F%84 , https://ko.wikipedia.org/wiki/%EA%B2%BD%EB%8F%84 |
EXIF의 GPSInfo를 보면 아래와 같이 구성되어 있다.
{0: b'\x02\x02\x00\x00', 1: 'N', 2: ((41, 1), (53, 1), (553344, 10000)), 3: 'W', 4: ((87, 1), (37, 1), (234011, 10000)), 5: b'\x00', 6: (471000, 1000), 7: ((2, 1), (25, 1), (4, 1)), 18: 'WGS-84', 27: 'ASCII\x00\x00\x00CELLID', 29: '2020:01:21'} |
여기에서 위도(Latitude)와 경도(longitude) 정보는 각각 key 2와 4이다.
위도 : 2: ((41, 1), (53, 1), (553344, 10000))
경도 : 4: ((87, 1), (37, 1), (234011, 10000))
또한 위도의 북위, 남위 / 경도의 동경, 서경을 나타내는 정보는 각각 key 1과 3이다.
북남위 표시 : 1: 'N'
동서경 표시 : 3: 'W'
EXIF의 GPSInfo의 위도와 경도는 3가지의 값이 tuple로 나타나는데, 이는 각각 도, 분, 초로 부른다.
1도는 60분이며, 1분은 60초이다. 1도 = 60분 = 3600초
각각의 도, 분, 초는 두 개의 값으로 표현되는데, 첫번째 값을 두 번째 값으로 나누어서 각 값을 얻는다.
위도의 도, 분, 초 계산
도 (41, 1) = 42 / 1
분 (53, 1) = 53 / 1
초 (553344, 10000) = 553344 / 10000
도, 분, 초를 하나의 위도로 나타내는 식은 아래와 같다.
exifGPS = taglabel['GPSInfo']
latData = exifGPS[2]
lonData = exifGPS[4]
# 도, 분, 초 계산
latDeg = latData[0][0] / float(latData[0][1])
latMin = latData[1][0] / float(latData[1][1])
latSec = latData[2][0] / float(latData[2][1])
lonDeg = lonData[0][0] / float(lonData[0][1])
lonMin = lonData[1][0] / float(lonData[1][1])
lonSec = lonData[2][0] / float(lonData[2][1])
# 위도 계산
Lat = (latDeg + (latMin + latSec / 60.0) / 60.0)
# 북위, 남위인지를 판단, 남위일 경우 -로 변경
if exifGPS[1] == 'S': Lat = Lat * -1
# 경도 계산
Lon = (lonDeg + (lonMin + lonSec / 60.0) / 60.0)
# 동경, 서경인지를 판단, 서경일 경우 -로 변경
if exifGPS[3] == 'W': Lon = Lon * -1
전체코드
from PIL import Image from PIL.ExifTags import TAGS
image = Image.open("20200120_202504246.jpg")
# 새로운 딕셔너리 생성 taglabel = {}
for tag, value in info.items():
lonDeg = lonData[0][0] / float(lonData[0][1])
# 도, 분, 초로 나타내기
print(Lat, Lon)
# 도 decimal로 나타내기
# 경도 계산
print(Lat, ",", Lon) |
결과
41°53'55.3344"N 87°37'23.4011"W 41.898704 , -87.62316697222222 |
위의 GPS 정보를 구글 맵같은 곳에 입력하여 위치를 찾을 수 있다.
1) 41°53'55.3344"N 87°37'23.4011"W
2) 41.898704 , -87.62316697222222
5. 구글 맵을 자동으로 열기
파이썬에서 웹 브라우져를 오픈하는 모듈은 webbrowser이다.
webbrowser 모듈을 이용하여 웹 브라우져를 열기 위해서는 아래와 같이 사용한다.
webbrowser.open_new("웹 주소")
사진에서 GPS 정보를 찾아 자동으로 웹 브라우저를 오픈하는 코드는 아래와 같다.
전체코드
from PIL import Image from PIL.ExifTags import TAGS import webbrowser
image = Image.open("20200120_202504246.jpg")
# 새로운 딕셔너리 생성 taglabel = {}
for tag, value in info.items():
lonDeg = lonData[0][0] / float(lonData[0][1])
# 도, 분, 초로 나타내기
webbrowser.open_new("https://www.google.com/maps/place/"+Lat+"+"+Lon)
|
첨부파일
- images.zip (7.3M) 174 다운로드 | DATE : 2020-01-29 12:09:44