From 309c7751b35b958d09657015b32f86ab4ca0335b Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Fri, 6 Mar 2020 17:20:44 -0500 Subject: [PATCH] Sun sensor work Former-commit-id: 49d109199e3a21d8b42ee94cb5a06629fcd1477c --- opendm/multispectral.py | 39 +++++++++++++++++++++++++-------------- opendm/photo.py | 27 +++++++++++++++++++++------ stages/run_opensfm.py | 3 +++ 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/opendm/multispectral.py b/opendm/multispectral.py index 2e40f1a5..7d2ac7b3 100644 --- a/opendm/multispectral.py +++ b/opendm/multispectral.py @@ -65,8 +65,6 @@ def dn_to_radiance(photo, image): R = 1.0 / (1.0 + a2 * y / exposure_time - a3 * y) image *= R - cv2.imwrite("/datasets/mica/R.tif", R) - print("Row gradient") # Floor any negative radiances to zero (can happend due to noise around blackLevel) @@ -114,19 +112,28 @@ def vignette_map(photo): def dn_to_reflectance(photo, image, use_sun_sensor=True): radiance = dn_to_radiance(photo, image) - irradiance_scale = compute_irradiance_scale_factor(photo, use_sun_sensor=use_sun_sensor) - return radiance * irradiance_scale -def compute_irradiance_scale_factor(photo, use_sun_sensor=True): + # TODO REMOVE + cv2.imwrite("/datasets/sentera-6x/radiance.tif", radiance) + + + irradiance = compute_irradiance(photo, use_sun_sensor=use_sun_sensor) + print(irradiance) + return radiance * math.pi / irradiance + +def compute_irradiance(photo, use_sun_sensor=True): # Thermal? if photo.band_name == "LWIR": return 1.0 - if photo.irradiance is not None: - horizontal_irradiance = photo.irradiance - return math.pi / horizontal_irradiance - - if use_sun_sensor: + # Some cameras (Micasense) store the value (nice! just return) + hirradiance = photo.get_horizontal_irradiance() + if hirradiance is not None: + return hirradiance + + # TODO: support for calibration panels + + if use_sun_sensor and photo.sun_sensor: # Estimate it dls_orientation_vector = np.array([0,0,-1]) sun_vector_ned, sensor_vector_ned, sun_sensor_angle, \ @@ -137,21 +144,25 @@ def compute_irradiance_scale_factor(photo, use_sun_sensor=True): angular_correction = dls.fresnel(sun_sensor_angle) + print("Sun sensor") + # TODO: support for direct and scattered irradiance direct_to_diffuse_ratio = 6.0 # Assumption - spectral_irradiance = photo.sun_sensor # TODO: support for XMP:SpectralIrradiance + spectral_irradiance = photo.sun_sensor percent_diffuse = 1.0 / direct_to_diffuse_ratio sensor_irradiance = spectral_irradiance / angular_correction - # find direct irradiance in the plane normal to the sun + # Find direct irradiance in the plane normal to the sun untilted_direct_irr = sensor_irradiance / (percent_diffuse + np.cos(sun_sensor_angle)) direct_irradiance = untilted_direct_irr - scattered_irradiance = untilted_direct_irr*percent_diffuse + scattered_irradiance = untilted_direct_irr * percent_diffuse # compute irradiance on the ground using the solar altitude angle horizontal_irradiance = direct_irradiance * np.sin(solar_elevation) + scattered_irradiance - return math.pi / horizontal_irradiance + return horizontal_irradiance + elif use_sun_sensor: + log.ODM_WARNING("No sun sensor values found for %s" % photo.filename) return 1.0 \ No newline at end of file diff --git a/opendm/photo.py b/opendm/photo.py index ad984c4d..adc762ab 100644 --- a/opendm/photo.py +++ b/opendm/photo.py @@ -46,7 +46,9 @@ class ODM_Photo: self.bits_per_sample = None self.vignetting_center = None self.vignetting_polynomial = None - self.irradiance = None + # self.irradiance = None + self.horizontal_irradiance = None + self.irradiance_scale_to_si = None self.sun_sensor = None self.utc_time = None @@ -155,12 +157,17 @@ class ODM_Photo: 'Sentera:VignettingPolynomial', ]) - self.set_attr_from_xmp_tag('irradiance', tags, [ - 'Camera:Irradiance' + self.set_attr_from_xmp_tag('horizontal_irradiance', tags, [ + 'Camera:HorizontalIrradiance' + ], float) + + self.set_attr_from_xmp_tag('irradiance_scale_to_si', tags, [ + 'Camera:IrradianceScaleToSIUnits' ], float) self.set_attr_from_xmp_tag('sun_sensor', tags, [ - 'Camera:SunSensor' + 'Camera:SunSensor', + 'Camera:Irradiance', ], float) # self.set_attr_from_xmp_tag('center_wavelength', tags, [ @@ -181,7 +188,7 @@ class ODM_Photo: # print(self.vignetting_center) # print(self.sun_sensor) #print(self.get_vignetting_polynomial()) - #exit(1) + # exit(1) self.width, self.height = get_image_size.get_image_size(_path_file) # Sanitize band name since we use it in folder paths @@ -312,4 +319,12 @@ class ODM_Photo: def get_photometric_exposure(self): # H ~= (exposure_time) / (f_number^2) if self.fnumber is not None and self.exposure_time > 0: - return self.exposure_time / (self.fnumber * self.fnumber) \ No newline at end of file + return self.exposure_time / (self.fnumber * self.fnumber) + + def get_horizontal_irradiance(self): + if self.horizontal_irradiance is not None: + scale = 1.0 # Assumed + if self.irradiance_scale_to_si is not None: + scale = self.irradiance_scale_to_si + + return self.horizontal_irradiance * scale diff --git a/stages/run_opensfm.py b/stages/run_opensfm.py index 1694b42c..71c5568e 100644 --- a/stages/run_opensfm.py +++ b/stages/run_opensfm.py @@ -61,6 +61,9 @@ class ODMOpenSfMStage(types.ODM_Stage): if args.radiometric_calibration == "none": octx.convert_and_undistort(self.rerun()) else: + + # TODO: does this work for multi-band RGB images? + def radiometric_calibrate(shot_id, image): photo = reconstruction.get_photo(shot_id) return multispectral.dn_to_reflectance(photo, image, use_sun_sensor=args.radiometric_calibration=="camera+sun")