def test_pysolar_az_el_vs_usno(): # for simplicity's sake, let's pick a couple places on the prime meridian on the vernal equinox, # and test those vs the USNO # https://aa.usno.navy.mil/rstt/onedaytable?ID=AA&year=2019&month=3&day=20&place=&lon_sign=-1&lon_deg=0&lon_min=0&lat_sign=1&lat_deg=51&lat_min=28&tz=0&tz_sign=-1 lat = 51.4769 #greenwich observatory lon = 0 dt = datetime.datetime(2019, 3, 21, 12, 8, 0, tzinfo=datetime.timezone.utc) _, _, angle, sunAltitude, sunAzimuth = dls.compute_sun_angle( (lat, lon, 0), (0, 0, 0), dt, np.array([0, 0, -1])) assert angle == pytest.approx(math.radians(lat), abs=0.01) assert sunAltitude == pytest.approx(math.radians(90 - lat), abs=0.01) assert sunAzimuth == pytest.approx(math.pi, abs=0.01) #for simplicity's sake, let's pick a couple places on the prime meridian on the vernal equinox lat = 0 lon = 0 dt = datetime.datetime(2019, 3, 20, 12, 8, 0, tzinfo=datetime.timezone.utc) _, _, angle, sunAltitude, sunAzimuth = dls.compute_sun_angle( (lat, lon, 0), (0, 0, 0), dt, np.array([0, 0, -1])) assert angle == pytest.approx(math.radians(lat), abs=0.01) assert sunAltitude == pytest.approx(math.radians(90 - lat), abs=0.01) #assert sunAzimuth == pytest.approx(math.pi, abs=0.01) # should be straight up, at the equator, don't test elevation # middle of the ocean at 45deg sout latitutde lat = -45 lon = 0 dt = datetime.datetime(2019, 3, 20, 12, 8, 0, tzinfo=datetime.timezone.utc) _, _, angle, sunAltitude, sunAzimuth = dls.compute_sun_angle( (lat, lon, 0), (0, 0, 0), dt, np.array([0, 0, -1])) assert angle == pytest.approx(math.radians(math.fabs(lat)), abs=0.01) assert sunAltitude == pytest.approx(math.radians(90 + lat), abs=0.01) assert sunAzimuth == pytest.approx(2 * math.pi, abs=0.01) # should be due north
def __init__(self, images,panelCorners=[None]*5): if isinstance(images, image.Image): self.images = [images] elif isinstance(images, list): self.images = images else: raise RuntimeError("Provide an image or list of images to create a Capture") self.num_bands = len(self.images) self.images.sort() capture_ids = [img.capture_id for img in self.images] if len(set(capture_ids)) != 1: raise RuntimeError("Images provided are required to all have the same capture id") self.uuid = self.images[0].capture_id self.panels = None self.detected_panel_count = 0 self.panelCorners = panelCorners self.dls_orientation_vector = np.array([0,0,-1]) self.sun_vector_ned, \ self.sensor_vector_ned, \ self.sun_sensor_angle, \ self.solar_elevation, \ self.solar_azimuth=dls.compute_sun_angle(self.location(), self.dls_pose(), self.utc_time(), self.dls_orientation_vector) self.fresnel_correction = dls.fresnel(self.sun_sensor_angle)
def compute_horizontal_irradiance_dls2(self): ''' Compute the proper solar elevation, solar azimuth, and horizontal irradiance for cases where the camera system did not do it correctly ''' _, _, _, \ self.solar_elevation, \ self.solar_azimuth = dls.compute_sun_angle(self.location, (0, 0, 0), self.utc_time, np.array([0, 0, -1])) return self.horizontal_irradiance_from_direct_scattered()
def test_sun_angle(img): if dls.havePysolar: sun_angle = dls.compute_sun_angle((img.latitude, img.longitude, img.altitude), (img.dls_yaw, img.dls_pitch, img.dls_roll), img.utc_time, np.array([0,0,-1])) assert sun_angle[0] == pytest.approx([-0.711, -0.247, -0.659], abs=0.001) assert sun_angle[1] == pytest.approx([-1.87482468e-01, 1.82720334e-05, -9.82267949e-01], abs=0.001) assert sun_angle[2] == pytest.approx(0.6754, abs=0.001) assert sun_angle[3] == pytest.approx(0.7193, abs=0.001) assert sun_angle[4] == pytest.approx(-0.334, abs=0.001) else: assert True
def dls_correction(self): self.dls_irradiances = [ ] # otherwise, it will append everytime the function is run self.center_wavelengths = [] # Define DLS sensor orientation vector relative to dls pose frame dls_orientation_vector = np.array([0, 0, -1]) # compute sun orientation and sun-sensor angles ( sun_vector_ned, # Solar vector in North-East-Down coordinates sensor_vector_ned, # DLS vector in North-East-Down coordinates sun_sensor_angle, # Angle between DLS vector and sun vector solar_elevation, # Elevation of the sun above the horizon solar_azimuth, # Azimuth (heading) of the sun ) = dls.compute_sun_angle(self.cap.location(), self.cap.dls_pose(), self.cap.utc_time(), dls_orientation_vector) # ------------------ Correcting DLS readings for orientations ----------------- # Since the diffuser reflects more light at shallow angles than at steep angles, # we compute a correction for this fresnel_correction = dls.fresnel(sun_sensor_angle) # Now we can correct the raw DLS readings and compute the irradiance on level ground for img in self.cap.images: dir_dif_ratio = 6.0 percent_diffuse = 1.0 / dir_dif_ratio # measured Irradiance / fresnelCorrection sensor_irradiance = img.spectral_irradiance / fresnel_correction untilted_direct_irr = sensor_irradiance / ( percent_diffuse + np.cos(sun_sensor_angle)) # compute irradiance on the ground using the solar altitude angle dls_irr = untilted_direct_irr * (percent_diffuse + np.sin(solar_elevation)) self.dls_irradiances.append(dls_irr) self.center_wavelengths.append(img.center_wavelength)
def __init__(self, image_path, exiftool_obj=None): if not os.path.isfile(image_path): raise IOError("Provided path is not a file: {}".format(image_path)) self.path = image_path self.meta = metadata.Metadata(self.path, exiftool_obj=exiftool_obj) if self.meta.band_name() is None: raise ValueError("Provided file path does not have a band name: {}".format(image_path)) if self.meta.band_name().upper() != 'LWIR' and not self.meta.supports_radiometric_calibration(): raise ValueError('Library requires images taken with RedEdge-(3/M/MX) camera firmware v2.1.0 or later. ' + 'Upgrade your camera firmware to at least version 2.1.0 to use this library with RedEdge-(3/M/MX) cameras.') self.utc_time = self.meta.utc_time() self.latitude, self.longitude, self.altitude = self.meta.position() self.location = (self.latitude, self.longitude, self.altitude) self.dls_present = self.meta.dls_present() self.dls_yaw, self.dls_pitch, self.dls_roll = self.meta.dls_pose() self.capture_id = self.meta.capture_id() self.flight_id = self.meta.flight_id() self.band_name = self.meta.band_name() self.band_index = self.meta.band_index() self.black_level = self.meta.black_level() if self.meta.supports_radiometric_calibration(): self.radiometric_cal = self.meta.radiometric_cal() self.exposure_time = self.meta.exposure() self.gain = self.meta.gain() self.bits_per_pixel = self.meta.bits_per_pixel() self.vignette_center = self.meta.vignette_center() self.vignette_polynomial = self.meta.vignette_polynomial() self.distortion_parameters = self.meta.distortion_parameters() self.principal_point = self.meta.principal_point() self.focal_plane_resolution_px_per_mm = self.meta.focal_plane_resolution_px_per_mm() self.focal_length = self.meta.focal_length_mm() self.focal_length_35 = self.meta.focal_length_35_mm_eq() self.center_wavelength = self.meta.center_wavelength() self.bandwidth = self.meta.bandwidth() self.rig_relatives = self.meta.rig_relatives() self.spectral_irradiance = self.meta.spectral_irradiance() self.auto_calibration_image = self.meta.auto_calibration_image() self.panel_albedo = self.meta.panel_albedo() self.panel_region = self.meta.panel_region() self.panel_serial = self.meta.panel_serial() if self.dls_present: self.dls_orientation_vector = np.array([0, 0, -1]) self.sun_vector_ned, \ self.sensor_vector_ned, \ self.sun_sensor_angle, \ self.solar_elevation, \ self.solar_azimuth = dls.compute_sun_angle(self.location, self.meta.dls_pose(), self.utc_time, self.dls_orientation_vector) self.angular_correction = dls.fresnel(self.sun_sensor_angle) # when we have good horizontal irradiance the camera provides the solar az and el also if self.meta.scattered_irradiance() != 0 and self.meta.direct_irradiance() != 0: self.solar_azimuth = self.meta.solar_azimuth() self.solar_elevation = self.meta.solar_elevation() self.scattered_irradiance = self.meta.scattered_irradiance() self.direct_irradiance = self.meta.direct_irradiance() self.direct_to_diffuse_ratio = self.meta.direct_irradiance() / self.meta.scattered_irradiance() self.estimated_direct_vector = self.meta.estimated_direct_vector() if self.meta.horizontal_irradiance_valid(): self.horizontal_irradiance = self.meta.horizontal_irradiance() else: self.horizontal_irradiance = self.compute_horizontal_irradiance_dls2() else: self.direct_to_diffuse_ratio = 6.0 # assumption self.horizontal_irradiance = self.compute_horizontal_irradiance_dls1() self.spectral_irradiance = self.meta.spectral_irradiance() else: # no dls present or LWIR band: compute what we can, set the rest to 0 self.dls_orientation_vector = np.array([0, 0, -1]) self.sun_vector_ned, \ self.sensor_vector_ned, \ self.sun_sensor_angle, \ self.solar_elevation, \ self.solar_azimuth = dls.compute_sun_angle(self.location, (0, 0, 0), self.utc_time, self.dls_orientation_vector) self.angular_correction = dls.fresnel(self.sun_sensor_angle) self.horizontal_irradiance = 0 self.scattered_irradiance = 0 self.direct_irradiance = 0 self.direct_to_diffuse_ratio = 0 # Internal image containers; these can use a lot of memory, clear with Image.clear_images self.__raw_image = None # pure raw pixels self.__intensity_image = None # black level and gain-exposure/radiometric compensated self.__radiance_image = None # calibrated to radiance self.__reflectance_image = None # calibrated to reflectance (0-1) self.__reflectance_irradiance = None self.__undistorted_source = None # can be any of raw, intensity, radiance self.__undistorted_image = None # current undistorted image, depdining on source
cap.set_panelCorners(panelCorners) # ## Computing Solar orientation # In[ ]: # Define DLS sensor orientation vector relative to dls pose frame dls_orientation_vector = np.array([0, 0, -1]) # compute sun orientation and sun-sensor angles ( sun_vector_ned, # Solar vector in North-East-Down coordinates sensor_vector_ned, # DLS vector in North-East-Down coordinates sun_sensor_angle, # Angle between DLS vector and sun vector solar_elevation, # Elevation of the sun above the horizon solar_azimuth, # Azimuth (heading) of the sun ) = dls.compute_sun_angle(cap.location(), cap.dls_pose(), cap.utc_time(), dls_orientation_vector) # ## Correcting DLS readings for orientations # In[ ]: # Since the diffuser reflects more light at shallow angles than at steep angles, # we compute a correction for this fresnel_correction = dls.fresnel(sun_sensor_angle) # Now we can correct the raw DLS readings and compute the irradiance on level ground dls_irradiances = [] center_wavelengths = [] for img in cap.images: dir_dif_ratio = 6.0 percent_diffuse = 1.0 / dir_dif_ratio