def test_band_info_init_error():
    """Test init error of BandInfo class"""

    num_ch = 3
    centers = [100, 200]
    centers_true = [100, 200, 300]
    unit = "nm"
    bandwidths = [1, 2, 3, 5]
    centers_std = [0.1, 0.1, 0.2, 0.6, 0.2]
    bandwidths_std = [0.2, 0.3, 0.4, 1]
    type = "reflectance"

    # Test error handling
    with raises(ValueError) as cm:
        tmp = BandInfo(num_channels=num_ch, centers=centers, unit='nm')
    assert "Length of list has to match number of channels" == str(cm.value)

    with raises(ValueError) as cm:
        tmp = BandInfo(num_channels=num_ch, centers=centers_true,
                          bandwidths=bandwidths, unit='nm')
    assert "Length of list has to match number of channels" == str(cm.value)

    with raises(ValueError) as cm:
        tmp = BandInfo(num_channels=num_ch, centers=centers_true,
                          bandwidths_std=bandwidths_std, unit='nm')
    assert "Length of list has to match number of channels" == str(cm.value)

    with raises(ValueError) as cm:
        tmp = BandInfo(num_channels=num_ch, centers=centers_true,
                          centers_std=centers_std, unit='nm')
    assert "Length of list has to match number of channels" == str(cm.value)

    return
def test_band_info_downsampled():
    """Test get_subband() of BandInfo class"""

    num_ch = 13
    centers = np.linspace(400, 600, num_ch)
    unit = "nm"
    bandwidths = np.arange(num_ch)
    centers_std = 0.5*np.arange(num_ch)
    bandwidths_std = 0.25*np.arange(num_ch)
    type = "reflectance"

    tmp = BandInfo(num_channels=num_ch, centers=centers, unit=unit,
                   bandwidths=bandwidths, bandwidths_std=bandwidths_std,
                   centers_std=centers_std, type=type)

    tmp_down = tmp.get_downsampled(num=7)
    centers_exp = np.linspace(400, 600, 7)

    assert tmp.type == tmp_down.type
    assert 7 == tmp_down.num_channels
    assert np.array_equal(centers_exp, tmp_down.centers)
    assert tmp_down.centers_std is None
    assert tmp_down.bandwidths is None
    assert tmp_down.bandwidths_std is None

    return
def test_get_resampled():
    """Test SpectralArray resampling"""

    # Init SpectralArray
    num_ch = 100

    # 1D Spectrum
    arr = np.random.rand(num_ch).astype(np.float32)
    meta = dict(metadata="test")
    tmp = SpectralArray(arr, band_info=None, meta=meta, dtype=np.float32)

    tmp_dec = tmp.get_resampled_spectrum(num=13)

    assert 13 == tmp_dec.num_channels
    assert tmp_dec.band_info is None
    assert meta == tmp_dec.meta
    assert tmp_dec.dtype == np.float32

    # Test with BandInfo object
    band_info = BandInfo.from_equidistant(num_ch, 400, 700)
    band_info_down = BandInfo.from_equidistant(13, 400, 700)

    tmp = SpectralArray(arr, band_info=band_info, meta=None, dtype=np.float32)

    tmp_dec = tmp.get_resampled_spectrum(num=13)
    assert band_info_down == tmp_dec.band_info

    return
def test_band_info_subband():
    """Test get_subband() of BandInfo class"""

    num_ch = 13
    centers = np.arange(400, 400 + num_ch)
    unit = "nm"
    bandwidths = np.arange(num_ch)
    centers_std = 0.5*np.arange(num_ch)
    bandwidths_std = 0.25*np.arange(num_ch)
    type = "reflectance"

    tmp = BandInfo(num_channels=num_ch, centers=centers, unit=unit,
                   bandwidths=bandwidths, bandwidths_std=bandwidths_std,
                   centers_std=centers_std, type=type)

    tmp_sub = tmp.get_subband(start=5, stop=11)
    centers_exp = np.asarray([405, 406, 407, 408, 409, 410])
    centers_std_exp = np.asarray([2.5, 3.0, 3.5, 4.0, 4.5, 5.0])
    bandwidths_exp = np.asarray([5, 6, 7, 8, 9, 10])
    bandwidths_std_exp = np.asarray([1.25, 1.5, 1.75, 2.0, 2.25, 2.5])

    assert tmp.type == tmp_sub.type
    assert 6 == tmp_sub.num_channels
    assert np.array_equal(centers_exp, tmp_sub.centers)
    assert np.array_equal(centers_std_exp, tmp_sub.centers_std)
    assert np.array_equal(bandwidths_exp, tmp_sub.bandwidths)
    assert np.array_equal(bandwidths_std_exp, tmp_sub.bandwidths_std)

    return
def test_band_info_eq_op():
    """Test eq operator
    """
    options = dict(num_channels=5, lambda_start=400, lambda_end=800,
                   bandwidth=0.5, center_std=1, bandwidth_std=0.7)

    # Create two BandInfo objects with same options
    tmp1 = BandInfo.from_equidistant(**options)
    tmp2 = BandInfo.from_equidistant(**options)

    assert tmp1 == tmp2

    return
Example #6
0
    def _read_envi(path: Path) -> Tuple[ndarray, BandInfo, dict]:
        """Read array data from ENVI binary and header file.

        This function uses imageio to read the image and adds the
        BandInfo and metadata from the ENVI header file.

        Args:
            path: Path to ENVI binary file (usually .raw or .img).

        Returns:
            image, bandinfo, meta
            Tuple containing ndarray of the image data, BandInfo object and
            metadata dictionary.
        """
        hsi = imageio.imread(path, format='gdal')
        if hsi.ndim == 2:
            hsi = hsi[..., np.newaxis]

        # Transpose axis as imageio uses (ch, x, y) shape for spectral images
        hsi = np.transpose(hsi, (1, 2, 0))

        meta = SpectralArray.read_envi_header(path.with_suffix('.hdr'))
        bandinfo = BandInfo.from_envi_header(meta)

        return hsi, bandinfo, meta
def test_get_subband():
    """Test SpectralArray subband"""

    # Init SpectralArray
    num_ch = 100

    # 1D Spectrum
    arr = np.random.rand(num_ch).astype(np.float32)
    meta = dict(metadata="test")
    tmp = SpectralArray(arr, band_info=None, meta=meta, dtype=np.float32)

    tmp_dec = tmp.get_subband(30, 51)

    assert np.array_equal(arr[..., 30:51], np.asarray(tmp_dec))
    assert tmp_dec.band_info is None
    assert meta == tmp_dec.meta
    assert tmp_dec.dtype == np.float32

    # Test with BandInfo object
    band_info = BandInfo.from_equidistant(num_ch, 400, 700)

    tmp = SpectralArray(arr, band_info=band_info, meta=None, dtype=np.float32)

    tmp_dec = tmp.get_subband(30, 51)
    assert np.array_equal(band_info.centers[30:51], tmp_dec.band_info.centers)

    return
def test_spectral_array_operations():
    num_ch = 10
    arr = np.random.rand(3, 3, num_ch).astype(np.float32)
    info = BandInfo.from_equidistant(num_channels=num_ch,
                                     lambda_start=400, lambda_end=70)
    meta = dict(entry="Entry", setting="Setting")

    tmp_arr = SpectralArray(arr, dtype=np.float32, copy=True,
                            meta=meta, band_info=info)

    # Multiplication
    tmp = 0.5*tmp_arr
    assert np.array_equal(0.5*arr, tmp)
    assert num_ch == tmp.num_channels
    assert meta == tmp.meta
    assert info == tmp.band_info

    # Addition
    tmp = tmp_arr + arr
    assert np.array_equal(2*arr, tmp)
    assert num_ch == tmp.num_channels
    assert meta == tmp.meta
    assert info == tmp.band_info

    tmp = arr + tmp_arr
    assert np.array_equal(2 * arr, tmp)
    assert num_ch == tmp.num_channels
    assert meta == tmp.meta
    assert info == tmp.band_info

    return
def test_band_info_equidistant():
    """Test ``from_equidistant`` class method.
    """

    tmp = BandInfo.from_equidistant(num_channels=5,
                                       lambda_start=400,
                                       lambda_end=800,
                                       bandwidth=0.5,
                                       center_std=1,
                                       bandwidth_std=0.7)

    assert tmp.num_channels == 5
    assert np.array_equal(tmp.centers,
                          np.asarray([400, 500, 600, 700, 800]))

    assert np.array_equal(tmp.bandwidths,
                          np.asarray([0.5, 0.5, 0.5, 0.5, 0.5]))

    assert np.array_equal(tmp.centers_std,
                          np.asarray([1, 1, 1, 1, 1]))

    assert np.array_equal(tmp.bandwidths_std,
                          np.asarray([0.7, 0.7, 0.7, 0.7, 0.7]))

    return
def test_band_info_copy():
    """Test copy() of BandInfo class"""

    num_ch = 3
    centers = [100, 200, 300]
    unit = "nm"
    bandwidths = [1, 2, 3]
    centers_std = [0.1, 0.1, 0.2]
    bandwidths_std = [0.2, 0.3, 0.4]
    type = "reflectance"

    tmp = BandInfo(num_channels=num_ch, centers=centers, unit=unit,
                   bandwidths=bandwidths, bandwidths_std=bandwidths_std,
                   centers_std=centers_std, type=type)

    tmp_cp = tmp.copy()

    assert tmp == tmp_cp

    return
def test_spectral_array_errors():

    # Test input array type
    with raises(ValueError) as cm:
        tmp_arr = SpectralArray([1, 2, 3], dtype=np.float32, copy=True,
                                meta=None, band_info=None)
    assert "SpectralArray expects a numpy array." == str(cm.value)

    # Test input metadata type
    with raises(ValueError) as cm:
        tmp_arr = SpectralArray(np.asarray([1, 2, 3], dtype=np.uint8),
                                dtype=np.float32, copy=True,
                                meta="Not Meta", band_info=None)
    assert "SpectralArray expects meta data to be a dict." == str(cm.value)

    # Test input BandInfo type
    with raises(ValueError) as cm:
        tmp_arr = SpectralArray(np.asarray([1, 2, 3], dtype=np.uint8),
                                dtype=np.float32, copy=True,
                                meta=None, band_info="Not Bandinfo")
    assert "SpectralArray expects BandInfo or None instance." == str(cm.value)

    # Test input array size
    with raises(ValueError) as cm:
        tmp_arr = SpectralArray(np.asarray([], dtype=np.uint8),
                                dtype=np.float32, copy=True,
                                meta=None, band_info=None)
    assert "Invalid array size. Must have at least one axis." == str(cm.value)

    # Test invalid conversion

    # Test dtype argument
    with raises(ValueError) as cm:
        tmp_arr = SpectralArray(np.asarray([0.0, 0.1, 0.2], dtype=np.float32),
                                dtype=np.uint8, copy=True,
                                meta=None, band_info=None)
    assert "The passed dtype '<class 'numpy.uint8'>' is invalid. " \
           "Only numpy float types are allowed." == str(cm.value)

    # Test BandInfo compability
    info = BandInfo.from_equidistant(num_channels=10,
                                     lambda_start=400, lambda_end=700)
    arr = np.random.rand(5, 5, 11).astype(np.float32)

    with raises(ValueError) as cm:
        tmp_arr = SpectralArray(arr,
                                dtype=np.float32, copy=True,
                                meta=None, band_info=info)
    assert f"The numbers of channels of the band info object and the numbers "\
        f"of channels of the given data does not match. Found " \
        f"10 and 11 respectively." == str(cm.value)

    return
def test_spectral_array_copy():
    """Test copying of SpectralArray"""

    num_ch = 10
    arr = np.random.rand(3, 3, num_ch).astype(np.float32)
    info = BandInfo.from_equidistant(num_channels=num_ch,
                                     lambda_start=400, lambda_end=70)
    meta = dict(entry="Entry", setting="Setting")

    tmp_arr = SpectralArray(arr, dtype=np.float32, copy=True,
                            meta=meta, band_info=info)

    tmp_arr_copy = tmp_arr.copy()

    assert np.array_equal(tmp_arr, tmp_arr_copy)
    assert tmp_arr.num_channels == tmp_arr_copy.num_channels
    assert tmp_arr.meta == tmp_arr_copy.meta
    assert tmp_arr.band_info == tmp_arr_copy.band_info

    return
def test_band_info_envi():
    """Test ``from_envi`` class method.
    """
    testing.needs_internet()

    envi_file = testing.get_remote_file(TEST_ENVI_HDR)
    d = SpectralArray.read_envi_header(envi_file)

    band_info = BandInfo.from_envi_header(d)
    centers_exp = np.asarray([400.6, 450.3, 500, 551.7, 600.666, 760.9])
    bandwiths_exp = np.asarray([1.1, 1.2, 1.3, 1.4, 1.5, 1.6])

    assert 6 == band_info.num_channels
    assert band_info.type is None
    assert band_info.centers_std is None
    assert band_info.bandwidths_std is None
    assert np.array_equal(centers_exp, band_info.centers)
    assert np.array_equal(bandwiths_exp, band_info.bandwidths)

    return
def test_spectral_array_new():

    num_ch = 10
    arr = np.random.rand(3, 3, num_ch).astype(np.float32)
    info = BandInfo.from_equidistant(num_channels=num_ch,
                                     lambda_start=400, lambda_end=70)
    meta = dict(entry="Entry", setting="Setting")

    tmp_arr = SpectralArray(arr, dtype=np.float32, copy=True,
                            meta=meta, band_info=info)

    assert np.array_equal(arr, tmp_arr)
    assert tmp_arr.num_channels == num_ch
    assert meta == tmp_arr.meta
    assert info == tmp_arr.band_info

    # Test Data conversion
    for dtype in [np.float16, np.float32, np.float64]:
        tmp_arr = SpectralArray(arr, dtype=dtype, copy=True)
        assert np.allclose(arr.astype(dtype), tmp_arr)

    return
def test_band_info_init():
    """Test init of BandInfo class"""

    num_ch = 3
    centers = [100, 200, 300]
    unit = "nm"
    bandwidths = [1, 2, 3]
    centers_std = [0.1, 0.1, 0.2]
    bandwidths_std = [0.2, 0.3, 0.4]
    type = "reflectance"

    tmp = BandInfo(num_channels=num_ch, centers=centers, unit=unit,
                   bandwidths=bandwidths, bandwidths_std=bandwidths_std,
                   centers_std=centers_std, type=type)

    assert tmp.num_channels == num_ch
    assert tmp.centers == centers
    assert tmp.unit == unit
    assert tmp.bandwidths == bandwidths
    assert tmp.centers_std == centers_std
    assert tmp.bandwidths_std == bandwidths_std
    assert tmp.type == type

    return