예제 #1
0
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
예제 #2
0
 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)
예제 #3
0
 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
예제 #5
0
    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)
예제 #6
0
    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