Source code for aitlas.datasets.eopatch_crops

import logging
import os
import urllib

import h5py
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from aitlas.datasets.crops_classification import CropsDataset
from eolearn.core import EOPatch, FeatureType
from eolearn.geometry import VectorToRasterTask
from sklearn.model_selection import train_test_split
from tqdm import tqdm


logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")


[docs]class DownloadProgressBar(tqdm):
[docs] def update_to(self, b=1, bsize=1, tsize=None): if tsize is not None: self.total = tsize self.update(b * bsize - self.n)
[docs]def download_file(url, output_path, overwrite=False): if url is None: raise ValueError("download_file: provided url is None!") if not os.path.exists(output_path) or overwrite: with DownloadProgressBar( unit="B", unit_scale=True, miniters=1, desc=url.split("/")[-1] ) as t: urllib.request.urlretrieve( url, filename=output_path, reporthook=t.update_to ) else: logging.info( f"file exists in {output_path}. specify overwrite=True if intended" )
BANDS = ["B3", "B4", "B5", "B6", "B7", "B8", "B11", "B12", "NDVI", "NDWI", "Brightness"]
[docs]class EOPatchCrops(CropsDataset): """EOPatchCrops - a crop type classification dataset""" def __init__(self, config): super().__init__(config) self.root = self.config.root self.regions = self.config.regions self.indexfile = os.path.join(self.config.root, self.config.csv_file_path) self.h5path = {} self.split_sets = ["train", "test", "val"] for region in self.split_sets: self.h5path[region] = os.path.join(self.config.root, f"{region}.hdf5") self.classmappingfile = os.path.join(self.config.root, "classmapping.csv") self.load_classmapping(self.classmappingfile) # Only do the timeseries (breizhcrops) file structure generation once, if a general index doesn't exist if not os.path.isfile(self.indexfile): self.preprocess() self.selected_bands = BANDS self.index = pd.read_csv( os.path.join(self.config.root, f"{self.regions[0]}.csv"), index_col=None ) for region in self.regions[1:]: region_ind = pd.read_csv( os.path.join(self.config.root, f"{region}.csv"), index_col=None ) self.index = pd.concat([self.index, region_ind], axis=0, ignore_index=True) self.X_list = None
[docs] def preprocess(self): self.eopatches = [ f.name for f in os.scandir(os.path.join(self.root, "eopatches")) if f.is_dir() ] self.indexfile = os.path.join(self.root, "index.csv") columns = [ "path", "eopatch", "polygon_id", "CODE_CULTU", "sequencelength", "classid", "classname", "region", ] list_index = list() for patch in self.eopatches: eop = EOPatch.load(os.path.join(self.root, "eopatches", patch)) polygons = eop.vector_timeless["CROP_TYPE_GDF"] for row in polygons.itertuples(): if row.ct_eu_code not in self.mapping.index.values: continue poly_id = int(row.polygon_id) classid = self.mapping.loc[row.ct_eu_code].id classname = self.mapping.loc[row.ct_eu_code].classname list_index.append( { columns[0]: os.path.join(patch, str(poly_id)), columns[1]: patch, columns[2]: poly_id, columns[3]: row.ct_eu_code, columns[4]: 0, columns[5]: classid, columns[6]: classname, columns[7]: "", } ) self.index = pd.DataFrame(list_index) self.split() f = {} for set in self.split_sets: f[set] = h5py.File(self.h5path[set], "w") self.index.set_index("path", drop=False, inplace=True) for patch in self.eopatches: eop = EOPatch.load(os.path.join(self.root, "eopatches", patch)) polygons = eop.vector_timeless["CROP_TYPE_GDF"] for row in polygons.itertuples(): if row.ct_eu_code not in self.mapping.index.values: continue poly_id = int(row.polygon_id) index_row = self.index.loc[os.path.join(patch, str(poly_id))] polygon = polygons[polygons.polygon_id == poly_id] temp = VectorToRasterTask( vector_input=polygon, raster_feature=(FeatureType.MASK_TIMELESS, "poly"), values=1, raster_shape=(FeatureType.MASK_TIMELESS, "CROP_TYPE"), ) polygon_indicator_mask = temp.execute(eop).mask_timeless["poly"] seq_length = eop.data["FEATURES_S2"].shape[0] num_bands = eop.data["FEATURES_S2"].shape[3] polygon_indicator_mask_ts = np.repeat( polygon_indicator_mask[np.newaxis, :, :, :], seq_length, axis=0 ) polygon_indicator_mask_ts = np.repeat( polygon_indicator_mask_ts, num_bands, axis=3 ) temp_X = np.sum( np.multiply(polygon_indicator_mask_ts, eop.data["FEATURES_S2"]), axis=(1, 2), ) dset = f[index_row.region].create_dataset( patch + os.sep + str(poly_id), data=temp_X ) self.index.reset_index(inplace=True, drop=True) self.write_index()
[docs] def split(self): X_train, X_test, y_train, y_test = train_test_split( self.index.values, self.index.classid.values, test_size=0.15, random_state=1 ) X_train, X_val, y_train, y_val = train_test_split( X_train, y_train, test_size=0.15, random_state=1 ) X_train = pd.DataFrame(X_train, columns=self.index.columns) X_train["region"] = "train" X_train.to_csv(os.path.join(self.root, "train.csv")) X_test = pd.DataFrame(X_test, columns=self.index.columns) X_test["region"] = "test" X_test.to_csv(os.path.join(self.root, "test.csv")) X_val = pd.DataFrame(X_val, columns=self.index.columns) X_val["region"] = "val" X_val.to_csv(os.path.join(self.root, "val.csv")) self.index = pd.concat([X_train, X_val, X_test], ignore_index=True)
[docs] def write_index(self): self.index.to_csv(self.indexfile)