Skip to content

Commit fc82656

Browse files
committed
修改图片地理位置
1 parent 752f989 commit fc82656

File tree

6 files changed

+372
-0
lines changed

6 files changed

+372
-0
lines changed

Diff for: .DS_Store

4 KB
Binary file not shown.

Diff for: ModifyLocation/.DS_Store

6 KB
Binary file not shown.

Diff for: ModifyLocation/gps_utils.py

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env python
2+
# encoding: utf-8
3+
4+
"""
5+
@version: v1.0
6+
@author: xag
7+
@license: Apache Licence
8+
9+
@site: http://www.xingag.top
10+
@software: PyCharm
11+
@file: gps_utils.py
12+
@time: 2019-11-17 10:34
13+
@description:TODO
14+
"""
15+
16+
import math
17+
18+
19+
def gps_to_dms(gps_data):
20+
"""
21+
坐标转为度、分、秒(double)
22+
116.397451
23+
:param gps_data:
24+
:return:
25+
"""
26+
# 度:向下取整
27+
gps_degree = math.floor(gps_data)
28+
29+
gps_data_temp1 = (gps_data - gps_degree) * 60
30+
31+
# 分
32+
gps_minute = math.floor(gps_data_temp1)
33+
34+
gps_data_temp2 = gps_data_temp1 - gps_minute
35+
36+
# 秒,取小数点后4位
37+
gps_second = round(gps_data_temp2 * 60, 2)
38+
39+
# 注意:秒必须转换为整形
40+
result = ((gps_degree, 1), (gps_minute, 1), (int(gps_second * 100), 100))
41+
42+
return result
43+
44+
45+
def dms_to_gps(dms_data):
46+
"""
47+
度、分、秒转为坐标值(double)
48+
:param dms_data:
49+
:return:
50+
"""
51+
data1 = dms_data[0][0] / dms_data[0][1]
52+
53+
data2 = dms_data[1][0] / dms_data[1][1] / 60
54+
55+
data3 = dms_data[2][0] / dms_data[2][1] / 3600
56+
57+
result = round(data1 + data2 + data3,6)
58+
59+
return result

Diff for: ModifyLocation/main.py

+208
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
#!/usr/bin/env python
2+
# encoding: utf-8
3+
4+
"""
5+
@version: v1.0
6+
@author: xag
7+
@license: Apache Licence
8+
9+
@site: http://www.xingag.top
10+
@software: PyCharm
11+
@file: main.py
12+
@time: 2019-11-16 10:12
13+
@description:修改图片地理位置
14+
"""
15+
16+
import requests
17+
import time
18+
from PIL import Image
19+
import piexif
20+
import json
21+
from gps_utils import *
22+
from position_utils import *
23+
24+
25+
# 依赖:pip3 install piexif
26+
27+
class Exif():
28+
def __init__(self):
29+
self.time = '2019:11:17 14:13:22'
30+
31+
# 地理编码(地址转为经纬度)
32+
self.url_geo = 'https://restapi.amap.com/v3/geocode/geo'
33+
34+
# 逆地理编码(经纬度转为地址)
35+
self.url_regeo = 'https://restapi.amap.com/v3/geocode/regeo?parameters'
36+
37+
# key
38+
self.ak = '你的ak'
39+
40+
# 数字签名
41+
self.sign = '你的sign'
42+
43+
def read_image(self, image_path):
44+
"""
45+
开始处理图片
46+
exifread:读取图片属性
47+
:return:
48+
"""
49+
exif_dict = piexif.load(image_path)
50+
51+
if exif_dict['GPS']:
52+
53+
# 纬度
54+
gps_lati_pre = exif_dict['GPS'][2]
55+
56+
gps_lati = dms_to_gps(gps_lati_pre)
57+
58+
# 经度
59+
gps_long_pre = exif_dict['GPS'][4]
60+
gps_long = dms_to_gps(gps_long_pre)
61+
62+
# GPS坐标转为高德坐标
63+
lng, lat = wgs84togcj02(gps_long, gps_lati)
64+
65+
# print(lng, lat)
66+
67+
print(f"原图地理位置如下\n经度:{lng}\n纬度:{lat}\n")
68+
69+
return f'{lng}, {lat}'
70+
else:
71+
print(f'抱歉!这张图片不包含地理位置!')
72+
73+
def current_time(self):
74+
"""
75+
获取当前时间
76+
:return:
77+
"""
78+
time_now = time.strftime('%Y:%m:%d %H:%M:%S', time.localtime(time.time()))
79+
80+
result = bytes(time_now, encoding='utf-8')
81+
82+
return result
83+
84+
def str_to_bytes(self, str_content):
85+
"""
86+
字符串转bytes
87+
:return:
88+
"""
89+
return bytes(str_content, encoding='utf-8')
90+
91+
def is_image(self, filename):
92+
"""
93+
判断文件是否是一张图片
94+
:param filename:
95+
:return:
96+
"""
97+
file_suffix = filename.split('.')[-1]
98+
99+
if file_suffix == 'jpg' or file_suffix == 'png':
100+
return True
101+
else:
102+
return False
103+
104+
def write_image(self, image_path, gps_long, gps_lati):
105+
"""
106+
修改文件夹下所有文件的属性
107+
:param image_path: 文件夹路径
108+
:return:
109+
"""
110+
# 读取图片
111+
img = Image.open(image_path)
112+
113+
try:
114+
exif_dict = piexif.load(img.info['exif'])
115+
except:
116+
print('加载文件地理位置异常!')
117+
return
118+
119+
# 修改地理位置
120+
# GPS GPSLatitudeRef:N
121+
# GPS GPSLatitude:[22, 32, 189/20]
122+
# GPS GPSLongitudeRef:E
123+
# GPS GPSLongitude:[114, 1, 689/20]
124+
exif_dict['GPS'][2] = gps_to_dms(gps_lati)
125+
exif_dict['GPS'][4] = gps_to_dms(gps_long)
126+
127+
exif_bytes = piexif.dump(exif_dict)
128+
129+
# 写入到新的图片中去
130+
img.save(image_path, 'jpeg', exif=exif_bytes)
131+
132+
def get_address_by_location(self, location):
133+
"""
134+
通过经纬度拿到地理位置
135+
:param location:
136+
:return:
137+
"""
138+
params = {
139+
'key': self.ak,
140+
'location': location,
141+
'sig': self.sign
142+
}
143+
144+
resp = json.loads(requests.get(url=self.url_regeo, params=params).text)
145+
146+
if resp and resp.get('regeocode') and resp.get('regeocode').get('formatted_address'):
147+
address = resp.get('regeocode').get('formatted_address')
148+
print(f'原图的拍摄地址为:{address}\n')
149+
else:
150+
print('api解析地址出错,请检查ak!\n')
151+
152+
def get_location_by_address(self, city, address):
153+
"""
154+
通过地理位置到拿到经纬度
155+
地理编码:https://lbs.amap.com/api/webservice/guide/api/georegeo/
156+
:param address:
157+
:return:
158+
"""
159+
params = {
160+
'key': self.ak,
161+
'city': city,
162+
'address': address,
163+
'sig': self.sign
164+
}
165+
166+
resp = json.loads(requests.get(url=self.url_geo, params=params).text)
167+
168+
# 获取坐标地址
169+
if resp and len(resp.get('geocodes')) >= 1 and resp.get('geocodes')[0].get('location'):
170+
location = resp.get('geocodes')[0].get('location')
171+
gps_data = location.split(',')
172+
173+
# 得到经度和纬度
174+
gps_long = float(gps_data[0])
175+
gps_lati = float(gps_data[1])
176+
177+
return gps_long, gps_lati
178+
else:
179+
print('api解析地址出错,请检查ak!')
180+
return None
181+
182+
183+
if __name__ == '__main__':
184+
exif = Exif()
185+
186+
image_path = './WechatIMG1439.jpeg'
187+
188+
# 1、读取原图的属性
189+
location = exif.read_image(image_path)
190+
191+
if location:
192+
# 2、原图的详细地址
193+
exif.get_address_by_location(location)
194+
195+
# 3、输入地址(市+目的地,例如:深圳莲花山公园)
196+
city = input('请输入定位城市(例如:深圳):')
197+
address = input('请输入具体的定位地址(例如:莲花山公园):')
198+
199+
if address:
200+
# 通过地址拿到坐标地址
201+
location = exif.get_location_by_address(city, address)
202+
203+
if location:
204+
# 4、修改图片属性,写入经度和纬度
205+
exif.write_image(image_path, location[0], location[1])
206+
print('修改图片地理成功!')
207+
else:
208+
print('请先输入具体地址!')

Diff for: ModifyLocation/position_utils.py

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env python
2+
# encoding: utf-8
3+
4+
"""
5+
@version: v1.0
6+
@author: xag
7+
@license: Apache Licence
8+
9+
@site: http://www.xingag.top
10+
@software: PyCharm
11+
@file: position_utils.py
12+
@time: 2019-08-23 17:44
13+
@description:坐标转换
14+
"""
15+
16+
# -*- coding: utf-8 -*-
17+
import math
18+
19+
x_pi = 3.14159265358979324 * 3000.0 / 180.0
20+
pi = 3.1415926535897932384626 # π
21+
a = 6378245.0 # 长半轴
22+
ee = 0.00669342162296594323 # 扁率
23+
24+
25+
def wgs84togcj02(lng, lat):
26+
"""
27+
WGS84转GCJ02(火星坐标系)
28+
:param lng:WGS84坐标系的经度
29+
:param lat:WGS84坐标系的纬度
30+
:return:
31+
"""
32+
if out_of_china(lng, lat): # 判断是否在国内
33+
return lng, lat
34+
dlat = transformlat(lng - 105.0, lat - 35.0)
35+
dlng = transformlng(lng - 105.0, lat - 35.0)
36+
radlat = lat / 180.0 * pi
37+
magic = math.sin(radlat)
38+
magic = 1 - ee * magic * magic
39+
sqrtmagic = math.sqrt(magic)
40+
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
41+
dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
42+
mglat = lat + dlat
43+
mglng = lng + dlng
44+
return [mglng, mglat]
45+
46+
47+
def gcj02towgs84(lng, lat):
48+
"""
49+
GCJ02(火星坐标系)转GPS84
50+
:param lng:火星坐标系的经度
51+
:param lat:火星坐标系纬度
52+
:return:
53+
"""
54+
if out_of_china(lng, lat):
55+
return lng, lat
56+
dlat = transformlat(lng - 105.0, lat - 35.0)
57+
dlng = transformlng(lng - 105.0, lat - 35.0)
58+
radlat = lat / 180.0 * pi
59+
magic = math.sin(radlat)
60+
magic = 1 - ee * magic * magic
61+
sqrtmagic = math.sqrt(magic)
62+
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
63+
dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
64+
mglat = lat + dlat
65+
mglng = lng + dlng
66+
return [lng * 2 - mglng, lat * 2 - mglat]
67+
68+
69+
def transformlat(lng, lat):
70+
ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + \
71+
0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
72+
ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
73+
math.sin(2.0 * lng * pi)) * 2.0 / 3.0
74+
ret += (20.0 * math.sin(lat * pi) + 40.0 *
75+
math.sin(lat / 3.0 * pi)) * 2.0 / 3.0
76+
ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *
77+
math.sin(lat * pi / 30.0)) * 2.0 / 3.0
78+
return ret
79+
80+
81+
def transformlng(lng, lat):
82+
ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \
83+
0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
84+
ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
85+
math.sin(2.0 * lng * pi)) * 2.0 / 3.0
86+
ret += (20.0 * math.sin(lng * pi) + 40.0 *
87+
math.sin(lng / 3.0 * pi)) * 2.0 / 3.0
88+
ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *
89+
math.sin(lng / 30.0 * pi)) * 2.0 / 3.0
90+
return ret
91+
92+
93+
def out_of_china(lng, lat):
94+
"""
95+
判断是否在国内,不在国内不做偏移
96+
:param lng:
97+
:param lat:
98+
:return:
99+
"""
100+
if lng < 72.004 or lng > 137.8347:
101+
return True
102+
if lat < 0.8293 or lat > 55.8271:
103+
return True
104+
return False

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,4 @@
5555
## 其他
5656

5757
* [使用 Python 定位到女朋友的位置](./获取女友的位置)
58+
* [女朋友背着我,用 Python 偷偷隐藏了她的行踪](./ModifyLocation)

0 commit comments

Comments
 (0)