本文主要写技术验证:读取普通手机图片信息,提取经纬度信息。 在地理信息系统中,获取精确的地理位置数据对于各种分析至关重要。随着数码摄影的普及,越来越多的照片包含了EXIF元数据,其中就包含了拍摄地点的GPS信息。只要你的手机(无人机)开启了GPS定位,那么拍摄的图片就会包含GPS信息。 本文将介绍如何使用Python编程语言从照片中提取这些GPS信息,并将其转换为Shapefile文件,以便在GIS软件中进行进一步的分析和处理。 一、准备工作在开始之前,需要确保已经安装了以下Python库: PIL(或Pillow):用于处理图像文件。 pyshp:用于读写Shapefile文件。
可以使用pip来安装这些库: pip install pillow pyshp 二、提取信息首先,我们需要编写一个函数来从照片中提取EXIF元数据中的GPS信息。这个函数将打开照片文件,解析EXIF标签,并提取出经度和纬度信息。 from PIL import Image def exif(img): ''' 从图片中返回EXIF元数据 ''' exif_data = {}
try: i = Image.open(img) # 使用PIL库打开图片 tags = i._getexif() # 获取图片的EXIF标签
for tag, value in tags.items(): decoded = TAGS.get(tag, tag) # 尝试从预定义的TAGS字典中获取标签的中文描述,否则使用标签ID exif_data[decoded] = value # 将标签及其值存储到exif_data字典中
except: pass # 捕获所有异常并忽略,这通常不是一个好的做法,应该明确指定要捕获的异常
return exif_data 三、GPS信息清洗由于EXIF中的GPS信息是以度、分、秒(DMS)的格式存储的,并且可能包含方向信息(东、西、南、北),我们需要编写一个函数dms2dd() 来将这些信息转换为十进制度(DD)的格式。 def dms2dd(d, m, s, direction): ''' 将度分秒格式转换为十进制度格式 ''' sec = float((m * 60) + s) dec = float(sec / 3600) deg = float(d + dec) if direction.upper() == 'W' or direction.upper() == 'S': deg = deg * -1 return float(deg) 接下来,我们需要编写一个函数gps() 来解析EXIF元数据中的GPS信息,并返回经度和纬度值。这个函数将首先检查是否存在GPSInfo标签,然后提取度、分、秒和方向信息,并使用dms2dd() 函数进行转换。 def gps(exif_data): ''' 从EXIF数据中提取GPS信息并转换为十进制度格式 ''' lat = None lon = None if exif_data and 'GPSInfo' in exif_data: # 这里省略了详细的GPSInfo解析过程,因为它涉及多个EXIF标签的组合 # ... # 假设我们已经从exif_data中提取了经纬度信息(度、分、秒和方向) # 这里只是模拟赋值 lat_d, lat_m, lat_s, lat_dir = (30, 15, 30, 'N') lon_d, lon_m, lon_s, lon_dir = (120, 20, 45, 'E') lat = dms2dd(lat_d, lat_m, lat_s, lat_dir) lon = dms2dd(lon_d, lon_m, lon_s, lon_dir) return lat, lon 四、将GPS信息转换为Shapefile格式一旦我们从照片中提取了GPS信息,就可以将其转换为Shapefile文件,这是一种常用于地理信息系统中的矢量数据格式。我们将使用Python的pyshp 库来创建Shapefile文件。 首先,我们需要编写一个函数gps_to_shapefile() 来遍历指定目录下的所有照片文件,提取GPS信息,并创建一个包含这些信息的Shapefile文件。 photos = {} photo_dir = '.\photos'
# 查找指定目录下的所有JPG照片 files = glob.glob(os.path.join(photo_dir, '*.jpg'))
# 从文件中提取GPS元数据 for f in files: e = exif(f) lat, lon = gps(e) photos[f] = [lon, lat] # 注意:这里通常经度在前,纬度在后,但此处按照您的代码保持原样
# 构建一个包含照片文件名作为属性的点shapefile with shapefile.Writer('photos1', shapefile.POINT) as w: w.field('NAME', 'C', 80) # 创建一个名为NAME的字符型字段,最大长度为80
for f, coords in photos.items(): w.point(*coords) # 使用经度和纬度(注意顺序)创建一个点要素 w.record(f) # 为点要素添加文件名属性 五、完整代码import glob import os try: import Image import ImageDraw except: from PIL import Image from PIL.ExifTags import TAGS import shapefile
def exif(img): ''' 从图片中返回EXIF元数据 ''' exif_data = {}
try: i = Image.open(img) # 使用PIL库打开图片 tags = i._getexif() # 获取图片的EXIF标签
for tag, value in tags.items(): decoded = TAGS.get(tag, tag) # 尝试从预定义的TAGS字典中获取标签的中文描述,否则使用标签ID exif_data[decoded] = value # 将标签及其值存储到exif_data字典中
except: pass # 捕获所有异常并忽略,这通常不是一个好的做法,应该明确指定要捕获的异常
return exif_data
def dms2dd(d, m, s, i): ''' 将度/分/秒转换为十进制度 ''' sec = float((m * 60) + s) # 将分和秒转换为秒 dec = float(sec / 3600) # 将秒转换为小数度 deg = float(d + dec) # 将度和小数度相加
if i.upper() == 'W': # 如果方向是西 deg = deg * -1 # 将度数变为负数
elif i.upper() == 'S': # 如果方向是南 deg = deg * -1 # 将度数变为负数
return float(deg)
def gps(exif): ''' 从EXIF元数据中提取GPS信息 ''' lat = None # 纬度 lon = None # 经度
if exif.get('GPSInfo'): # 如果EXIF中包含GPS信息 # 纬度 coords = exif['GPSInfo'] i = coords[1] # 纬度方向(N/S) d = coords[2][0] # 纬度度数 m = coords[2][1] # 纬度分钟 s = coords[2][2] # 纬度秒 lat = dms2dd(d, m, s, i) # 将纬度转换为十进制度
# 经度 i = coords[3] # 经度方向(E/W) d = coords[4][0] # 经度度数 m = coords[4][1] # 经度分钟 s = coords[4][2] # 经度秒 lon = dms2dd(d, m, s, i) # 将经度转换为十进制度
return lat, lon
if __name__ == '__main__': # 存储照片文件名和GPS坐标的字典 photos = {} photo_dir = '.\photos'
# 查找指定目录下的所有JPG照片 files = glob.glob(os.path.join(photo_dir, '*.jpg'))
# 从文件中提取GPS元数据 for f in files: e = exif(f) lat, lon = gps(e) photos[f] = [lon, lat] # 注意:这里通常经度在前,纬度在后,但此处按照您的代码保持原样
# 构建一个包含照片文件名作为属性的点shapefile with shapefile.Writer('photos1', shapefile.POINT) as w: w.field('NAME', 'C', 80) # 创建一个名为NAME的字符型字段,最大长度为80
for f, coords in photos.items(): w.point(*coords) # 使用经度和纬度(注意顺序)创建一个点要素 w.record(f) # 为点要素添加文件名属性
结果在arcgis打开,如下: ![图片](http://image109.360doc.com/DownloadImg/2024/05/2415/284023962_1_2024052403494320.png)
现在只是读取普通的图片,获取它的GPS位置信息。下一步目的是: 1、对无人机照片校正。 2、把图片格式转为KMZ格式,放到谷歌地球上显示。 今天先到这里,再会。 ![图片](http://image109.360doc.com/DownloadImg/2024/05/2415/284023962_2_20240524034943145.gif)
|