代码仓库
https://github.com/Dongvdong/v1_1_slam_tool
主要有两个库
1正常的库 获取经纬度 但是无法获取云台和飞机姿态
2 2进制模式读取可以获取更多信息,但是读取的高度有精度损失。
# -*- coding: utf-8 -*- # conda activate py37gaosi # 服务器 # activate py38 # 笔记本 import os import numpy as np #改进检测地区 import os import exifread import re import sys import requests import json # 遍历文件夹及子文件夹中的所有图片,逐个文件读取exif信息 ''' def get_pic_GPS(pic_dir): items = os.listdir(pic_dir) for item in items: path = os.path.join(pic_dir, item) if os.path.isdir(path): get_pic_GPS(path) else: imageread(path) ''' def convert_altitude_to_decimal(altitude): #print(altitude) try: # 可能会抛出异常的代码 a, b = altitude.strip().split('/') #print(f"a:{a},b:{b}") return float(a)/float(b) except ValueError as e: #print(f"不存在‘/’") #print(altitude) # 这里可以继续执行其他代码 return float(altitude) # 将经纬度转换为小数形式 def convert_to_decimal(*gps): # 度 if '/' in gps[0]: deg = gps[0].split('/') if deg[0] == '0' or deg[1] == '0': gps_d = 0 else: gps_d = float(deg[0]) / float(deg[1]) else: gps_d = float(gps[0]) # 分 if '/' in gps[1]: minu = gps[1].split('/') if minu[0] == '0' or minu[1] == '0': gps_m = 0 else: gps_m = (float(minu[0]) / float(minu[1])) / 60 else: gps_m = float(gps[1]) / 60 # 秒 if '/' in gps[2]: sec = gps[2].split('/') if sec[0] == '0' or sec[1] == '0': gps_s = 0 else: gps_s = (float(sec[0]) / float(sec[1])) / 3600 else: gps_s = float(gps[2]) / 3600 decimal_gps = gps_d + gps_m + gps_s # 如果是南半球或是西半球 if gps[3] == 'W' or gps[3] == 'S' or gps[3] == "83" or gps[3] == "87": return str(decimal_gps * -1) else: return str(decimal_gps) ''' # 如果提取 图像信息不需要机身自讨 精度更高 Image ImageDescription Image Make Image Model Image Orientation Image XResolution Image YResolution Image ResolutionUnit Image Software Image DateTime Image YCbCrPositioning Image ExifOffset GPS GPSVersionID GPS GPSLatitudeRef GPS GPSLatitude GPS GPSLongitudeRef GPS GPSLongitude GPS GPSAltitudeRef GPS GPSAltitude Image GPSInfo Image XPComment Image XPKeywords Thumbnail Compression Thumbnail XResolution Thumbnail YResolution Thumbnail ResolutionUnit Thumbnail JPEGInterchangeFormat Thumbnail JPEGInterchangeFormatLength EXIF ExposureTime EXIF FNumber EXIF ExposureProgram EXIF ISOSpeedRatings EXIF ExifVersion EXIF DateTimeOriginal EXIF DateTimeDigitized EXIF ComponentsConfiguration EXIF CompressedBitsPerPixel EXIF ShutterSpeedValue EXIF ApertureValue EXIF ExposureBiasValue EXIF MaxApertureValue EXIF SubjectDistance EXIF MeteringMode EXIF LightSource EXIF Flash EXIF FocalLength EXIF MakerNote EXIF FlashPixVersion EXIF ColorSpace EXIF ExifImageWidth EXIF ExifImageLength Interoperability InteroperabilityIndex Interoperability InteroperabilityVersion EXIF InteroperabilityOffset EXIF ExposureIndex EXIF FileSource EXIF SceneType EXIF CustomRendered EXIF ExposureMode EXIF WhiteBalance EXIF DigitalZoomRatio EXIF FocalLengthIn35mmFilm EXIF SceneCaptureType EXIF GainControl EXIF Contrast EXIF Saturation EXIF Sharpness EXIF SubjectDistanceRange EXIF BodySerialNumber ''' # 读取图片的经纬度和拍摄时间 def Api_1_1Get_ImageGPS(path): f = open(path, 'rb') GPS = {} gps_=[-1,-1,-1] try: tags = exifread.process_file(f) except: return gps_ #print(tags) #for tag in tags: # print(str(tag),str(tags[str(tag)])) # 南北半球标识 if 'GPS GPSLatitudeRef' in tags: GPS['GPSLatitudeRef'] = str(tags['GPS GPSLatitudeRef']) # print(GPS['GPSLatitudeRef']) else: GPS['GPSLatitudeRef'] = 'N' # 缺省设置为北半球 # 东西半球标识 if 'GPS GPSLongitudeRef' in tags: GPS['GPSLongitudeRef'] = str(tags['GPS GPSLongitudeRef']) # print(GPS['GPSLongitudeRef']) else: GPS['GPSLongitudeRef'] = 'E' # 缺省设置为东半球 # 海拔高度标识 if 'GPS GPSAltitudeRef' in tags: GPS['GPSAltitudeRef'] = str(tags['GPS GPSAltitudeRef']) # 获取纬度 if 'GPS GPSLatitude' in tags: lat = str(tags['GPS GPSLatitude']) # 处理无效值 if lat == '[0, 0, 0]' or lat == '[0/0, 0/0, 0/0]': GPS['GPSLatitude']=-1 else: deg, minu, sec = [x.replace(' ', '') for x in lat[1:-1].split(',')] # 将纬度转换为小数形式 GPS['GPSLatitude'] = convert_to_decimal(deg, minu, sec, GPS['GPSLatitudeRef']) # 获取经度 if 'GPS GPSLongitude' in tags: lng = str(tags['GPS GPSLongitude']) # print(lng) # 处理无效值 if lng == '[0, 0, 0]' or lng == '[0/0, 0/0, 0/0]': GPS['GPSLongitude']=-1 else: deg, minu, sec = [x.replace(' ', '') for x in lng[1:-1].split(',')] # 将经度转换为小数形式 GPS['GPSLongitude'] = convert_to_decimal(deg, minu, sec, GPS['GPSLongitudeRef']) # 对特殊的经纬度格式进行处理 # 获取海拔高度 if 'GPS GPSAltitude' in tags: height = str(tags["GPS GPSAltitude"]) GPS['GPSAltitude'] = convert_altitude_to_decimal(height) # if 'GPS RelativeAltitude' in tags: # height = str(tags["GPS RelativeAltitude"]) # GPS['RelativeAltitude'] = convert_altitude_to_decimal(height) # 获取图片拍摄时间 # if 'Image DateTime' in tags: # GPS["DateTime"] = str(tags["Image DateTime"]) # print(GPS["DateTime"]) # elif "EXIF DateTimeOriginal" in tags: # GPS["DateTime"] = str(tags["EXIF DateTimeOriginal"]) # print(GPS["DateTime"]) # if 'Image Make' in tags: # print('照相机制造商:', tags['Image Make']) # if 'Image Model' in tags: # print('照相机型号:', tags['Image Model']) # if 'Image ExifImageWidth' in tags: # print('照片尺寸:', tags['EXIF ExifImageWidth'],tags['EXIF ExifImageLength']) gps_=[float(GPS['GPSLatitude']) ,float(GPS['GPSLongitude']), float(GPS['GPSAltitude'])] #print(gps_) return gps_ ''' # 如果需要提取相机字条和机身姿态 读取信息查看 tiff:Make="DJI" tiff:Model="FC6310R" dc:format="image/jpg" drone-dji:AbsoluteAltitude="+514.64" drone-dji:RelativeAltitude="+100.09" drone-dji:GpsLatitude="34.03250565" drone-dji:GpsLongtitude="108.76779926" drone-dji:GimbalRollDegree="+0.00" 拍照时刻云台的Roll 欧拉角 drone-dji:GimbalYawDegree="+93.50" drone-dji:GimbalPitchDegree="-89.90" drone-dji:FlightRollDegree="+2.10" 拍照时刻飞行器机体的Roll 欧拉角 drone-dji:FlightYawDegree="+93.50" drone-dji:FlightPitchDegree="+1.00" drone-dji:FlightXSpeed="+0.00" drone-dji:FlightYSpeed="+0.00" drone-dji:FlightZSpeed="+0.00" drone-dji:CamReverse="0" drone-dji:GimbalReverse="0" drone-dji:SelfData="Undefined" drone-dji:CalibratedFocalLength="3666.666504" 焦距 drone-dji:CalibratedOpticalCenterX="2736.000000" drone-dji:CalibratedOpticalCenterY="1824.000000" drone-dji:RtkFlag="50" drone-dji:RtkStdLon="0.01117" drone-dji:RtkStdLat="0.01132" drone-dji:RtkStdHgt="0.02493" drone-dji:DewarpFlag="1" drone-dji:PhotoDiff="" crs:Version="7.0" crs:HasSettings="False" crs:HasCrop="False" crs:AlreadyApplied="False"> </rdf:Description> ''' # 读取单个照片的 gps信息 这个方法有问题 读取高度精度损失 def Api_1_2Get_Image_AllInfo(file_path): b = b"\x3c\x2f\x72\x64\x66\x3a\x44\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x3e" a = b"\x3c\x72\x64\x66\x3a\x44\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x20" aa=["\x3c\x72\x64\x66\x3a\x44\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x20"] bb=["\x3c\x2f\x72\x64\x66\x3a\x44\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x3e"] #xml format to save EXIF的数据规范 # aa ['<rdf:Description '] #print("aa",aa) # bb ['</rdf:Description>'] #print("bb",bb) # rb是读取二进制文件 img = open(file_path, 'rb') # bytearray() 方法返回一个新字节数组 data = bytearray() #标识符, flag = False for i in img.readlines(): # 按行读取二进制信息,标签成对出现 if a in i: flag = True if flag: #把第i行数据复制到新数组中 data += i if b in i: break #print("======大疆精灵4照片中原始数据 =======\n",data) if len(data) > 0: data = str(data.decode('ascii'))#ascii #print(data) #filter()函数用于过滤序列,过滤掉不符合条件的元素,返回符合条件的元素组成新列表。 #filter(function,iterable) ,function -- 判断函数。iterable -- 可迭代对象 #python允许用lambda关键字创造匿名函数。 # 在 lambda 关键字之后、冒号左边为参数列表,可不带参数,也可有多个参数。若有多个参数,则参数间用逗号隔开,冒号右边为 lambda 表达式的返回值。 #left--->right # judge condition 'drone-dji:' in x lines = list(filter(lambda x: 'drone-dji:' in x, data.split("\n"))) #print("lines",lines) dj_data_dict = {} for d in lines: # remove 'drone-dji:' d = d.strip()[10:] # k is name # v is value k, v = d.split("=") v=v.replace('\"','') #print(k, v) dj_data_dict[k] = v return dj_data_dict else: dj_data_dict="error" def Api_2Get_Image_GPS(img_path): #img_name=img_path[img_path.rfind('/')+1:img_path.rfind('.')]# 去掉后缀 #print(img_name) dj_data_dict=Api_1_1Get_ImageGPS(img_path) GPS_lat_lon_h=[-1,-1,-1] if dj_data_dict !="error": #dj_data_dict['GpsLatitude'] # 这种方法会损失高度 #dj_data_dict['GpsLongtitude'] #dj_data_dict['RelativeAltitude'] lat=float(dj_data_dict[0]) lon=float(dj_data_dict[1]) absh=float(dj_data_dict[2]) GPS_lat_lon_h=[lat,lon,absh] #print(GPS) return GPS_lat_lon_h # 遍历文件夹读取照片的GPS 高度保留厘米 def API_read_directory(img_path_dir): Gnss_list=[] for filename in os.listdir(img_path_dir): file_dir_name=img_path_dir+filename #print(filename) GPS_lat_lon_h=Api_2Get_Image_GPS(file_dir_name) gnss_temp=[] gnss_temp.append(filename) gnss_temp.append(GPS_lat_lon_h[0]) gnss_temp.append(GPS_lat_lon_h[1]) gnss_temp.append(GPS_lat_lon_h[2]) #print("1 照片读取到的GNSS",gnss_temp) Gnss_list.append(gnss_temp) return Gnss_list def API_Save2txt(GPS_txt_name,Gnss_list): with open(GPS_txt_name, 'w') as file: for row in Gnss_list: line = ' '.join(map(str, row)) file.write(f"{line}\n") print(GPS_txt_name,"保存成功") def API_read2txt(GPS_txt_name): print(GPS_txt_name,"读取txt数据成功") Gnss_list = [] with open(GPS_txt_name, 'r') as file: for line in file: row = list(map(str, line.split())) Gnss_list.append(row) #print(row) return Gnss_list #====================测试======================== ''' if __name__ == "__main__": # 参数 # 0-1 gps照片路径 img_path_dir="E:/v0_Project/V0_Mybao/v8_slam/python工具/0测试数据/d1_100mRTKColmap/images/gps_images/" # 0-2 txt保存的名字 GPS_txt_name="GPS.txt" # 1读取数据 Gnss_list=API_read_directory(img_path_dir) # 2保存txt 格式: name lat lon h API_Save2txt(GPS_txt_name,Gnss_list) # 3读取txt 格式: name lat lon h Gnss_list_Read = API_read2txt(GPS_txt_name) '''
数据格式
DJI_0002.JPG 34.03250563926396 108.7677992500047 514.6380141189607 DJI_0005.JPG 34.03267641704175 108.76781155556024 514.4640141184373 DJI_0011.JPG 34.03394725037507 108.76789833333802 514.635014120011 DJI_0015.JPG 34.03487661148619 108.76796561111581 514.6420141205874 DJI_0018.JPG 34.03509530593064 108.76797844444913 514.6150141188659 DJI_0022.JPG 34.035064472597305 108.76773913889359 514.58201412093 DJI_0025.JPG 34.03463080593064 108.76770336111582 514.6600141209601 DJI_0028.JPG 34.03403180593064 108.76765755556025 514.5780141181838 DJI_0031.JPG 34.033382778152856 108.76761005556025 514.5470141202469 DJI_0035.JPG 34.032533167041734 108.7675511111158 514.6610141190716 DJI_0041.JPG 34.03248758370841 108.7671833611158 514.8310141174146 DJI_0042.JPG 34.03248605593062 108.76717719444913 514.781014119351
标签:读取,EXIF,tags,drone,GNSS,slam,dji,GPS,gps From: https://www.cnblogs.com/gooutlook/p/18253338