EXIF(Exchangeable image file format,可交換圖像文件格式)是專門爲數碼相機的照片設定的,能夠記錄數碼照片的屬性信息和拍攝數據,如拍攝時間、圖像分辨率、感光值、GPS座標等。html
Exif最初由日本電子工業發展協會在1996年制定,版本爲1.0。1998年,升級到2.1,增長了對音頻文件的支持。2002年3月,發表了2.2版。python
Exif能夠附加於JPEG、TIFF、RIFF等文件之中,爲其增長有關數碼相機拍攝信息的內容和索引圖或圖像處理軟件的版本信息。git
Exif信息是能夠被任意編輯的,所以只有參考的功能。Exif信息以0xFFE1做爲開頭標記,後兩個字節表示Exif信息的長度。因此Exif信息最大爲64 kb,而內部採用TIFF格式。shell
Windows7以上操做系統具有對Exif的原生支持,Windows系統下,能夠經過鼠標右鍵點擊圖片打開菜單,點擊屬性並切換到詳細信息標籤下,便可直接獲取圖片的EXIF信息。json
https://exif.tuchong.com/windows
https://www.gaitubao.com/exifapi
https://www.52doutu.cn/tools/...微信
exifread模塊爲python讀取圖片EXIF信息的庫。
exifread模塊的下載地址:https://pypi.python.org/pypi/...
安裝exifread庫app
pip install exifread
主要使用process_file函數進行解析,傳入圖片文件對象,返回一個包含圖片信息的字典。其中,exif中GPS格式爲DMS格式,即:D(degree,度)、M(minute,分)、S(second,秒),所以要進行轉換才能獲得常見的double類型的經緯度值。下面就用python + exifread讀取圖片的詳細信息。echarts
import exifread with open('IMG_20190618_163339.jpg', 'rb') as f: exif_dict = exifread.process_file(f) print('拍攝時間:', exif_dict['EXIF DateTimeOriginal']) print('照相機制造商:', exif_dict['Image Make']) print('照相機型號:', exif_dict['Image Model']) print('照片尺寸:', exif_dict['EXIF ExifImageWidth'], exif_dict['EXIF ExifImageLength']) # 經度 lon_ref = exif_dict["GPS GPSLongitudeRef"].printable lon = exif_dict["GPS GPSLongitude"].printable[1:-1].replace(" ", "").replace("/", ",").split(",") lon = float(lon[0]) + float(lon[1]) / 60 + float(lon[2]) / float(lon[3]) / 3600 if lon_ref != "E": lon = lon * (-1) # 緯度 lat_ref = exif_dict["GPS GPSLatitudeRef"].printable lat = exif_dict["GPS GPSLatitude"].printable[1:-1].replace(" ", "").replace("/", ",").split(",") lat = float(lat[0]) + float(lat[1]) / 60 + float(lat[2]) / float(lat[3]) / 3600 if lat_ref != "N": lat = lat * (-1) print('照片的經緯度:', (lat, lon)) for key in exif_dict: print("%s: %s" % (key, exif_dict[key]))
輸出:
拍攝時間: 2019:06:18 16:33:40 照相機制造商: HUAWEI 照相機型號: HRY-AL00Ta 照片尺寸: 3968 2976 照片的經緯度: (13.787098884444445, 100.62936401361111) Image ImageWidth: 3968 Image ImageLength: 2976 Image BitsPerSample: [8, 8, 8] Image Make: HUAWEI Image Model: HRY-AL00Ta Image Orientation: 0 Image XResolution: 72 Image YResolution: 72 Image ResolutionUnit: Pixels/Inch Image Software: HRY-AL00Ta 9.0.1.130(C00E130R4P1) Image DateTime: 2019:06:18 16:33:40 Image YCbCrPositioning: Centered Image ExifOffset: 290 GPS GPSVersionID: [2, 2, 0, 0] GPS GPSLatitudeRef: N GPS GPSLatitude: [13, 47, 847249/62500] GPS GPSLongitudeRef: E GPS GPSLongitude: [100, 37, 45710449/1000000] ............................省略
要想將圖片中的經緯度信息轉換爲詳細地址,一樣也有不少方法,好比在線查詢、地圖API或者利用python的地理位置信息庫:geopy。
http://www.gpsspg.com/maps.htm
http://www.gzhatu.com/dingwei...
沒錯,這張圖片是我在泰國拍的😀
這裏以百度地圖API爲例,須要去官網註冊建立應用獲取AK碼。
百度地圖:http://lbsyun.baidu.com
這裏以我以前拍的重慶彩車照進行試驗,從輸出結果上看算是很是精準定位了。
import json import requests import exifread with open('IMG_20191019_164726.jpg', 'rb') as f: exif_dict = exifread.process_file(f) # 經度 lon_ref = exif_dict["GPS GPSLongitudeRef"].printable lon = exif_dict["GPS GPSLongitude"].printable[1:-1].replace(" ", "").replace("/", ",").split(",") lon = float(lon[0]) + float(lon[1]) / 60 + float(lon[2]) / float(lon[3]) / 3600 if lon_ref != "E": lon = lon * (-1) # 緯度 lat_ref = exif_dict["GPS GPSLatitudeRef"].printable lat = exif_dict["GPS GPSLatitude"].printable[1:-1].replace(" ", "").replace("/", ",").split(",") lat = float(lat[0]) + float(lat[1]) / 60 + float(lat[2]) / float(lat[3]) / 3600 if lat_ref != "N": lat = lat * (-1) print('照片的經緯度:', (lat, lon)) # 調用百度地圖api轉換經緯度爲詳細地址 secret_key = 'MAsVGINLNyTGiM4UulcaeluCekGnAFxj' # 百度地圖api 須要註冊建立應用 baidu_map_api = 'http://api.map.baidu.com/reverse_geocoding/v3/?ak={}&output=json&coordtype=wgs84ll&location={},{}'.format(secret_key, lat, lon) content = requests.get(baidu_map_api).text gps_address = json.loads(content) # 結構化的地址 formatted_address = gps_address["result"]["formatted_address"] # 國家(若需訪問境外POI,需申請逆地理編碼境外POI服務權限) country = gps_address["result"]["addressComponent"]["country"] # 省 province = gps_address["result"]["addressComponent"]["province"] # 市 city = gps_address["result"]["addressComponent"]["city"] # 區 district = gps_address["result"]["addressComponent"]["district"] # 語義化地址描述 sematic_description = gps_address["result"]["sematic_description"] print(formatted_address) print(gps_address["result"]["business"])
輸出
照片的經緯度: (29.564165115277778, 106.54840087888888) 重慶市渝中區學田灣正街2號11樓 大禮堂,上清寺,大溪溝
geopy使python開發人員可以使用第三方地理編碼程序和其餘數據源(包括谷歌地圖,必應地圖,Nominatim等),輕鬆定位全球各地的地址、城市、國家和地標的座標。
安裝
pip install geopy
經過geopy進行經緯度查詢
import exifread from geopy.geocoders import Nominatim with open('IMG_20190618_163339.jpg', 'rb') as f: exif_dict = exifread.process_file(f) # 經度 lon_ref = exif_dict["GPS GPSLongitudeRef"].printable lon = exif_dict["GPS GPSLongitude"].printable[1:-1].replace(" ", "").replace("/", ",").split(",") lon = float(lon[0]) + float(lon[1]) / 60 + float(lon[2]) / float(lon[3]) / 3600 if lon_ref != "E": lon = lon * (-1) # 緯度 lat_ref = exif_dict["GPS GPSLatitudeRef"].printable lat = exif_dict["GPS GPSLatitude"].printable[1:-1].replace(" ", "").replace("/", ",").split(",") lat = float(lat[0]) + float(lat[1]) / 60 + float(lat[2]) / float(lat[3]) / 3600 if lat_ref != "N": lat = lat * (-1) print('照片的經緯度:', (lat, lon)) reverse_value = str(lat) + ', ' + str(lon) geolocator = Nominatim() location = geolocator.reverse(reverse_value) print('照片的經緯度信息:') print((location.latitude, location.longitude)) print('照片的地址信息:') print(location.address)
輸出
照片的經緯度: (13.787098884444445, 100.62936401361111) 照片的經緯度信息: (13.787094791472175, 100.6293647961708) 照片的地址信息: กรุงเทพมหานคร, เขตวังทองหลาง, 10310, ประเทศไทย
一張圖片能夠暴露你什麼時間在什麼地方,甚至體現了你當時在作什麼,想一想有多可怕,不信能夠看看這個:
不過對於我的來講,圖片exif信息可讓咱們更好地管理本身拍攝的圖片庫。好比說:
能夠經過exif時間信息,將圖片歸類到不一樣時間命名的文件夾下。
import os import exifread import shutil imgs_path = 'E:\泰國遊' for img in os.listdir(imgs_path): img_path = os.path.join(imgs_path, img) img_file = open(img_path, 'rb') exif_dict = exifread.process_file(img_file) date = exif_dict['EXIF DateTimeOriginal'] date = date.values.replace(':', '_') year_month_day = date[:10] target_path = os.path.join('E:\旅遊', year_month_day) if not os.path.exists(target_path): os.mkdir(target_path) shutil.copy(img_path, target_path)
下面以本人2019年下半年的手機圖片數據進行統計分析,並結合pyecharts和Mapbox進行展現。
pyecharts:一個大神建立的輪子,將python與echarts結合的強大的數據可視化工具。注意版本不一樣,有些接口調用是有區別的。
pip install pyecharts pip install echarts-countries-pypkg pip install pyecharts-jupyter-installer==0.0.3
統計和轉換地址的代碼,輸出爲csv文件:
import os import json import requests import pandas as pd import exifread from geopy.geocoders import Nominatim secret_key = '###################' def convert_dms2dd(coord_arr): arr = str(coord_arr).replace('[', '').replace(']', '').split(', ') d = float(arr[0]) m = float(arr[1]) s = float(arr[2].split('/')[0]) / float(arr[2].split('/')[1]) dd = float(d) + (float(m) / 60) + (float(s) / 3600) return dd def get_img_infor_tup(photo): img_file = open(photo, 'rb') image_map = exifread.process_file(img_file) img_dict = {} img_dict['Image Name'] = os.path.basename(photo) try: img_dict['width'] = image_map['Image ImageWidth'].printable img_dict['length'] = image_map['Image ImageLength'].printable # 圖片的經度 img_longitude = convert_dms2dd(image_map["GPS GPSLongitude"].printable) if image_map["GPS GPSLongitudeRef"].printable != "E": img_longitude = img_longitude * (-1) img_dict['longitude'] = img_longitude # 圖片的緯度 img_latitude = convert_dms2dd(image_map["GPS GPSLatitude"].printable) if image_map["GPS GPSLatitudeRef"].printable != "N": img_latitude = img_latitude * (-1) img_dict['latitude'] = img_latitude altitude = image_map['GPS GPSAltitude'].printable if '/' in altitude: altitude = float(altitude.split('/')[0]) / float(altitude.split('/')[1]) img_dict['altitude'] = altitude # 照片拍攝時間 img_dict['date'] = image_map["EXIF DateTimeOriginal"].printable img_file.close() # 返回經緯度元組 return img_dict except Exception as e: img_file.close() print('ERROR:圖片中不包含Gps信息') return None def get_detail_infor_by_baidu(lat, lon): baidu_map_api = 'http://api.map.baidu.com/reverse_geocoding/v3/?ak={0}&output=json&coordtype=wgs84ll&location={1},' \ '{2}'.format(secret_key, lat, lon) content = requests.get(baidu_map_api).text gps_address = json.loads(content) return gps_address["result"] def img_data_statistic(imgs_path): info_list = [] for file_name in os.listdir(imgs_path): img_path = os.path.join(imgs_path, file_name) info_dict = get_img_infor_tup(img_path) if info_dict is not None: gps_address_dict = get_detail_infor_by_baidu(info_dict['latitude'], info_dict['longitude']) # 省 info_dict['province'] = gps_address_dict["addressComponent"]["province"] # 市 info_dict['city'] = gps_address_dict["addressComponent"]["city"] # 區 info_dict['district'] = gps_address_dict["addressComponent"]["district"] info_dict['formatted_address'] = gps_address_dict["formatted_address"] info_list.append(info_dict) # break img_df = pd.DataFrame(info_list) img_df.to_csv('imgInfo.csv', index=False, encoding='utf-8') if __name__ == '__main__': imgs_path = 'E:/photo' img_data_statistic(imgs_path)
可視化,主要是經過pyecharts進行繪圖。
import pandas as pd from pyecharts.charts import Bar df = pd.read_csv('imgInfo.csv',sep=',') data = df["province"].value_counts() bar = ( Bar() .add_xaxis(data.index.tolist()) .add_yaxis("圖片數量", data.values.tolist()) .set_global_opts(title_opts=opts.TitleOpts(title="各省分佈狀況", subtitle='19年下半年去了哪兒'), xaxis_opts=opts.AxisOpts(name="省份",axislabel_opts={"rotate":45})) ) bar.render_notebook()
同理,各個城市的統計圖。
以及,在地圖上進行可視化。
import json import pandas as pd from pyecharts import options as opts from pyecharts.charts import Geo from pyecharts.globals import CurrentConfig, NotebookType CurrentConfig.NOTEBOOK_TYPE = NotebookType.JUPYTER_NOTEBOOK def is_Chinese(word): for ch in word: if '\u4e00' <= ch <= '\u9fff': return True return False df = pd.read_csv('imgInfo.csv',sep=',') data = df["city"].value_counts() # 找出國外地址,Geo添加自定義點 thailand_address = [] json_data= {} for city in data.index: if not is_Chinese(city): json_data[city] = df[['longitude','latitude']][df["city"] == city].mean().values.tolist() thailand_address.append(city) json_str = json.dump(json_data, open('thailand.json', 'w', encoding='utf-8'), ensure_ascii=False,indent=4) # 鏈式調用 c = ( Geo() .add_schema(maptype="world") .add_coordinate_json(json_file='thailand.json') .add("去過的城市", [list(z) for z in zip(data.index.tolist(), data.values.tolist())], symbol_size = 30, large_threshold = 2000, symbol="pin") .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) .set_global_opts(title_opts=opts.TitleOpts(title="2019下半年你去過哪兒")) ) c.render_notebook()
國內地圖展現
能夠直接將包含經度和維度的統計數據(csv格式)拖入到網站:
https://www.mapbox.cn/labs/mb...
綜上,要想信息不被泄露
python第三方庫之exifread庫使用【華爲雲技術分享】Python解析照片EXIF信息,獲取座標位置