Example #1
0
    def test_remove_feature(self):
        bands = np.arange(2 * 3 * 3 * 2).reshape(2, 3, 3, 2)
        names = ['bands1', 'bands2', 'bands3']

        eop = EOPatch()
        eop.add_feature(FeatureType.DATA, names[0], bands)
        eop.data[names[1]] = bands
        eop[FeatureType.DATA][names[2]] = bands

        for feature_name in names:
            self.assertTrue(
                feature_name in eop.data,
                "Feature {} was not added to EOPatch".format(feature_name))
            self.assertTrue(
                np.array_equal(eop.data[feature_name], bands),
                "Data of feature {} is "
                "incorrect".format(feature_name))

        eop.remove_feature(FeatureType.DATA, names[0])
        del eop.data[names[1]]
        del eop[FeatureType.DATA][names[2]]
        for feature_name in names:
            self.assertFalse(feature_name in eop.data,
                             msg="Feature {} should be deleted from "
                             "EOPatch".format(feature_name))
    def test_add_ndvi(self):
        a = np.arange(2 * 3 * 3 * 13).reshape(2, 3, 3, 13)
        eop = EOPatch()
        eop.add_feature(attr_type=FeatureType.DATA, field='bands', value=a)

        eotask_ndvi = FeatureExtractionTask('I(B4, B8A)', 'bands', 'ndvi')

        eop_ndvi = eotask_ndvi(eop)

        in_shape = eop.data['bands'].shape
        out_shape = in_shape[:-1] + (1, )

        self.assertEqual(eop_ndvi.data['ndvi'].shape, out_shape)
    def test_temporal_indices(self):
        """ Test case for computation of argmax/argmin of NDVI and another band

        Cases with and without data masking are tested
        """
        # EOPatch
        eopatch = EOPatch()
        t, h, w, c = 5, 3, 3, 2
        # NDVI
        ndvi_shape = (t, h, w, 1)
        # VAlid data mask
        valid_data = np.ones(ndvi_shape, np.bool)
        valid_data[0] = 0
        valid_data[-1] = 0
        # Fill in eopatch
        eopatch.add_feature(FeatureType.DATA, 'NDVI',
                            np.arange(np.prod(ndvi_shape)).reshape(ndvi_shape))
        eopatch.add_feature(FeatureType.MASK, 'IS_DATA',
                            np.ones(ndvi_shape, dtype=np.int16))
        eopatch.add_feature(FeatureType.MASK, 'VALID_DATA', valid_data)
        # Task
        add_ndvi = AddMaxMinTemporalIndicesTask(mask_data=False)
        # Run task
        new_eopatch = add_ndvi(eopatch)
        # Asserts
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['ARGMIN_NDVI'],
                           np.zeros((h, w, 1))))
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['ARGMAX_NDVI'],
                           (t - 1) * np.ones((h, w, 1))))
        del add_ndvi, new_eopatch
        # Repeat with valid dat amask
        add_ndvi = AddMaxMinTemporalIndicesTask(mask_data=True)
        new_eopatch = add_ndvi(eopatch)
        # Asserts
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['ARGMIN_NDVI'],
                           np.ones((h, w, 1))))
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['ARGMAX_NDVI'],
                           (t - 2) * np.ones((h, w, 1))))
        del add_ndvi, new_eopatch, valid_data
        # BANDS
        bands_shape = (t, h, w, c)
        eopatch.add_feature(
            FeatureType.DATA, 'BANDS',
            np.arange(np.prod(bands_shape)).reshape(bands_shape))
        add_bands = AddMaxMinTemporalIndicesTask(data_feature='BANDS',
                                                 data_index=1,
                                                 amax_data_feature='ARGMAX_B1',
                                                 amin_data_feature='ARGMIN_B1',
                                                 mask_data=False)
        new_eopatch = add_bands(eopatch)
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['ARGMIN_B1'],
                           np.zeros((h, w, 1))))
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['ARGMAX_B1'],
                           (t - 1) * np.ones((h, w, 1))))
def tif_to_npz(files):
    patch = EOPatch()
    tasks = [
        ImportFromTiff((FeatureType.DATA, f'LOADED_DATA'), path)
        for path in files[::-1]
    ]

    for task in tqdm(tasks):
        task.execute(patch)
        if 'bands' in patch[FeatureType.DATA]:
            patch.add_feature(
                FeatureType.DATA, 'bands',
                EOPatch.concatenate_data(
                    patch[FeatureType.DATA][f'LOADED_DATA'],
                    patch[FeatureType.DATA]['bands'],
                ))
            patch.remove_feature(FeatureType.DATA, f'LOADED_DATA')
        else:
            patch.rename_feature(FeatureType.DATA, f'LOADED_DATA', 'bands')

    np.savez_compressed('data', data=patch[FeatureType.DATA]['bands'])
    def test_stf_task(self):
        """ Test case for computation of spatio-temporal features

            The NDVI is a sinusoid over 0-pi over the temporal dimension, while bands is an array with values equal to
            the temporal index
        """
        # Timestamps
        timestamp = perdelta(date(2018, 3, 1), date(2018, 3, 11),
                             timedelta(days=1))
        # EOPatch
        eopatch = EOPatch(timestamp=list(timestamp))
        # Shape of arrays
        t, h, w, c = 10, 3, 3, 2
        # NDVI is a sinusoid where max slope is at index 1 and min slope at index 8
        ndvi_shape = (t, h, w, 1)
        bands_shape = (t, h, w, c)
        xx = np.zeros(ndvi_shape, np.float32)
        x = np.linspace(0, np.pi, t)
        xx[:, :, :, :] = x[:, None, None, None]
        # Bands are arrays with values equal to the temporal index
        bands = np.ones(bands_shape) * np.arange(t)[:, None, None, None]
        # Add features to eopatch
        eopatch.add_feature(FeatureType.DATA, 'NDVI', np.sin(xx))
        eopatch.add_feature(FeatureType.DATA, 'BANDS', bands)
        eopatch.add_feature(FeatureType.MASK, 'IS_DATA',
                            np.ones(ndvi_shape, np.bool))
        # Tasks
        add_ndvi = AddMaxMinTemporalIndicesTask(mask_data=False)
        add_bands = AddMaxMinTemporalIndicesTask(data_feature='BANDS',
                                                 data_index=1,
                                                 amax_data_feature='ARGMAX_B1',
                                                 amin_data_feature='ARGMIN_B1',
                                                 mask_data=False)
        add_ndvi_slope = AddMaxMinNDVISlopeIndicesTask(mask_data=False)
        add_stf = AddSpatioTemporalFeaturesTask(argmax_red='ARGMAX_B1',
                                                data_feature='BANDS',
                                                indices=[0, 1])
        # Run tasks
        new_eopatch = add_stf(add_ndvi_slope(add_bands(add_ndvi(eopatch))))
        # Asserts
        self.assertTrue(new_eopatch.data_timeless['STF'].shape == (h, w,
                                                                   c * 5))
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['STF'][:, :, 0:c],
                           4 * np.ones((h, w, c))))
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['STF'][:, :, c:2 * c],
                           9 * np.ones((h, w, c))))
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['STF'][:, :, 2 * c:3 * c],
                           np.ones((h, w, c))))
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['STF'][:, :, 3 * c:4 * c],
                           8 * np.ones((h, w, c))))
        self.assertTrue(
            np.array_equal(new_eopatch.data_timeless['STF'][:, :, 4 * c:5 * c],
                           9 * np.ones((h, w, c))))
def save_as_eopatch(data, label, field_id, dates, folder):
    """
    Creates an EOPatch and adds data:
    * S2 L2A bands will be stored in DATA feature under name `S2-BANDS-L2A`
    * sen2cor cloud probabilities will be stored in DATA feature under name `CLOUD_PROB`
    * labels will be stored in MASK_TIMELESS under name `CROP_ID`
    * field ids  will be stored in MASK_TIMELESS under name `FIELD_ID`
    * dates of observations will be added to timestamps

    EOPatch is saved to specified folder.
    """
    eopatch = EOPatch()

    eopatch.add_feature(FeatureType.DATA, 'S2-BANDS-L2A', data[..., :12])
    eopatch.add_feature(FeatureType.DATA, 'CLOUD_PROB', data[..., -1][...,np.newaxis])
    eopatch.add_feature(FeatureType.MASK_TIMELESS, 'CROP_ID', label[...,np.newaxis])
    eopatch.add_feature(FeatureType.MASK_TIMELESS, 'FIELD_ID', field_id[...,np.newaxis])
    eopatch.timestamp = dates

    eopatch.save(folder)

    return eopatch
    def test_ndvi_slope_indices(self):
        """ Test case for computation of argmax/argmin of NDVI slope

            The NDVI is a sinusoid over 0-pi over the temporal dimension

            Cases with and without data masking are tested
        """
        # Slope needs timestamps
        timestamp = perdelta(date(2018, 3, 1), date(2018, 3, 11), timedelta(days=1))
        # EOPatch
        eopatch = EOPatch(timestamp=list(timestamp))
        t, h, w, = 10, 3, 3
        # NDVI is a sinusoid where max slope is at index 1 and min slope at index 8
        ndvi_shape = (t, h, w, 1)
        xx = np.zeros(ndvi_shape, np.float32)
        x = np.linspace(0, np.pi, t)
        xx[:, :, :, :] = x[:, None, None, None]
        # Valid data mask
        valid_data = np.ones(ndvi_shape, np.uint8)
        valid_data[1] = 0
        valid_data[-1] = 0
        valid_data[4] = 0
        # Fill EOPatch
        eopatch.add_feature(FeatureType.DATA, 'NDVI', np.sin(xx))
        eopatch.add_feature(FeatureType.MASK, 'IS_DATA', np.ones(ndvi_shape, np.bool))
        eopatch.add_feature(FeatureType.MASK, 'VALID_DATA', valid_data)
        # Tasks
        add_ndvi = AddMaxMinTemporalIndicesTask(mask_data=False)
        add_ndvi_slope = AddMaxMinNDVISlopeIndicesTask(mask_data=False)
        # Run
        new_eopatch = add_ndvi_slope(add_ndvi(eopatch))
        # Assert
        self.assertTrue(np.array_equal(new_eopatch.data_timeless['ARGMIN_NDVI'], (t-1)*np.ones((h, w, 1))))
        self.assertTrue(np.array_equal(new_eopatch.data_timeless['ARGMAX_NDVI'], (t//2-1)*np.ones((h, w, 1))))
        self.assertTrue(np.array_equal(new_eopatch.data_timeless['ARGMIN_NDVI_SLOPE'], (t-2)*np.ones((h, w, 1))))
        self.assertTrue(np.array_equal(new_eopatch.data_timeless['ARGMAX_NDVI_SLOPE'], np.ones((h, w, 1))))
        del add_ndvi_slope, add_ndvi, new_eopatch
        # Run on valid data only now
        add_ndvi = AddMaxMinTemporalIndicesTask(mask_data=True)
        add_ndvi_slope = AddMaxMinNDVISlopeIndicesTask(mask_data=True)
        # Run
        new_eopatch = add_ndvi_slope(add_ndvi(eopatch))
        # Assert
        self.assertTrue(np.array_equal(new_eopatch.data_timeless['ARGMIN_NDVI'], 0 * np.ones((h, w, 1))))
        self.assertTrue(np.array_equal(new_eopatch.data_timeless['ARGMAX_NDVI'], (t // 2) * np.ones((h, w, 1))))
        self.assertTrue(np.array_equal(new_eopatch.data_timeless['ARGMIN_NDVI_SLOPE'], (t - 3) * np.ones((h, w, 1))))
        self.assertTrue(np.array_equal(new_eopatch.data_timeless['ARGMAX_NDVI_SLOPE'], 2 * np.ones((h, w, 1))))
Example #8
0
    def test_registration(self):
        # Set up a dummy EOPatch to test execution of registration
        bands = np.zeros((2, 20, 20, 1))
        bands[1] = np.arange(400).reshape(1, 20, 20, 1) / 400
        bands[0] = bands[1]
        bands[1, 5:15, 5:15, :] = .5
        bands[0, 7:17, 5:15, :] = .5
        mask = np.ones((2, 20, 20, 1))
        ndvi = np.ones((2, 20, 20, 1))
        dem = np.ones((20, 20, 1))

        eop = EOPatch()
        eop.add_feature(attr_type=FeatureType.DATA, field='bands', value=bands)
        eop.add_feature(attr_type=FeatureType.DATA, field='ndvi', value=ndvi)
        eop.add_feature(attr_type=FeatureType.MASK, field='cm', value=mask)
        eop.add_feature(attr_type=FeatureType.DATA_TIMELESS, field='dem', value=dem)

        reg = ECCRegistration(FeatureType.DATA, 'bands', interpolation=Interpolation.NEAREST)
        reop = reg.execute(eop)

        self.assertEqual(eop.data['bands'].shape, reop.data['bands'].shape,
                         msg='Shapes of .data[''bands''] do not match')
        self.assertEqual(eop.data['ndvi'].shape, reop.data['ndvi'].shape,
                         msg='Shapes of .data[''ndvi''] do not match')
        self.assertEqual(eop.mask['cm'].shape, reop.mask['cm'].shape,
                         msg='Shapes of .mask[''cm''] do not match')
        self.assertEqual(eop.data_timeless['dem'].shape, reop.data_timeless['dem'].shape,
                         msg='Shapes of .data[''bands''] do not match')
        self.assertFalse(np.allclose(eop.data['bands'], reop.data['bands']),
                         msg='Registration did not warp .data[''bands'']')
        self.assertFalse(np.allclose(eop.data['ndvi'], reop.data['ndvi']),
                         msg='Registration did not warp .data[''ndvi'']')
        self.assertFalse(np.allclose(eop.mask['cm'], reop.mask['cm']),
                         msg='Registration did not warp .mask[''cm'']')
        self.assertTrue(np.allclose(eop.data_timeless['dem'], reop.data_timeless['dem']),
                        msg='Registration did warp data_timeless')
Example #9
0
def save_as_eopatch(data, label, field_id, dates, folder):
    """
    Creates an EOPatch and adds data:
    * S2 L2A bands will be stored in DATA feature under name `S2-BANDS-L2A`
    * Individual bands will be stored in DATA features under their respective channel names
    * sen2cor cloud probabilities will be stored in DATA feature under name `CLOUD_PROB`
    * labels will be stored in MASK_TIMELESS under name `CROP_ID`
    * field ids  will be stored in MASK_TIMELESS under name `FIELD_ID`
    * dates of observations will be added to timestamps

    EOPatch is saved to specified folder.
    """
    eopatch = EOPatch()

    # Bands
    eopatch.add_feature(FeatureType.DATA, 'B01', data[..., 0][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B02', data[..., 1][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B03', data[..., 2][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B04', data[..., 3][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B05', data[..., 4][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B06', data[..., 5][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B07', data[..., 6][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B08', data[..., 7][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B8A', data[..., 8][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B09', data[..., 9][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B11', data[..., 10][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'B12', data[..., 11][..., np.newaxis])
    eopatch.add_feature(FeatureType.DATA, 'S2-BANDS-L2A', data[..., :12])

    eopatch.add_feature(FeatureType.DATA, 'CLOUD_PROB', data[..., -1][..., np.newaxis])
    eopatch.add_feature(FeatureType.MASK_TIMELESS, 'CROP_ID', label[..., np.newaxis])
    eopatch.add_feature(FeatureType.MASK_TIMELESS, 'FIELD_ID', field_id[..., np.newaxis])
    eopatch.timestamp = dates

    eopatch.save(folder)

    return eopatch