66import numpy as np
77import math
88import os
9+ from datetime import datetime
910
1011def rad_to_deg (rad ):
1112 """Convert radians to degrees"""
@@ -41,8 +42,8 @@ def interpolate_position(gnss_times, gnss_data, target_time):
4142 # Convert to degrees
4243 return rad_to_deg (lat_rad ), rad_to_deg (lon_rad )
4344
44- def convert_gps_to_exif_format (latitude , longitude ):
45- """Convert GPS coordinates to EXIF format"""
45+ def convert_gps_to_exif_format (latitude , longitude , altitude ):
46+ """Convert GPS coordinates and altitude to EXIF format"""
4647 def decimal_to_dms (decimal ):
4748 decimal = float (decimal )
4849 degrees = int (decimal )
@@ -55,7 +56,12 @@ def decimal_to_dms(decimal):
5556 lat_ref = 'N' if latitude >= 0 else 'S'
5657 lon_ref = 'E' if longitude >= 0 else 'W'
5758
58- return lat_dms , lon_dms , lat_ref , lon_ref
59+ # Convert altitude to EXIF format (rational number)
60+ alt_ref = 0 if altitude >= 0 else 1 # 0 = above sea level, 1 = below sea level
61+ altitude = abs (altitude )
62+ alt_ratio = (int (altitude * 100 ), 100 ) # Multiply by 100 for 2 decimal precision
63+
64+ return lat_dms , lon_dms , lat_ref , lon_ref , alt_ratio , alt_ref
5965
6066# Create images directory if it doesn't exist
6167os .makedirs ('images' , exist_ok = True )
@@ -95,18 +101,54 @@ def decimal_to_dms(decimal):
95101 image_time = t .to_sec ()
96102 lat , lon = interpolate_position (gnss_times , gnss_messages , image_time )
97103
104+ # Get altitude from GNSS message (you'll need to interpolate this as well)
105+ altitude = gnss_messages [np .searchsorted (gnss_times , image_time )].height
106+
98107 # Convert GPS coordinates to EXIF format
99- lat_dms , lon_dms , lat_ref , lon_ref = convert_gps_to_exif_format (lat , lon )
108+ lat_dms , lon_dms , lat_ref , lon_ref , alt_ratio , alt_ref = convert_gps_to_exif_format (lat , lon , altitude )
109+
110+ timestamp = datetime .fromtimestamp (t .to_sec ())
100111
101- # Create EXIF data
102112 exif_dict = {
103- "GPS" : {
104- piexif .GPSIFD .GPSLatitudeRef : lat_ref .encode (),
105- piexif .GPSIFD .GPSLatitude : lat_dms ,
106- piexif .GPSIFD .GPSLongitudeRef : lon_ref .encode (),
107- piexif .GPSIFD .GPSLongitude : lon_dms
108- }
113+ "0th" : {
114+ piexif .ImageIFD .Make : "FLIR" .encode (),
115+ piexif .ImageIFD .Model : "Blackfly S BFS-U3-16S2C" .encode (),
116+ piexif .ImageIFD .Software : "ROS" .encode (),
117+ piexif .ImageIFD .DateTime : timestamp .strftime ("%Y:%m:%d %H:%M:%S" ).encode (),
118+ piexif .ImageIFD .ImageDescription : "Captured with ROS and FLIR Blackfly S" .encode (),
119+ piexif .ImageIFD .XResolution : (msg .width , 1 ),
120+ piexif .ImageIFD .YResolution : (msg .height , 1 ),
121+ piexif .ImageIFD .ResolutionUnit : 2 , # inches
122+ },
123+ "Exif" : {
124+ piexif .ExifIFD .DateTimeOriginal : timestamp .strftime ("%Y:%m:%d %H:%M:%S" ).encode (),
125+ piexif .ExifIFD .DateTimeDigitized : timestamp .strftime ("%Y:%m:%d %H:%M:%S" ).encode (),
126+ piexif .ExifIFD .ExposureTime : (1 , 100 ), # 1/100 second
127+ piexif .ExifIFD .FNumber : (16 , 10 ), # f/1.6
128+ piexif .ExifIFD .ExposureProgram : 1 , # Manual
129+ piexif .ExifIFD .ISOSpeedRatings : 100 ,
130+ piexif .ExifIFD .ExifVersion : b'0230' ,
131+ piexif .ExifIFD .ComponentsConfiguration : b'\x01 \x02 \x03 \x00 ' , # RGB
132+ piexif .ExifIFD .FocalLength : (16 , 1 ), # 16mm
133+ piexif .ExifIFD .ColorSpace : 1 , # sRGB
134+ piexif .ExifIFD .PixelXDimension : msg .width ,
135+ piexif .ExifIFD .PixelYDimension : msg .height ,
136+ piexif .ExifIFD .ExposureMode : 1 , # Manual exposure
137+ piexif .ExifIFD .WhiteBalance : 1 , # Manual white balance
138+ piexif .ExifIFD .SceneCaptureType : 0 , # Standard
139+ },
140+ "GPS" : {
141+ piexif .GPSIFD .GPSLatitudeRef : lat_ref .encode (),
142+ piexif .GPSIFD .GPSLatitude : lat_dms ,
143+ piexif .GPSIFD .GPSLongitudeRef : lon_ref .encode (),
144+ piexif .GPSIFD .GPSLongitude : lon_dms ,
145+ piexif .GPSIFD .GPSAltitudeRef : alt_ref ,
146+ piexif .GPSIFD .GPSAltitude : alt_ratio ,
147+ piexif .GPSIFD .GPSTimeStamp : tuple (map (lambda x : (int (x ), 1 ), timestamp .strftime ("%H:%M:%S" ).split (":" ))),
148+ piexif .GPSIFD .GPSDateStamp : timestamp .strftime ("%Y:%m:%d" ).encode (),
149+ piexif .GPSIFD .GPSVersionID : (2 , 3 , 0 , 0 ),
109150 }
151+ }
110152
111153 # Convert to bytes
112154 exif_bytes = piexif .dump (exif_dict )
0 commit comments