最近发现的一个很简单,而且很有意思的一个项目,就是通过对手机拍摄照片的EXIF信息进行分析,可以获取到拍摄时间和拍摄时的GPS坐标。然后,通过地理逆编码,就可以把GPS对应的地点翻译出来。
有意思的用处
(1)对忘记信息的照片提供回忆线索。通过对拍摄时间地点的获取,很容易回忆出来当时拍摄时的情景。
(2)对你想知道的人进行定位。从别人那里要来一张图片,你就可以知道拍摄者的位置,拍摄时间。
依赖库
程序需要两个依赖库:exifread ,用来获取图片EXIF 信息; geopy,用来将GPS左边逆编码为地理信息。
地理信息的获取也可以在高德,百度,腾讯地图注册开发者获取api来完成,但是没有geopy方便。
可以通过安装两个依赖库
pip install exifreadpip install geopy
注意:
图片一定要是原图,一定要是原图,一定要是原图。(无它,美图拍出来的照片都不行)
获取图片 EXIF信息
以这个图片为例(这张图片已经不是原图了。。):
对于一张图片,其实直接电脑右键,再点击属性,然后点击详细信息,就会发现,其实图片的EXIF信息(时间,GPS坐标等)就已经能查看了。
现在就是要借助exifread这个包把这些信息全都获取出来
import exifreadimg=exifread.process_file(open('picture.jpg','rb'))time=img['Image DateTime']print(time)latitude=img['GPS GPSLatitude']print(latitude)longitude=img['GPS GPSLongitude']print(longitude)
img其实是一个字典,根据字典的key值找出对应时间,经纬度就可以了
只不过这个时候的经纬度还是GPS坐标的形式
输出的结果为:
:08:08 14:44:15[34, 12, 9286743/200000][108, 57, 56019287/1000000]
这样,需要的信息就获取到了。
GPS坐标的理解:
以维度坐标为例:
34指的是度,12是分,9286743/200000 是秒,所以纬度就是:34度12分9286743/200000秒
格式化地理坐标
地理逆解码需要的坐标需要的是小数形式,所以要将上面的坐标进行转换,根据
1度=60分;1分=60秒
将GPS坐标进行转换
import exifreaddef format_lati_long(data):list_tmp=str(data).replace('[', '').replace(']', '').split(',')list=[ele.strip() for ele in list_tmp]data_sec = int(list[-1].split('/')[0]) /(int(list[-1].split('/')[1])*3600)# 秒的值data_minute = int(list[1])/60data_degree = int(list[0])result=data_degree + data_minute + data_secreturn resultimg=exifread.process_file(open('picture.jpg','rb'))latitude=format_lati_long(str(img['GPS GPSLatitude']))print(latitude)longitude=format_lati_long(str(img['GPS GPSLongitude']))print(longitude)
程序运行的结果为:
34.21289825416667108.96556091305555
这样,格式转换就完成了。
地理解码
最后一步是地理解码,直接上代码
from geopy.geocoders import Nominatimgeolocator = Nominatim(user_agent='demo_of_gnss_help')position = geolocator.reverse('34.21289825416667,108.96556091305555')#str格式才显示中国print(position.address)
输出结果为:
大唐芙蓉园西门, 芙蓉西路 Fúróng West Rd, 曲江, 雁塔区, 雁塔区 (Yanta), 西安市, 陕西省, 710061, 中国
好吧,这是暑假出去玩的时候拍的照片。。
程序运行时可能会报warning,不用担心,没问题的,等结果就行。
重要的是下面两个问题:
首先,经纬度的顺序:我们通常的习惯是先经度后维度,例如:东经(E)xxx度北纬(N)xx度。但是在填写的时候要先纬度后经度,否则会报错;
经纬坐标的填写一定要是字符格式,不能是float格式,否则地点就是国外了。
例如:
from geopy.geocoders import Nominatimgeolocator = Nominatim()position = geolocator.reverse(34.21289825416667,108.96556091305555)#float格式才显示中国print(position.address)
上面程序输出的结果为:
RN 109, sidi khalifa, daïra Marhoum, Sidi Bel Abbès - سيدي بلعباس, ⴷⵣⴰⵢⵔ الجزائر
或者通过高德,百度,腾迅地图的api解码地理信息
以高德为例:
api_key可以自己注册高德开发者模式获取,可以参考网上教程
import requests,jsonapi_key = 'xxxxxxxxxxxxxxxxxxxxxx'url_get_position = '/v3/geocode/regeo?output=JSON&location={}&key={}&radius=1000&extensions=base'longitude=108.96556091305555latitude=34.21289825416667resp=requests.get(url_get_position.format(f'{longitude},{latitude}',api_key))location_data = json.loads(resp.text)address = location_data.get('regeocode').get('formatted_address')print(address)
上面程序输出的结果为:
陕西省西安市雁塔区大雁塔街道金月汇(曲江店)曼蒂广场
地点其实都一样。
完整的代码可以去github上获取 代码链接