Bugfix/metadata utctime error negative subsec
Casting f"0.self.get_time('EXIF:SubSecTime')" directly causes ValueError as the string to be casted is in the format '0.-nnnnnn'.
Hi, when did this occur with which camera? With our MicaSense RedEdge-P this is working fine.
How are you processing the images?
Hi,
when did this occur with which camera?
I encountered this issue in March 2025, however, the image set is quite old from RedEdge-M (the red body) camera taken in 2018. I've also included the set in my unit test commit
Note: This commit eeaf6e86d505acc74f0c5a6dab7269f5333b824c introduced the type casting f"0.self.get_time('EXIF:SubSecTime')".
How are you processing the images?
- I cloned the repository and use the micasense code as a python module
- I use Python 3.10.15 installed via pyenv
- Here's the code snippet that I ran.
import micasense.capture as capture
import micasense.imageutils as imageutils
def get_image_type_and_irradiance(the_capture, panel_cap):
"""
Determine if the output image should be "reflectance" or "radiance"
and compute the irradiance list using panel capture if available.
"""
if panel_cap is not None:
if panel_cap.panel_albedo() is not None:
panel_reflectance_by_band = panel_cap.panel_albedo()
else:
panel_reflectance_by_band = [0.49] * len(
the_capture.eo_band_names()
) # RedEdge band_index order
irradiance_list = panel_cap.panel_irradiance(panel_reflectance_by_band) + [0]
# prevent negative irradiance
irradiance_list = np.abs(irradiance_list).tolist()
the_capture.plot_undistorted_reflectance(irradiance_list)
return "reflectance", irradiance_list
else:
if the_capture.dls_present():
irradiance_list = the_capture.dls_irradiance() + [0]
# prevent negative irradiance
irradiance_list = np.abs(irradiance_list).tolist()
the_capture.plot_undistorted_reflectance(irradiance_list)
return "reflectance", irradiance_list
else:
the_capture.plot_undistorted_radiance()
return "radiance", None
def align_non_panchro_capture(
the_capture,
warp_matrices,
img_type,
match_index,
pyramid_levels,
max_alignment_iterations,
warp_mode,
regenerate=True,
multithreaded=False,
):
"""
For non-panchromatic cameras, align the capture using OpenCV.
"""
st = time.time()
# Set regenerate flag to force creation of new warp matrices (or use already loaded ones)
if warp_matrices and not regenerate:
print("Using existing warp matrices...")
else:
print("Aligning images...")
warp_matrices, alignment_pairs = imageutils.align_capture(
the_capture,
ref_index=match_index,
max_iterations=max_alignment_iterations,
warp_mode=warp_mode,
pyramid_levels=pyramid_levels,
multithreaded=multithreaded,
)
print("Finished aligning")
et = time.time()
print("Alignment time:", int(et - st), "seconds")
cropped_dimensions, edges = imageutils.find_crop_bounds(
the_capture, warp_matrices, warp_mode=warp_mode, reference_band=match_index
)
print("Cropped dimensions:", cropped_dimensions)
im_aligned = the_capture.create_aligned_capture(
warp_matrices=warp_matrices, motion_type=warp_mode, img_type=img_type
)
return im_aligned, warp_matrices
main():
image_names = [
'/path/to/IMG_0008_1.tif',
'/path/to/IMG_0008_2.tif',
'/path/to/IMG_0008_3.tif',
'/path/to/IMG_0008_4.tif',
'/path/to/IMG_0008_5.tif'
]
warp_matrices = None
regenerate = True
sharpened_stack = None
warp_mode = cv2.MOTION_HOMOGRAPHY
max_alignment_iterations = 10
multithreaded = True
the_capture = capture.Capture.from_filelist(image_names)
img_type, irradiance_list = get_image_type_and_irradiance(the_capture, None)
im_aligned, warp_matrices = align_non_panchro_capture(
the_capture,
warp_matrices,
img_type,
match_index,
pyramid_levels,
max_alignment_iterations,
warp_mode,
regenerate=regenerate,
multithreaded=multithreaded
)
...