-
Notifications
You must be signed in to change notification settings - Fork 455
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
372 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
#!/usr/bin/env python | ||
# encoding: utf-8 | ||
|
||
""" | ||
@version: v1.0 | ||
@author: xag | ||
@license: Apache Licence | ||
@contact: [email protected] | ||
@site: http://www.xingag.top | ||
@software: PyCharm | ||
@file: gps_utils.py | ||
@time: 2019-11-17 10:34 | ||
@description:TODO | ||
""" | ||
|
||
import math | ||
|
||
|
||
def gps_to_dms(gps_data): | ||
""" | ||
坐标转为度、分、秒(double) | ||
116.397451 | ||
:param gps_data: | ||
:return: | ||
""" | ||
# 度:向下取整 | ||
gps_degree = math.floor(gps_data) | ||
|
||
gps_data_temp1 = (gps_data - gps_degree) * 60 | ||
|
||
# 分 | ||
gps_minute = math.floor(gps_data_temp1) | ||
|
||
gps_data_temp2 = gps_data_temp1 - gps_minute | ||
|
||
# 秒,取小数点后4位 | ||
gps_second = round(gps_data_temp2 * 60, 2) | ||
|
||
# 注意:秒必须转换为整形 | ||
result = ((gps_degree, 1), (gps_minute, 1), (int(gps_second * 100), 100)) | ||
|
||
return result | ||
|
||
|
||
def dms_to_gps(dms_data): | ||
""" | ||
度、分、秒转为坐标值(double) | ||
:param dms_data: | ||
:return: | ||
""" | ||
data1 = dms_data[0][0] / dms_data[0][1] | ||
|
||
data2 = dms_data[1][0] / dms_data[1][1] / 60 | ||
|
||
data3 = dms_data[2][0] / dms_data[2][1] / 3600 | ||
|
||
result = round(data1 + data2 + data3,6) | ||
|
||
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
#!/usr/bin/env python | ||
# encoding: utf-8 | ||
|
||
""" | ||
@version: v1.0 | ||
@author: xag | ||
@license: Apache Licence | ||
@contact: [email protected] | ||
@site: http://www.xingag.top | ||
@software: PyCharm | ||
@file: main.py | ||
@time: 2019-11-16 10:12 | ||
@description:修改图片地理位置 | ||
""" | ||
|
||
import requests | ||
import time | ||
from PIL import Image | ||
import piexif | ||
import json | ||
from gps_utils import * | ||
from position_utils import * | ||
|
||
|
||
# 依赖:pip3 install piexif | ||
|
||
class Exif(): | ||
def __init__(self): | ||
self.time = '2019:11:17 14:13:22' | ||
|
||
# 地理编码(地址转为经纬度) | ||
self.url_geo = 'https://restapi.amap.com/v3/geocode/geo' | ||
|
||
# 逆地理编码(经纬度转为地址) | ||
self.url_regeo = 'https://restapi.amap.com/v3/geocode/regeo?parameters' | ||
|
||
# key | ||
self.ak = '你的ak' | ||
|
||
# 数字签名 | ||
self.sign = '你的sign' | ||
|
||
def read_image(self, image_path): | ||
""" | ||
开始处理图片 | ||
exifread:读取图片属性 | ||
:return: | ||
""" | ||
exif_dict = piexif.load(image_path) | ||
|
||
if exif_dict['GPS']: | ||
|
||
# 纬度 | ||
gps_lati_pre = exif_dict['GPS'][2] | ||
|
||
gps_lati = dms_to_gps(gps_lati_pre) | ||
|
||
# 经度 | ||
gps_long_pre = exif_dict['GPS'][4] | ||
gps_long = dms_to_gps(gps_long_pre) | ||
|
||
# GPS坐标转为高德坐标 | ||
lng, lat = wgs84togcj02(gps_long, gps_lati) | ||
|
||
# print(lng, lat) | ||
|
||
print(f"原图地理位置如下\n经度:{lng}\n纬度:{lat}\n") | ||
|
||
return f'{lng}, {lat}' | ||
else: | ||
print(f'抱歉!这张图片不包含地理位置!') | ||
|
||
def current_time(self): | ||
""" | ||
获取当前时间 | ||
:return: | ||
""" | ||
time_now = time.strftime('%Y:%m:%d %H:%M:%S', time.localtime(time.time())) | ||
|
||
result = bytes(time_now, encoding='utf-8') | ||
|
||
return result | ||
|
||
def str_to_bytes(self, str_content): | ||
""" | ||
字符串转bytes | ||
:return: | ||
""" | ||
return bytes(str_content, encoding='utf-8') | ||
|
||
def is_image(self, filename): | ||
""" | ||
判断文件是否是一张图片 | ||
:param filename: | ||
:return: | ||
""" | ||
file_suffix = filename.split('.')[-1] | ||
|
||
if file_suffix == 'jpg' or file_suffix == 'png': | ||
return True | ||
else: | ||
return False | ||
|
||
def write_image(self, image_path, gps_long, gps_lati): | ||
""" | ||
修改文件夹下所有文件的属性 | ||
:param image_path: 文件夹路径 | ||
:return: | ||
""" | ||
# 读取图片 | ||
img = Image.open(image_path) | ||
|
||
try: | ||
exif_dict = piexif.load(img.info['exif']) | ||
except: | ||
print('加载文件地理位置异常!') | ||
return | ||
|
||
# 修改地理位置 | ||
# GPS GPSLatitudeRef:N | ||
# GPS GPSLatitude:[22, 32, 189/20] | ||
# GPS GPSLongitudeRef:E | ||
# GPS GPSLongitude:[114, 1, 689/20] | ||
exif_dict['GPS'][2] = gps_to_dms(gps_lati) | ||
exif_dict['GPS'][4] = gps_to_dms(gps_long) | ||
|
||
exif_bytes = piexif.dump(exif_dict) | ||
|
||
# 写入到新的图片中去 | ||
img.save(image_path, 'jpeg', exif=exif_bytes) | ||
|
||
def get_address_by_location(self, location): | ||
""" | ||
通过经纬度拿到地理位置 | ||
:param location: | ||
:return: | ||
""" | ||
params = { | ||
'key': self.ak, | ||
'location': location, | ||
'sig': self.sign | ||
} | ||
|
||
resp = json.loads(requests.get(url=self.url_regeo, params=params).text) | ||
|
||
if resp and resp.get('regeocode') and resp.get('regeocode').get('formatted_address'): | ||
address = resp.get('regeocode').get('formatted_address') | ||
print(f'原图的拍摄地址为:{address}\n') | ||
else: | ||
print('api解析地址出错,请检查ak!\n') | ||
|
||
def get_location_by_address(self, city, address): | ||
""" | ||
通过地理位置到拿到经纬度 | ||
地理编码:https://lbs.amap.com/api/webservice/guide/api/georegeo/ | ||
:param address: | ||
:return: | ||
""" | ||
params = { | ||
'key': self.ak, | ||
'city': city, | ||
'address': address, | ||
'sig': self.sign | ||
} | ||
|
||
resp = json.loads(requests.get(url=self.url_geo, params=params).text) | ||
|
||
# 获取坐标地址 | ||
if resp and len(resp.get('geocodes')) >= 1 and resp.get('geocodes')[0].get('location'): | ||
location = resp.get('geocodes')[0].get('location') | ||
gps_data = location.split(',') | ||
|
||
# 得到经度和纬度 | ||
gps_long = float(gps_data[0]) | ||
gps_lati = float(gps_data[1]) | ||
|
||
return gps_long, gps_lati | ||
else: | ||
print('api解析地址出错,请检查ak!') | ||
return None | ||
|
||
|
||
if __name__ == '__main__': | ||
exif = Exif() | ||
|
||
image_path = './WechatIMG1439.jpeg' | ||
|
||
# 1、读取原图的属性 | ||
location = exif.read_image(image_path) | ||
|
||
if location: | ||
# 2、原图的详细地址 | ||
exif.get_address_by_location(location) | ||
|
||
# 3、输入地址(市+目的地,例如:深圳莲花山公园) | ||
city = input('请输入定位城市(例如:深圳):') | ||
address = input('请输入具体的定位地址(例如:莲花山公园):') | ||
|
||
if address: | ||
# 通过地址拿到坐标地址 | ||
location = exif.get_location_by_address(city, address) | ||
|
||
if location: | ||
# 4、修改图片属性,写入经度和纬度 | ||
exif.write_image(image_path, location[0], location[1]) | ||
print('修改图片地理成功!') | ||
else: | ||
print('请先输入具体地址!') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
#!/usr/bin/env python | ||
# encoding: utf-8 | ||
|
||
""" | ||
@version: v1.0 | ||
@author: xag | ||
@license: Apache Licence | ||
@contact: [email protected] | ||
@site: http://www.xingag.top | ||
@software: PyCharm | ||
@file: position_utils.py | ||
@time: 2019-08-23 17:44 | ||
@description:坐标转换 | ||
""" | ||
|
||
# -*- coding: utf-8 -*- | ||
import math | ||
|
||
x_pi = 3.14159265358979324 * 3000.0 / 180.0 | ||
pi = 3.1415926535897932384626 # π | ||
a = 6378245.0 # 长半轴 | ||
ee = 0.00669342162296594323 # 扁率 | ||
|
||
|
||
def wgs84togcj02(lng, lat): | ||
""" | ||
WGS84转GCJ02(火星坐标系) | ||
:param lng:WGS84坐标系的经度 | ||
:param lat:WGS84坐标系的纬度 | ||
:return: | ||
""" | ||
if out_of_china(lng, lat): # 判断是否在国内 | ||
return lng, lat | ||
dlat = transformlat(lng - 105.0, lat - 35.0) | ||
dlng = transformlng(lng - 105.0, lat - 35.0) | ||
radlat = lat / 180.0 * pi | ||
magic = math.sin(radlat) | ||
magic = 1 - ee * magic * magic | ||
sqrtmagic = math.sqrt(magic) | ||
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi) | ||
dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi) | ||
mglat = lat + dlat | ||
mglng = lng + dlng | ||
return [mglng, mglat] | ||
|
||
|
||
def gcj02towgs84(lng, lat): | ||
""" | ||
GCJ02(火星坐标系)转GPS84 | ||
:param lng:火星坐标系的经度 | ||
:param lat:火星坐标系纬度 | ||
:return: | ||
""" | ||
if out_of_china(lng, lat): | ||
return lng, lat | ||
dlat = transformlat(lng - 105.0, lat - 35.0) | ||
dlng = transformlng(lng - 105.0, lat - 35.0) | ||
radlat = lat / 180.0 * pi | ||
magic = math.sin(radlat) | ||
magic = 1 - ee * magic * magic | ||
sqrtmagic = math.sqrt(magic) | ||
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi) | ||
dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi) | ||
mglat = lat + dlat | ||
mglng = lng + dlng | ||
return [lng * 2 - mglng, lat * 2 - mglat] | ||
|
||
|
||
def transformlat(lng, lat): | ||
ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + \ | ||
0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng)) | ||
ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 * | ||
math.sin(2.0 * lng * pi)) * 2.0 / 3.0 | ||
ret += (20.0 * math.sin(lat * pi) + 40.0 * | ||
math.sin(lat / 3.0 * pi)) * 2.0 / 3.0 | ||
ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 * | ||
math.sin(lat * pi / 30.0)) * 2.0 / 3.0 | ||
return ret | ||
|
||
|
||
def transformlng(lng, lat): | ||
ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \ | ||
0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng)) | ||
ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 * | ||
math.sin(2.0 * lng * pi)) * 2.0 / 3.0 | ||
ret += (20.0 * math.sin(lng * pi) + 40.0 * | ||
math.sin(lng / 3.0 * pi)) * 2.0 / 3.0 | ||
ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 * | ||
math.sin(lng / 30.0 * pi)) * 2.0 / 3.0 | ||
return ret | ||
|
||
|
||
def out_of_china(lng, lat): | ||
""" | ||
判断是否在国内,不在国内不做偏移 | ||
:param lng: | ||
:param lat: | ||
:return: | ||
""" | ||
if lng < 72.004 or lng > 137.8347: | ||
return True | ||
if lat < 0.8293 or lat > 55.8271: | ||
return True | ||
return False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,3 +55,4 @@ | |
## 其他 | ||
|
||
* [使用 Python 定位到女朋友的位置](./获取女友的位置) | ||
* [女朋友背着我,用 Python 偷偷隐藏了她的行踪](./ModifyLocation) |