├── README.md ├── outputs ├── crop_classes.png └── orange_rive.png ├── presentation └── images │ ├── Sentinel2_band_info.png │ ├── eo-learn-logo.png │ └── postGIS_logo.jpeg └── work_flow ├── .Rhistory ├── .ipynb_checkpoints ├── 01_data_preprocessing-checkpoint.ipynb ├── 01_pre_processing_alt-checkpoint.ipynb ├── 02-create-features-checkpoint.ipynb ├── 03-Modeling_binary-checkpoint.ipynb ├── Modeling-multiclass-checkpoint.ipynb └── Visualization-checkpoint.ipynb ├── 01_data_preprocessing.ipynb ├── 01_pre_processing_alt.ipynb ├── 02-create-features.ipynb ├── 03-Modeling_binary.ipynb ├── Modeling-multiclass.ipynb ├── Visualization.ipynb └── data_munging.R /README.md: -------------------------------------------------------------------------------- 1 | # Classifying Crop Type using Satellite Imagery 2 | 3 | This was part of a Zindi coding challenge and the source data can be found here: https://zindi.africa/competitions/farm-pin-crop-detection-challenge/data 4 | 5 | ## Notebook Workflow 6 | 1. 01-Pre-processing - read data in from PostGIS and join it with other relational tables in the dataset. This was also a first step to look at the data. 7 | 2. 02-create-features - write functions to calculate each vegetation index based on spectral bands. For each veg index calculate the mean and standard deviation across time and save as a multiband raster. I used 6 different vegetation inices. 8 | 3. 03-modeling-binary - model and hyperparameter selection using grid search and cross validation using 4 different kinds of models: logistic regression, random forests, support vector classification, and k-nearest neighbors. 9 | 4. I included a multi-class notebook to show that I tried! 10 | 5. Visualization is not included because it was done in a variety of programs, mainly QGIS and Tableau. 11 | 12 | ## Overview 13 | One of the United Nations sustainable development goals is “zero hunger by 2030.” Hunger and malnutrition remain a significant barrier to development in Africa. Collecting accurate data is critical for monitoring agricultural growth and improving food security. I will be using data from a Zindi challenge, which is an African data science platform that focuses on using data science for social benefit. 14 | 15 | This project is a stepping stone to more advanced predictions such as crop yield prediction and predicted food security under future climate change scenarios which I am interested in doing for my final project. 16 | 17 | 18 | ## Goals 19 | The objective of this project is to create a classification model to identify vineyards using Sentinel-2 satellite imagery. The end result will be a map of classified fields (Vinyard or not) for the agricultural region along the Orange river. 20 | 21 | 22 | ## Data 23 | The fields in the training set are along the Orange River, a major agricultural region in South Africa that have been verified in person and with drones in 2017. 24 | 25 | There are 7 crop types present in the fields: 26 | 27 | 1. Cotton 28 | 2. Dates 29 | 3. Grass 30 | 4. Lucern 31 | 5. Maize 32 | 6. Pecan 33 | 7. Vacant 34 | 8. Vineyard 35 | 9. Vineyard & Pecan ("Intercrop") 36 | 37 | ## Files included in the dataset: 38 | - Orange River Climate: Useful background information 39 | - Orange River Crop Grown Stages: Useful background information 40 | - Train.zip: shapefile containing all of the fields in the training dataset. This is the dataset that you will use to train your model. 41 | - Test.zip: shapefile containing all of the fields in the test dataset. 42 | - Crop_id_list.csv: List of all the unique crops and their Crop IDs 43 | - Satellite images tile 1 are the 11 files named as YYYY-MM-DD.zip: These are Sentinel-2 satellite data captured on the date indicated in the file name. These files are in SENTINEL-SAFE format, including image data in JPEG2000 format, quality indicators (e.g. defective pixels mask), auxiliary data and metadata. This includes all bands and TCI. Each image contains 90% fields in both the training and test set. 44 | - Satellite images tile 2 are the 11 files named as YYYY-MM-DD-JFP.zip: These are Sentinel-2 satellite data captured on the date indicated in the file name. These files are in SENTINEL-SAFE format, including image data in JPEG2000 format, quality indicators (e.g. defective pixels mask), auxiliary data and metadata. This includes all bands and TCI. Each image contains the remaining 10% of fields in both the training and test set. 45 | - The two tiles make up the entire scene. 90% of the fields are in tile 1 and the remaining 10% of the fields are in tile 2. 46 | -------------------------------------------------------------------------------- /outputs/crop_classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sauer3/crop-classification/dbbfa49782fa141d93e4450307656188927219a9/outputs/crop_classes.png -------------------------------------------------------------------------------- /outputs/orange_rive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sauer3/crop-classification/dbbfa49782fa141d93e4450307656188927219a9/outputs/orange_rive.png -------------------------------------------------------------------------------- /presentation/images/Sentinel2_band_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sauer3/crop-classification/dbbfa49782fa141d93e4450307656188927219a9/presentation/images/Sentinel2_band_info.png -------------------------------------------------------------------------------- /presentation/images/eo-learn-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sauer3/crop-classification/dbbfa49782fa141d93e4450307656188927219a9/presentation/images/eo-learn-logo.png -------------------------------------------------------------------------------- /presentation/images/postGIS_logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sauer3/crop-classification/dbbfa49782fa141d93e4450307656188927219a9/presentation/images/postGIS_logo.jpeg -------------------------------------------------------------------------------- /work_flow/.Rhistory: -------------------------------------------------------------------------------- 1 | library(raster) 2 | library(rgeos) 3 | library(rgdal) 4 | orange_river <- readOGR('/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'orange_river_crop_img') 5 | img <- stack('/Users/AuerPower/Metis/git/crop-classification/data/intermediate/img_crop.tif') 6 | ### Extract img raster values to crop polygons 7 | orange_river_buff <- buffer(orange_river, width=20) 8 | ### create points within polygons 9 | samples <- spsample(orange_river_buff , n=1000, "random") 10 | #coords <- coordinates(samples) 11 | #coord_df <- data.frame(coords) 12 | #names(coords) <- c('x', 'y') 13 | #points <- SpatialPointsDataFrame(coords, data=coord_df, proj4string=crs(orange_river)) 14 | samples_img <- extract(img, samples, method='simple', sp=TRUE) 15 | samples_crop <- extract(orange_river, samples_img, method='simple', sp=TRUE) 16 | head(samples_crop) 17 | samples_join <- merge(samples_crop, samples_img) 18 | samples_join <- join(samples_crop, samples_img) 19 | samples_img <- extract(img, samples, method='simple', sp=TRUE) 20 | samples_img <- as.data.frame(samples_img) 21 | samples_img <- extract(img, samples, method='simple', sp=TRUE) 22 | samples_img <- as.data.frame(samples_img, xy=TRUE) 23 | samples_crop <- extract(orange_river, samples, method='simple', sp=TRUE) 24 | samples_crop <- as.data.frame(samples_crop, xy=TRUE) 25 | View(samples_img) 26 | View(samples_crop) 27 | samples_join <- merge(samples_crop, samples_img) 28 | View(samples_join) 29 | samples_join <- cbind(samples_crop, samples_img) 30 | View(samples_join) 31 | samples_join <- SpatialPointsDataFrame(samples_join) 32 | samples_join <- SpatialPointsDataFrame(coords=samples_join[c('x', 'y')], samples_join, proj4string=crs(orange_river)) 33 | head(samples_join) 34 | writeOGR(samples_join, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'samples', driver = "ESRI Shapefile") 35 | ### Extract img raster values to crop polygons 36 | orange_river_buff <- buffer(orange_river, width=20) 37 | ### create points within polygons 38 | samples <- spsample(orange_river_buff , n=10000, "random") 39 | #coords <- coordinates(samples) 40 | #coord_df <- data.frame(coords) 41 | #names(coords) <- c('x', 'y') 42 | #points <- SpatialPointsDataFrame(coords, data=coord_df, proj4string=crs(orange_river)) 43 | ### extract values from crop polygon and img bands 44 | #samples2 <- extract(orange_river, samples, method='simple', sp=TRUE) 45 | #samples_crop <- over(points, orange_river) 46 | #samples_crop <- extract(orange_river, samples, method='simple', sp=TRUE) 47 | samples_img <- extract(img, samples, method='simple', sp=TRUE) 48 | samples_img <- as.data.frame(samples_img, xy=TRUE) 49 | samples_crop <- extract(orange_river, samples, method='simple', sp=TRUE) 50 | samples_crop <- as.data.frame(samples_crop, xy=TRUE) 51 | samples_join <- cbind(samples_crop, samples_img) 52 | samples_join <- SpatialPointsDataFrame(coords=samples_join[c('x', 'y')], samples_join, proj4string=crs(orange_river)) 53 | writeOGR(samples_join, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'samples', driver = "ESRI Shapefile" , overwrite_layer = TRUE) 54 | samples_crop <- extract(orange_river, samples_img, method='simple', sp=TRUE) 55 | samples_crop <- extract(orange_river, samples_img[c('x', 'y')], method='simple', sp=TRUE) 56 | View(samples_crop) 57 | head(orange_river) 58 | orange_river_ras = rasterize(orange_river, img[[1]], 'Crop_Id_Ne') 59 | plot(orange_river_ras) 60 | img <- stack('/Users/AuerPower/Metis/git/crop-classification/data/intermediate/veg_indices.tiff') 61 | plot(img[[6]]) 62 | img <- crop(img, orange_river) 63 | plot(img[[5]]) 64 | plot(orange_river, add=TRUE) 65 | orange_river_ras = rasterize(orange_river, img[[4]], 'Crop_Id_Ne') 66 | samples_img <- extract(img, orange_river_ras, method='simple', sp=TRUE) 67 | plot(orange_river_ras) 68 | orange_river_points <- rasterToPoints(orange_river_ras, fun=NULL, spatial=TRUE) 69 | samples_img <- extract(img, orange_river_points, method='simple', sp=TRUE) 70 | head(samples_img) 71 | unique(samples_img$layer) 72 | plot(orange_river_ras) 73 | samples_img_df <- as.data.frame(samples_img, xy=TRUE) 74 | writeOGR(samples_img, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'samples', driver = "ESRI Shapefile" , overwrite_layer = TRUE) 75 | write.csv(samples_img_df, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate/samples_df.csv') 76 | head(orange_river) 77 | orange_river_ras <- rasterize(orange_river, img[[4]], 'Area Subregion') 78 | orange_river_ras <- rasterize(orange_river, img[[4]], 'Subregion') 79 | orange_river_region <- rasterize(orange_river, img[[4]], 'Subregion') 80 | plot(orange_river_region) 81 | head(orange_river_region) 82 | orange_river_region@data 83 | orange_river_region_points <- rasterToPoints(orange_river_region, fun=NULL, spatial=TRUE) 84 | head(orange_river_region_points) 85 | orange_river_merge <- merge(orange_river_points, orange_river_region_points) 86 | writeOGR(orange_river_region_points, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 87 | 'region_points', driver = "ESRI Shapefile") 88 | orange_river_region <- rasterize(orange_river, img[[4]], 'Field_Id') 89 | orange_river_region_points <- rasterToPoints(orange_river_region, fun=NULL, spatial=TRUE) 90 | writeOGR(orange_river_region_points, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 91 | 'fieldID_points', driver = "ESRI Shapefile") 92 | samples_img <- extract(img, orange_river_points, method='bilinear', sp=TRUE) 93 | samples_img_df <- as.data.frame(samples_img, xy=TRUE) 94 | writeOGR(samples_img, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'samples', driver = "ESRI Shapefile" , overwrite_layer = TRUE) 95 | write.csv(samples_img_df, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate/samples_df.csv') 96 | -------------------------------------------------------------------------------- /work_flow/.ipynb_checkpoints/Visualization-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": {}, 4 | "nbformat": 4, 5 | "nbformat_minor": 2 6 | } 7 | -------------------------------------------------------------------------------- /work_flow/01_pre_processing_alt.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 6, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "#Jupyter notebook related\n", 10 | "%reload_ext autoreload\n", 11 | "%autoreload 2\n", 12 | "%matplotlib inline\n", 13 | "\n", 14 | "# Built-in modules\n", 15 | "import pickle\n", 16 | "import sys\n", 17 | "import os\n", 18 | "import datetime\n", 19 | "import itertools\n", 20 | "from enum import Enum\n", 21 | "\n", 22 | "# PostGIS\n", 23 | "import psycopg2 as pg\n", 24 | "import pandas as pd\n", 25 | "import pandas.io.sql as pd_sql\n", 26 | "\n", 27 | "# Basics of Python data handling and visualization\n", 28 | "import numpy as np\n", 29 | "import geopandas as gpd\n", 30 | "import matplotlib as mpl\n", 31 | "import matplotlib.pyplot as plt\n", 32 | "import matplotlib.gridspec as gridspec\n", 33 | "import seaborn as sns\n", 34 | "from mpl_toolkits.axes_grid1 import make_axes_locatable\n", 35 | "from shapely.geometry import Polygon\n", 36 | "from tqdm import tqdm_notebook as tqdm\n", 37 | "\n", 38 | "# Machine learning \n", 39 | "import lightgbm as lgb\n", 40 | "from sklearn.externals import joblib\n", 41 | "from sklearn import metrics\n", 42 | "from sklearn import preprocessing\n", 43 | "\n", 44 | "# Imports from eo-learn and sentinelhub-py\n", 45 | "from eolearn.core import EOTask, EOPatch, LinearWorkflow, FeatureType, OverwritePermission, \\\n", 46 | " LoadFromDisk, SaveToDisk, EOExecutor\n", 47 | "from eolearn.io import S2L1CWCSInput, ExportToTiff\n", 48 | "from eolearn.mask import AddCloudMaskTask, get_s2_pixel_cloud_detector, AddValidDataMaskTask\n", 49 | "from eolearn.geometry import VectorToRaster, PointSamplingTask, ErosionTask\n", 50 | "from eolearn.features import LinearInterpolation, SimpleFilterTask\n", 51 | "from sentinelhub import BBoxSplitter, BBox, CRS, CustomUrlParam\n", 52 | "\n", 53 | "# additional needed for EO learn workflow section\n", 54 | "from scipy import stats\n", 55 | "from pathlib import Path\n", 56 | "from tqdm import tqdm \n", 57 | "from contextlib import contextmanager \n", 58 | "\n", 59 | "import rasterio\n", 60 | "from rasterio import Affine, MemoryFile\n", 61 | "from rasterio.enums import Resampling\n", 62 | "\n", 63 | "from eolearn.io.local_io import *\n", 64 | "#from eolearn.mask.utilities import resize_images\n", 65 | "from eolearn.features import LinearInterpolation, SimpleFilterTask\n", 66 | "\n", 67 | "from eolearn.features import ValueFilloutTask, InterpolationTask\n", 68 | "from eolearn.features import HaralickTask, AddMaxMinNDVISlopeIndicesTask\n", 69 | "from eolearn.features.temporal_features import AddMaxMinTemporalIndicesTask, AddSpatioTemporalFeaturesTask\n", 70 | "from eolearn.features import HOGTask, MaxNDVICompositing, LocalBinaryPatternTask\n" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 2, 76 | "metadata": {}, 77 | "outputs": [ 78 | { 79 | "name": "stdout", 80 | "output_type": "stream", 81 | "text": [ 82 | "Collecting package metadata (current_repodata.json): done\n", 83 | "Solving environment: failed with initial frozen solve. Retrying with flexible solve.\n", 84 | "Collecting package metadata (repodata.json): done\n", 85 | "Solving environment: done\n", 86 | "\n", 87 | "\n", 88 | "==> WARNING: A newer version of conda exists. <==\n", 89 | " current version: 4.8.1\n", 90 | " latest version: 4.8.2\n", 91 | "\n", 92 | "Please update conda by running\n", 93 | "\n", 94 | " $ conda update -n base -c defaults conda\n", 95 | "\n", 96 | "\n", 97 | "\n", 98 | "## Package Plan ##\n", 99 | "\n", 100 | " environment location: /Users/AuerPower/opt/miniconda3/envs/metis\n", 101 | "\n", 102 | " added / updated specs:\n", 103 | " - eo-learn-core==0.6.0\n", 104 | "\n", 105 | "\n", 106 | "The following packages will be downloaded:\n", 107 | "\n", 108 | " package | build\n", 109 | " ---------------------------|-----------------\n", 110 | " eo-learn-core-0.6.0 | py_0 33 KB conda-forge\n", 111 | " ------------------------------------------------------------\n", 112 | " Total: 33 KB\n", 113 | "\n", 114 | "The following packages will be DOWNGRADED:\n", 115 | "\n", 116 | " eo-learn-core 0.7.0-py_0 --> 0.6.0-py_0\n", 117 | "\n", 118 | "\n", 119 | "\n", 120 | "Downloading and Extracting Packages\n", 121 | "eo-learn-core-0.6.0 | 33 KB | ##################################### | 100% \n", 122 | "Preparing transaction: done\n", 123 | "Verifying transaction: done\n", 124 | "Executing transaction: done\n", 125 | "Collecting package metadata (current_repodata.json): done\n", 126 | "Solving environment: failed with initial frozen solve. Retrying with flexible solve.\n", 127 | "Collecting package metadata (repodata.json): done\n", 128 | "Solving environment: done\n", 129 | "\n", 130 | "\n", 131 | "==> WARNING: A newer version of conda exists. <==\n", 132 | " current version: 4.8.1\n", 133 | " latest version: 4.8.2\n", 134 | "\n", 135 | "Please update conda by running\n", 136 | "\n", 137 | " $ conda update -n base -c defaults conda\n", 138 | "\n", 139 | "\n", 140 | "\n", 141 | "## Package Plan ##\n", 142 | "\n", 143 | " environment location: /Users/AuerPower/opt/miniconda3/envs/metis\n", 144 | "\n", 145 | " added / updated specs:\n", 146 | " - eo-learn-coregistration==0.6.0\n", 147 | "\n", 148 | "\n", 149 | "The following packages will be downloaded:\n", 150 | "\n", 151 | " package | build\n", 152 | " ---------------------------|-----------------\n", 153 | " eo-learn-coregistration-0.6.0| py_0 13 KB conda-forge\n", 154 | " ------------------------------------------------------------\n", 155 | " Total: 13 KB\n", 156 | "\n", 157 | "The following packages will be UPDATED:\n", 158 | "\n", 159 | " eo-learn-coregist~ sentinel-hub::eo-learn-coregistration~ --> conda-forge::eo-learn-coregistration-0.6.0-py_0\n", 160 | "\n", 161 | "\n", 162 | "\n", 163 | "Downloading and Extracting Packages\n", 164 | "eo-learn-coregistrat | 13 KB | ##################################### | 100% \n", 165 | "Preparing transaction: done\n", 166 | "Verifying transaction: done\n", 167 | "Executing transaction: done\n", 168 | "Collecting package metadata (current_repodata.json): done\n", 169 | "Solving environment: failed with initial frozen solve. Retrying with flexible solve.\n", 170 | "Collecting package metadata (repodata.json): done\n", 171 | "Solving environment: done\n", 172 | "\n", 173 | "\n", 174 | "==> WARNING: A newer version of conda exists. <==\n", 175 | " current version: 4.8.1\n", 176 | " latest version: 4.8.2\n", 177 | "\n", 178 | "Please update conda by running\n", 179 | "\n", 180 | " $ conda update -n base -c defaults conda\n", 181 | "\n", 182 | "\n", 183 | "\n", 184 | "## Package Plan ##\n", 185 | "\n", 186 | " environment location: /Users/AuerPower/opt/miniconda3/envs/metis\n", 187 | "\n", 188 | " added / updated specs:\n", 189 | " - eo-learn-features==0.6.0\n", 190 | "\n", 191 | "\n", 192 | "The following packages will be downloaded:\n", 193 | "\n", 194 | " package | build\n", 195 | " ---------------------------|-----------------\n", 196 | " eo-learn-features-0.6.0 | py_0 27 KB conda-forge\n", 197 | " ------------------------------------------------------------\n", 198 | " Total: 27 KB\n", 199 | "\n", 200 | "The following packages will be UPDATED:\n", 201 | "\n", 202 | " eo-learn-features sentinel-hub::eo-learn-features-0.4.2~ --> conda-forge::eo-learn-features-0.6.0-py_0\n", 203 | "\n", 204 | "\n", 205 | "\n", 206 | "Downloading and Extracting Packages\n", 207 | "eo-learn-features-0. | 27 KB | ##################################### | 100% \n", 208 | "Preparing transaction: done\n", 209 | "Verifying transaction: done\n", 210 | "Executing transaction: done\n", 211 | "Collecting package metadata (current_repodata.json): done\n", 212 | "Solving environment: failed with initial frozen solve. Retrying with flexible solve.\n", 213 | "Collecting package metadata (repodata.json): done\n", 214 | "Solving environment: done\n", 215 | "\n", 216 | "\n", 217 | "==> WARNING: A newer version of conda exists. <==\n", 218 | " current version: 4.8.1\n", 219 | " latest version: 4.8.2\n", 220 | "\n", 221 | "Please update conda by running\n", 222 | "\n", 223 | " $ conda update -n base -c defaults conda\n", 224 | "\n", 225 | "\n", 226 | "\n", 227 | "## Package Plan ##\n", 228 | "\n", 229 | " environment location: /Users/AuerPower/opt/miniconda3/envs/metis\n", 230 | "\n", 231 | " added / updated specs:\n", 232 | " - eo-learn-geometry==0.6.0\n", 233 | "\n", 234 | "\n", 235 | "The following packages will be downloaded:\n", 236 | "\n", 237 | " package | build\n", 238 | " ---------------------------|-----------------\n", 239 | " eo-learn-geometry-0.6.0 | py37_0 28 KB conda-forge\n", 240 | " ------------------------------------------------------------\n", 241 | " Total: 28 KB\n", 242 | "\n", 243 | "The following packages will be UPDATED:\n", 244 | "\n", 245 | " eo-learn-geometry sentinel-hub/noarch::eo-learn-geometr~ --> conda-forge/osx-64::eo-learn-geometry-0.6.0-py37_0\n", 246 | "\n", 247 | "\n", 248 | "\n", 249 | "Downloading and Extracting Packages\n", 250 | "eo-learn-geometry-0. | 28 KB | ##################################### | 100% \n", 251 | "Preparing transaction: done\n", 252 | "Verifying transaction: done\n", 253 | "Executing transaction: done\n", 254 | "Collecting package metadata (current_repodata.json): done\n", 255 | "Solving environment: done\n", 256 | "\n", 257 | "\n", 258 | "==> WARNING: A newer version of conda exists. <==\n", 259 | " current version: 4.8.1\n", 260 | " latest version: 4.8.2\n", 261 | "\n", 262 | "Please update conda by running\n", 263 | "\n", 264 | " $ conda update -n base -c defaults conda\n", 265 | "\n", 266 | "\n", 267 | "\n", 268 | "# All requested packages already installed.\n", 269 | "\n", 270 | "Collecting package metadata (current_repodata.json): done\n", 271 | "Solving environment: failed with initial frozen solve. Retrying with flexible solve.\n", 272 | "Collecting package metadata (repodata.json): done\n", 273 | "Solving environment: done\n", 274 | "\n", 275 | "\n", 276 | "==> WARNING: A newer version of conda exists. <==\n", 277 | " current version: 4.8.1\n", 278 | " latest version: 4.8.2\n", 279 | "\n", 280 | "Please update conda by running\n", 281 | "\n", 282 | " $ conda update -n base -c defaults conda\n", 283 | "\n", 284 | "\n", 285 | "\n", 286 | "## Package Plan ##\n", 287 | "\n", 288 | " environment location: /Users/AuerPower/opt/miniconda3/envs/metis\n", 289 | "\n", 290 | " added / updated specs:\n", 291 | " - eo-learn-mask==0.6.0\n", 292 | "\n", 293 | "\n", 294 | "The following packages will be downloaded:\n", 295 | "\n", 296 | " package | build\n", 297 | " ---------------------------|-----------------\n", 298 | " eo-learn-mask-0.6.0 | py37_0 26 KB conda-forge\n", 299 | " python-graphviz-0.13.2 | py_0 18 KB conda-forge\n", 300 | " s2cloudless-1.4.0 | py_0 3.6 MB conda-forge\n", 301 | " ------------------------------------------------------------\n", 302 | " Total: 3.6 MB\n", 303 | "\n", 304 | "The following NEW packages will be INSTALLED:\n", 305 | "\n", 306 | " python-graphviz conda-forge/noarch::python-graphviz-0.13.2-py_0\n", 307 | "\n", 308 | "The following packages will be UPDATED:\n", 309 | "\n", 310 | " eo-learn-mask sentinel-hub/noarch::eo-learn-mask-0.~ --> conda-forge/osx-64::eo-learn-mask-0.6.0-py37_0\n", 311 | " s2cloudless sentinel-hub::s2cloudless-1.2.2-py_0 --> conda-forge::s2cloudless-1.4.0-py_0\n", 312 | "\n", 313 | "\n", 314 | "\n", 315 | "Downloading and Extracting Packages\n", 316 | "s2cloudless-1.4.0 | 3.6 MB | ##################################### | 100% \n", 317 | "eo-learn-mask-0.6.0 | 26 KB | ##################################### | 100% \n", 318 | "python-graphviz-0.13 | 18 KB | ##################################### | 100% \n", 319 | "Preparing transaction: done\n", 320 | "Verifying transaction: done\n", 321 | "Executing transaction: done\n", 322 | "Collecting package metadata (current_repodata.json): done\n", 323 | "Solving environment: failed with initial frozen solve. Retrying with flexible solve.\n", 324 | "Collecting package metadata (repodata.json): done\n", 325 | "Solving environment: done\n", 326 | "\n", 327 | "\n", 328 | "==> WARNING: A newer version of conda exists. <==\n", 329 | " current version: 4.8.1\n", 330 | " latest version: 4.8.2\n", 331 | "\n", 332 | "Please update conda by running\n", 333 | "\n", 334 | " $ conda update -n base -c defaults conda\n", 335 | "\n", 336 | "\n", 337 | "\n", 338 | "## Package Plan ##\n", 339 | "\n", 340 | " environment location: /Users/AuerPower/opt/miniconda3/envs/metis\n", 341 | "\n", 342 | " added / updated specs:\n", 343 | " - eo-learn-ml-tools==0.6.0\n", 344 | "\n", 345 | "\n", 346 | "The following packages will be downloaded:\n", 347 | "\n", 348 | " package | build\n", 349 | " ---------------------------|-----------------\n", 350 | " eo-learn-ml-tools-0.6.0 | py_0 17 KB conda-forge\n", 351 | " ------------------------------------------------------------\n", 352 | " Total: 17 KB\n", 353 | "\n", 354 | "The following packages will be UPDATED:\n", 355 | "\n", 356 | " eo-learn-ml-tools sentinel-hub::eo-learn-ml-tools-0.4.2~ --> conda-forge::eo-learn-ml-tools-0.6.0-py_0\n", 357 | "\n", 358 | "\n", 359 | "\n", 360 | "Downloading and Extracting Packages\n", 361 | "eo-learn-ml-tools-0. | 17 KB | ##################################### | 100% \n", 362 | "Preparing transaction: done\n", 363 | "Verifying transaction: done\n", 364 | "Executing transaction: done\n", 365 | "Collecting package metadata (current_repodata.json): done\n", 366 | "Solving environment: failed with initial frozen solve. Retrying with flexible solve.\n", 367 | "Collecting package metadata (repodata.json): done\n", 368 | "Solving environment: done\n", 369 | "\n", 370 | "\n", 371 | "==> WARNING: A newer version of conda exists. <==\n", 372 | " current version: 4.8.1\n", 373 | " latest version: 4.8.2\n", 374 | "\n", 375 | "Please update conda by running\n", 376 | "\n", 377 | " $ conda update -n base -c defaults conda\n", 378 | "\n", 379 | "\n", 380 | "\n", 381 | "## Package Plan ##\n", 382 | "\n", 383 | " environment location: /Users/AuerPower/opt/miniconda3/envs/metis\n", 384 | "\n", 385 | " added / updated specs:\n", 386 | " - eo-learn-visualization==0.6.0\n", 387 | "\n", 388 | "\n", 389 | "The following packages will be downloaded:\n", 390 | "\n", 391 | " package | build\n", 392 | " ---------------------------|-----------------\n", 393 | " cartopy-0.17.0 |py37h6f81845_1010 1.7 MB conda-forge\n", 394 | " cftime-1.0.4.2 | py37h3b54f70_0 263 KB conda-forge\n", 395 | " colorcet-2.0.1 | py_0 1.5 MB conda-forge\n", 396 | " datashader-0.10.0 | py_0 14.0 MB conda-forge\n", 397 | " datashape-0.5.4 | py_1 49 KB conda-forge\n", 398 | " eo-learn-visualization-0.6.0| py_0 15 KB conda-forge\n", 399 | " geoviews-1.6.6 | py_1 4 KB conda-forge\n", 400 | " geoviews-core-1.6.6 | py_1 348 KB conda-forge\n", 401 | " holoviews-1.12.7 | py_0 3.3 MB conda-forge\n", 402 | " hvplot-0.5.2 | py_0 2.4 MB conda-forge\n", 403 | " netcdf4-1.5.3 |nompi_py37hcf2264a_102 473 KB conda-forge\n", 404 | " owslib-0.19.1 | py_0 126 KB conda-forge\n", 405 | " param-1.9.3 | py_0 60 KB conda-forge\n", 406 | " pyct-0.4.6 | py_0 3 KB conda-forge\n", 407 | " pyct-core-0.4.6 | py_0 13 KB conda-forge\n", 408 | " pyviz_comms-0.7.3 | py_0 13 KB conda-forge\n", 409 | " xarray-0.15.0 | py_0 476 KB conda-forge\n", 410 | " ------------------------------------------------------------\n", 411 | " Total: 24.7 MB\n", 412 | "\n", 413 | "The following NEW packages will be INSTALLED:\n", 414 | "\n", 415 | " cartopy conda-forge/osx-64::cartopy-0.17.0-py37h6f81845_1010\n", 416 | " cftime conda-forge/osx-64::cftime-1.0.4.2-py37h3b54f70_0\n", 417 | " colorcet conda-forge/noarch::colorcet-2.0.1-py_0\n", 418 | " datashader conda-forge/noarch::datashader-0.10.0-py_0\n", 419 | " datashape conda-forge/noarch::datashape-0.5.4-py_1\n", 420 | " eo-learn-visualiz~ conda-forge/noarch::eo-learn-visualization-0.6.0-py_0\n", 421 | " geoviews conda-forge/noarch::geoviews-1.6.6-py_1\n", 422 | " geoviews-core conda-forge/noarch::geoviews-core-1.6.6-py_1\n", 423 | " holoviews conda-forge/noarch::holoviews-1.12.7-py_0\n", 424 | " hvplot conda-forge/noarch::hvplot-0.5.2-py_0\n", 425 | " netcdf4 conda-forge/osx-64::netcdf4-1.5.3-nompi_py37hcf2264a_102\n", 426 | " owslib conda-forge/noarch::owslib-0.19.1-py_0\n", 427 | " param conda-forge/noarch::param-1.9.3-py_0\n", 428 | " pyct conda-forge/noarch::pyct-0.4.6-py_0\n", 429 | " pyct-core conda-forge/noarch::pyct-core-0.4.6-py_0\n", 430 | " pyepsg conda-forge/noarch::pyepsg-0.4.0-py_0\n", 431 | " pykdtree conda-forge/osx-64::pykdtree-1.3.1-py37h3b54f70_1002\n", 432 | " pyshp conda-forge/noarch::pyshp-2.1.0-py_0\n", 433 | " pyviz_comms conda-forge/noarch::pyviz_comms-0.7.3-py_0\n", 434 | " xarray conda-forge/noarch::xarray-0.15.0-py_0\n", 435 | "\n", 436 | "\n", 437 | "\n", 438 | "Downloading and Extracting Packages\n", 439 | "pyviz_comms-0.7.3 | 13 KB | ##################################### | 100% \n", 440 | "geoviews-1.6.6 | 4 KB | ##################################### | 100% \n", 441 | "datashape-0.5.4 | 49 KB | ##################################### | 100% \n", 442 | "cftime-1.0.4.2 | 263 KB | ##################################### | 100% \n", 443 | "pyct-0.4.6 | 3 KB | ##################################### | 100% \n", 444 | "pyct-core-0.4.6 | 13 KB | ##################################### | 100% \n", 445 | "owslib-0.19.1 | 126 KB | ##################################### | 100% \n", 446 | "holoviews-1.12.7 | 3.3 MB | ##################################### | 100% \n", 447 | "hvplot-0.5.2 | 2.4 MB | ##################################### | 100% \n", 448 | "cartopy-0.17.0 | 1.7 MB | ##################################### | 100% \n", 449 | "param-1.9.3 | 60 KB | ##################################### | 100% \n", 450 | "datashader-0.10.0 | 14.0 MB | ##################################### | 100% \n", 451 | "eo-learn-visualizati | 15 KB | ##################################### | 100% \n", 452 | "colorcet-2.0.1 | 1.5 MB | ##################################### | 100% \n", 453 | "xarray-0.15.0 | 476 KB | ##################################### | 100% \n", 454 | "netcdf4-1.5.3 | 473 KB | ##################################### | 100% \n", 455 | "geoviews-core-1.6.6 | 348 KB | ##################################### | 100% \n", 456 | "Preparing transaction: done\n", 457 | "Verifying transaction: done\n", 458 | "Executing transaction: done\n" 459 | ] 460 | } 461 | ], 462 | "source": [ 463 | "# !conda install -y eo-learn-core==0.6.0\n", 464 | "# !conda install -y eo-learn-coregistration==0.6.0\n", 465 | "# !conda install -y eo-learn-features==0.6.0\n", 466 | "# !conda install -y eo-learn-geometry==0.6.0\n", 467 | "# !conda install -y eo-learn-io==0.6.0\n", 468 | "# !conda install -y eo-learn-mask==0.6.0\n", 469 | "# !conda install -y eo-learn-ml-tools==0.6.0\n", 470 | "# !conda install -y eo-learn-visualization==0.6.0" 471 | ] 472 | }, 473 | { 474 | "cell_type": "markdown", 475 | "metadata": {}, 476 | "source": [ 477 | "### Define Study Area" 478 | ] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "execution_count": 7, 483 | "metadata": {}, 484 | "outputs": [ 485 | { 486 | "data": { 487 | "image/png": "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\n", 488 | "text/plain": [ 489 | "
" 490 | ] 491 | }, 492 | "metadata": { 493 | "needs_background": "light" 494 | }, 495 | "output_type": "display_data" 496 | } 497 | ], 498 | "source": [ 499 | "# Postgres info to connect\n", 500 | "connection_args = {\n", 501 | " 'host': 'localhost', # We are connecting to our _local_ version of psql\n", 502 | " 'dbname': 'orange_river', # DB that we are connecting to\n", 503 | " 'port': 5432 # port for psql\n", 504 | "}\n", 505 | "connection = pg.connect(**connection_args)\n", 506 | "\n", 507 | "crop_id = pd.read_csv('/Users/AuerPower/Metis/git/crop-classification/data/crop_id_list.csv')\n", 508 | "\n", 509 | "crop_id.dtypes\n", 510 | "crop_id['crop_id'] = crop_id.crop_id.astype(str)\n", 511 | "\n", 512 | "query = \"SELECT * FROM train;\"\n", 513 | "orange_river = gpd.GeoDataFrame.from_postgis(query, connection, geom_col='geom' )\n", 514 | "orange_river = orange_river.merge(crop_id, how='left', left_on='crop_id_ne', right_on='crop_id')\n", 515 | "\n", 516 | "# Plot study area\n", 517 | "orange_river.plot()\n", 518 | "plt.axis('off');" 519 | ] 520 | }, 521 | { 522 | "cell_type": "markdown", 523 | "metadata": {}, 524 | "source": [ 525 | "### Divide area into a grid of patches\n", 526 | "The eo-learn library allows users to divide an area into patches, define a workflow, and then execute the workflow on the patches in parallel. Modeling with imagery is likely to take a long time because they are large files." 527 | ] 528 | }, 529 | { 530 | "cell_type": "code", 531 | "execution_count": 44, 532 | "metadata": {}, 533 | "outputs": [], 534 | "source": [ 535 | "orange_river = gpd.read_file('/Users/AuerPower/Metis/git/crop-classification/data/train/train.shp')\n", 536 | "# Get the country's shape in polygon format\n", 537 | "#country_shape = country.geometry.values.tolist()[-1]" 538 | ] 539 | }, 540 | { 541 | "cell_type": "code", 542 | "execution_count": 46, 543 | "metadata": {}, 544 | "outputs": [], 545 | "source": [ 546 | "# Necessary to prevent weird non-geometry error when trying to project\n", 547 | "orange_river = orange_river[orange_river.geometry.notnull()]" 548 | ] 549 | }, 550 | { 551 | "cell_type": "code", 552 | "execution_count": 47, 553 | "metadata": {}, 554 | "outputs": [ 555 | { 556 | "name": "stderr", 557 | "output_type": "stream", 558 | "text": [ 559 | "/Users/AuerPower/opt/miniconda3/envs/metis/lib/python3.7/site-packages/pyproj/crs.py:77: FutureWarning: '+init=:' syntax is deprecated. ':' is the preferred initialization method.\n", 560 | " return _prepare_from_string(\" \".join(pjargs))\n" 561 | ] 562 | } 563 | ], 564 | "source": [ 565 | "# Project orange river shape\n", 566 | "orange_river.crs = {'init' :'epsg:4326'}\n", 567 | "#orange_river_crs = CRS.WGS84\n", 568 | "orange_river_crs = CRS.UTM_34S\n", 569 | "orange_river = orange_river.to_crs(epsg=32734)" 570 | ] 571 | }, 572 | { 573 | "cell_type": "code", 574 | "execution_count": 48, 575 | "metadata": {}, 576 | "outputs": [], 577 | "source": [ 578 | "# Create a buffer around union of all shapes\n", 579 | "orange_river = orange_river.geometry.unary_union.buffer(400)" 580 | ] 581 | }, 582 | { 583 | "cell_type": "code", 584 | "execution_count": 54, 585 | "metadata": {}, 586 | "outputs": [], 587 | "source": [ 588 | "#orange_river_buff = gpd.GeoDataFrame(orange_river) \n", 589 | "#orange_river.to_file('/Users/AuerPower/Metis/git/crop-classification/data/intermediate/orange_river_buff.shp')" 590 | ] 591 | }, 592 | { 593 | "cell_type": "code", 594 | "execution_count": 1, 595 | "metadata": { 596 | "ExecuteTime": { 597 | "end_time": "2020-02-09T22:57:42.921000Z", 598 | "start_time": "2020-02-09T22:57:42.900768Z" 599 | } 600 | }, 601 | "outputs": [], 602 | "source": [ 603 | "# Split buffered zone into grid\n", 604 | "bbox_splitter = BBoxSplitter([orange_river], CRS.UTM_34S, (5, 4)) \n", 605 | "#bbox_splitter = BBoxSplitter([orange_river], orange_river_crs, (6,5)) # 6 x 5 gives roughly square boxes\n", 606 | "\n", 607 | "bbox_list = np.array(bbox_splitter.get_bbox_list())\n", 608 | "info_list = np.array(bbox_splitter.get_info_list())\n", 609 | "\n", 610 | "# Create patchIDs\n", 611 | "patchIDs = []\n", 612 | "for idx, [bbox, info] in enumerate(zip(bbox_list, info_list)):\n", 613 | " patchIDs.append(idx)\n", 614 | " \n", 615 | "# Prepare info of selected EOPatches\n", 616 | "geometry = [Polygon(bbox.get_polygon()) for bbox in bbox_list[patchIDs]]\n", 617 | "idxs_x = [info['index_x'] for info in info_list[patchIDs]]\n", 618 | "idxs_y = [info['index_y'] for info in info_list[patchIDs]]\n", 619 | "\n", 620 | "gdf = gpd.GeoDataFrame({'index_x': idxs_x, 'index_y': idxs_y}, \n", 621 | " crs={'init': CRS.ogc_string(orange_river_crs)}, \n", 622 | " geometry=geometry)\n", 623 | "\n", 624 | "# save to shapefile\n", 625 | "shapefile_name = '/Users/AuerPower/Metis/git/crop-classification/data/intermediate/selected_orange_river_bboxes2.shp'\n", 626 | "gdf.to_file(shapefile_name)" 627 | ] 628 | }, 629 | { 630 | "cell_type": "markdown", 631 | "metadata": {}, 632 | "source": [ 633 | "### Plot grid" 634 | ] 635 | }, 636 | { 637 | "cell_type": "code", 638 | "execution_count": 31, 639 | "metadata": {}, 640 | "outputs": [ 641 | { 642 | "data": { 643 | "image/png": "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rqxKT2CP35iMneQ5sG/Y6pxMWZZVaIwZhv0enovdNcwHbMOuflYZo6fieKdij5WKwr55fx94uIYn9Q3CsqxsY8wQ7DmYzsdOOrZh/z4erEchgSONo8QYMwV4EPt9CMWeu6leyVTFvuYaY07AbvE5H7t7WD52t9DHqZhEt5Z9+LCrzL2NnZTcgP0ZyMOeo+m3lmV9Wc/QZmC3Sl2KnRzsBN7ErvxX16Irh4r3YWNMEXAddtfQLVWONwi7Fbhy3bpek8HG4jPGPAI8g11U5b5a1vdWJKvXYCdI79awTnnFQ55p2N0lK/e5A3uetKZK+kXkOGIOrFwrIiIixxNjzF+xk5T2lmUdcgJtERE5mJIpERGR44AxJqzqHFMVy5Kwxz9usSyrd/NEJiJy9FI3PxERkePDKGPMDOxS7tuANOBy7O6iR1rgQkTkuKRkSkRE5PiwAXtM2OXYlfRKgUXY4+0aowS6iMgxT938REREREREgqB5pkRERERERIKgZEpERERERCQISqZERERERESCoGRKREREREQkCEqmREREREREgqBkSkREREREJAhKpkRERERERIKgZEpERERERCQISqZERERERESCoGRKREREREQkCEqmREREREREgqBkSkREREREJAhKpkRERERERIKgZEpERERERCQISqZERERERESCoGRKREREREQkCEqmREREREREgqBkSkREREREJAhKpkRERERERIKgZEpERERERCQISqZERERERESCoGRKREREREQkCEqmREREREREgqBkSkREREREJAhKpkRERERERIKgZEpERERERCQISqZERERERESCoGRKREREREQkCEqmREREREREgqBkSkREREREJAhKpkRERERERIKgZEpERERERCQIruYOQORoYAwOICU2lozkZPq43bQ2hjAgFPB7PGx2u3EHApSXl1NUWsr+8nLKduxgPZAF5FsWVnOeg4iIiIg0LGNZR+H9XadOj5CQ0K65wzieBCzDjyXdoxYGTmyzKzwtNjTgKU/ZvzYvgdyyKKfHXxZwO/L8se4Q4wucELGqsGPozrLmjjloe/emk5i4tvLHL4pPiPtv+MRu8SlR7l6ZltU1ucSXGO31h4YErNAQf8Dnd5jsPeEh4e6A5fMbiktdjtJyh8Prc7Bxs9OxaZNFSX5p+QnFX2wZHPpjQap7Z6nLBJrz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Xz8c1dWktnlNnW6pn8KUiIiIiIgE1fDh1JWWYvBl9Hl8PJ6sLEybWvLjQl9ZcClMiYiIiIhIUG3cSEJiou9DJbKzMRxsS/VpWWAkUZgSEREREZGgWrqU3J/+FKfRx7TRrRveI95kS2irCj6FKRERERERCRqPB2pqsGVm0ubrPUlJeBqiullDWVcoKEyJiIiIiEjQvPcemampJPbo4XuYiorC6zJGdbps0ukKFhERERGRyLVyJf0uu4zm6Gi8vt5z6BDmJGdNayjrCgWFKRERERERCZrGRuJ69vS9K1VTg+nzz/FMsH5dE8q6QkFhSkREREREgiYhgYaKCnweJvHll8Tl5LCzd/QhRyjrCgWFKRERERERCZqCAiqWL8fnYRJbtsCIERwKZU2hojAlIiIiIiJBM306FRs3UvfOOyQ1Np46b9TXQ0YGna4rBQpTIiIiIiISRImJuO+9l+VffEH1J5+QeLJrN23C2txMY9++NHdUfcFkDncBIiIiIiLStaSn05aZiaNnT5wnuubrr4n55z8xXXIJX/t6uG+kUZgSEREREZGga2ggPi0N1/G+tnMn0a+/juGGG1gydCgNHV1bsHTSDCgiIiIiIpEsIYGGAwd+ONXP44G33iLm/PMp7sxBChSmREREREQkBCZNYvf772Oqrv7uarilS4mz26n58Y+pCldtwaJlfiIiIiIiEnTjxlFbXs7ahx5i6OjRGFNS8O7ahXHLFhpuu421nXWf1LcZvF5vuGsQERGRYMnOnk1Ghi3cZUgXVVVVSHr65nCXIZ3LfmeqZUXzUFu9MSk6k4PN4+PW1saZWj0/uPDw4UPs3n13GEoMmMKUiIiIiIhIALpAc01ERERERKTjKUyJiIiIiIgEQGFKREREREQkAApTIiIiIiIiAVCYEhERERERCYDClIiIiIiISAAUpkRERERERAKgMCUiIiIiIhIAhSkREREREZEAKEyJiIiIiIgEQGFKREREREQkAApTIiIiIiIiAVCYEhERERERCYDClIiIiIiISAAUpkRERERERAKgMCUiIiIiIhIAhSkREREREZEAKEyJiIiIiIgEQGFKREREREQkAApTIiIiIiIiAVCYEhERERERCYDClIiIiIiISAAUpkRERERERAKgMCUiIiIiIhIAhSkREREREZEAKEyJiIiIiIgEQGFKREREREQkAApTIiIiIiIiAVCYEhERERERCYDClIiIiIiISAAUpkRERERERAKgMCUiIiIiIhIAhSkREREREZEAKEyJiIiIiIgEQGFKREREREQkAApTIiIiIiIiAVCYEhERERERCcD/ByHnnxjnQiQBAAAAAElFTkSuQmCC\n", 644 | "text/plain": [ 645 | "
" 646 | ] 647 | }, 648 | "metadata": { 649 | "needs_background": "light" 650 | }, 651 | "output_type": "display_data" 652 | } 653 | ], 654 | "source": [ 655 | "fig, ax = plt.subplots(figsize=(15, 15))\n", 656 | "gdf.plot(ax=ax,facecolor='w',edgecolor='r',alpha=0.5)\n", 657 | "orange_river_gpdf = gpd.GeoDataFrame(geometry=[orange_river])\n", 658 | "orange_river_gpdf.plot(ax=ax, facecolor='w',edgecolor='b',alpha=0.5)\n", 659 | "ax.set_title('Grid of tiles from the Orange River', size=18);\n", 660 | "plt.axis('off')\n", 661 | "plt.show()" 662 | ] 663 | }, 664 | { 665 | "cell_type": "markdown", 666 | "metadata": {}, 667 | "source": [ 668 | "### Create an EO Learn workflow to:\n", 669 | "1. Read data from disk\n", 670 | "2. Create a cloud mask\n", 671 | "3. Add NDVI and euclidean norm features\n", 672 | "4. Add Spatio temporal features\n", 673 | "6. Add a raster mask with the target crop for each field polygon\n", 674 | "\n", 675 | "This method was adapted from [this blog](https://medium.com/sentinel-hub/land-cover-classification-with-eo-learn-part-1-2471e8098195)" 676 | ] 677 | }, 678 | { 679 | "cell_type": "code", 680 | "execution_count": 33, 681 | "metadata": {}, 682 | "outputs": [], 683 | "source": [ 684 | "#use context manager so DatasetReader and MemoryFile get cleaned up automatically\n", 685 | "@contextmanager\n", 686 | "def resample_raster(raster, size):\n", 687 | " t = raster.transform\n", 688 | " \n", 689 | " scale = size//raster.height\n", 690 | "\n", 691 | " # rescale the metadata\n", 692 | " transform = Affine(t.a / scale, t.b, t.c, t.d, t.e / scale, t.f)\n", 693 | " height = raster.height * scale\n", 694 | " width = raster.width * scale\n", 695 | "\n", 696 | " profile = raster.profile\n", 697 | " profile.update(transform=transform, driver='GTiff', height=height, width=width)\n", 698 | "\n", 699 | " data = raster.read( # Note changed order of indexes, arrays are band, row, col order not row, col, band\n", 700 | " out_shape=(raster.count, height, width, ),\n", 701 | " resampling=Resampling.bilinear,\n", 702 | " )\n", 703 | "\n", 704 | " with MemoryFile() as memfile:\n", 705 | " with memfile.open(**profile) as dataset: # Open as DatasetWriter\n", 706 | " dataset.write(data)\n", 707 | " del data\n", 708 | "\n", 709 | " with memfile.open() as dataset: # Reopen as DatasetReader\n", 710 | " yield dataset # Note yield not return \n", 711 | " \n", 712 | "class ImportFromJP2(BaseLocalIo):\n", 713 | " \n", 714 | " def __init__(self, feature, folder=None, *, timestamp_size=None, **kwargs):\n", 715 | " \n", 716 | " super().__init__(feature, folder=folder, **kwargs)\n", 717 | "\n", 718 | " self.timestamp_size = timestamp_size\n", 719 | " self.no_data_value = np.nan\n", 720 | "\n", 721 | " @staticmethod\n", 722 | " def _get_reading_window(width, height, data_bbox, eopatch_bbox):\n", 723 | " \"\"\" Calculates a window in pixel coordinates for which data will be read from an image\n", 724 | " \"\"\"\n", 725 | " if eopatch_bbox.crs is not data_bbox.crs:\n", 726 | " eopatch_bbox = eopatch_bbox.transform(data_bbox.crs)\n", 727 | "\n", 728 | " # The following will be in the future moved to sentinelhub-py\n", 729 | " data_ul_x, data_lr_y = data_bbox.lower_left\n", 730 | " data_lr_x, data_ul_y = data_bbox.upper_right\n", 731 | "\n", 732 | " res_x = abs(data_ul_x - data_lr_x) / width\n", 733 | " res_y = abs(data_ul_y - data_lr_y) / height\n", 734 | "\n", 735 | " ul_x, lr_y = eopatch_bbox.lower_left\n", 736 | " lr_x, ul_y = eopatch_bbox.upper_right\n", 737 | "\n", 738 | " # If these coordinates wouldn't be rounded here, rasterio.io.DatasetReader.read would round\n", 739 | " # them in the same way\n", 740 | " top = round((data_ul_y - ul_y) / res_y)\n", 741 | " left = round((ul_x - data_ul_x) / res_x)\n", 742 | " bottom = round((data_ul_y - lr_y) / res_y)\n", 743 | " right = round((lr_x - data_ul_x) / res_x)\n", 744 | "\n", 745 | " return (top, bottom), (left, right)\n", 746 | "\n", 747 | "def execute(self, eopatch=None, *, fn_exp='../**/*B*.jp2'):\n", 748 | "\n", 749 | " feature_type, feature_name = next(self.feature())\n", 750 | " if eopatch is None:\n", 751 | " eopatch = EOPatch()\n", 752 | "\n", 753 | " \n", 754 | " #get jp2 files matching filename expression\n", 755 | " jp2_files = [[*f.stem.split('_'),f] for f in self.folder.glob(fn_exp)]\n", 756 | " jp2_df = pd.DataFrame(jp2_files)\n", 757 | " jp2_df.columns = ['tile','date','band','filename']\n", 758 | " \n", 759 | " \n", 760 | " band_order = {\n", 761 | " 'B01':0,\n", 762 | " 'B02':1,\n", 763 | " 'B03':2,\n", 764 | " 'B04':3,\n", 765 | " 'B05':4,\n", 766 | " 'B06':5,\n", 767 | " 'B07':6,\n", 768 | " 'B08':7,\n", 769 | " 'B8A':8,\n", 770 | " 'B09':9,\n", 771 | " 'B10':10,\n", 772 | " 'B11':11,\n", 773 | " 'B12':12\n", 774 | " }\n", 775 | "\n", 776 | " jp2_df['band_order'] = jp2_df.band.map(band_order)\n", 777 | "\n", 778 | " jp2_df.sort_values(by=['date','tile','band_order'],inplace=True)\n", 779 | " \n", 780 | " dates = jp2_df.date.unique()\n", 781 | " tiles = jp2_df.tile.unique()\n", 782 | " bands = list(band_order.keys())\n", 783 | " date_data_list = list() #list to hold data for each date\n", 784 | " \n", 785 | " #iterate through all files and add data\n", 786 | " for date in dates:\n", 787 | " bands_data_list = list() #list to hold data for each band\n", 788 | " for band in bands:\n", 789 | " tile_data_list = list()\n", 790 | " for tile in tiles:\n", 791 | " filename_series = jp2_df[(jp2_df.date==date)\n", 792 | " &(jp2_df.band==band)\n", 793 | " &(jp2_df.tile==tile)].filename\n", 794 | " if len(filename_series) > 0:\n", 795 | " filename=filename_series.values[0]\n", 796 | " else: continue\n", 797 | " with rasterio.open(filename) as source:\n", 798 | " with resample_raster(source, size = 10980) as resampled:\n", 799 | "\n", 800 | " data_bbox = BBox(resampled.bounds, CRS(resampled.crs.to_epsg()))\n", 801 | " \n", 802 | " if rasterio.coords.disjoint_bounds(rasterio.coords.BoundingBox(*data_bbox), \n", 803 | " rasterio.coords.BoundingBox(*eopatch.bbox)):\n", 804 | " continue\n", 805 | "\n", 806 | " reading_window = self._get_reading_window(\n", 807 | " resampled.width, resampled.height, data_bbox, eopatch.bbox)\n", 808 | "\n", 809 | " data = resampled.read(window=reading_window, boundless=True, \n", 810 | " fill_value=self.no_data_value)\n", 811 | " \n", 812 | " if self.image_dtype is not None:\n", 813 | " data = data.astype(self.image_dtype)\n", 814 | " \n", 815 | " tile_data_list.append(data)\n", 816 | "\n", 817 | " #Choose the values from the non-zero tile or average the two sets of non-zero value\n", 818 | " if len(tile_data_list) > 1:\n", 819 | " merged_tile_data = np.where((tile_data_list[0]!=0) & (tile_data_list[1]!=0),\n", 820 | " (tile_data_list[0]+tile_data_list[1])/2,\n", 821 | " np.where(tile_data_list[0]==0, tile_data_list[1], tile_data_list[0])\n", 822 | " )\n", 823 | " else:\n", 824 | " merged_tile_data = tile_data_list[0]\n", 825 | "\n", 826 | " bands_data_list.append(merged_tile_data.squeeze())\n", 827 | " \n", 828 | " date_data_list.append(np.stack(bands_data_list,axis=-1))\n", 829 | " \n", 830 | " data = np.stack(date_data_list,axis=0)\n", 831 | " eopatch[feature_type][feature_name] = data/10000\n", 832 | " eopatch.timestamp = dates.tolist()\n", 833 | " \n", 834 | " meta_info= {\n", 835 | " 'service_type': 'wcs',\n", 836 | " 'size_x': '10m',\n", 837 | " 'size_y': '10m'\n", 838 | " }\n", 839 | " \n", 840 | " eopatch.meta_info = meta_info\n", 841 | "\n", 842 | " return eopatch" 843 | ] 844 | }, 845 | { 846 | "cell_type": "markdown", 847 | "metadata": {}, 848 | "source": [ 849 | "## EO Tasks to compute vegetation indices" 850 | ] 851 | }, 852 | { 853 | "cell_type": "code", 854 | "execution_count": 34, 855 | "metadata": {}, 856 | "outputs": [], 857 | "source": [ 858 | "class SentinelHubValidData:\n", 859 | " \"\"\"\n", 860 | " Combine Sen2Cor's classification map with `IS_DATA` to define a `VALID_DATA_SH` mask\n", 861 | " The SentinelHub's cloud mask is asumed to be found in eopatch.mask['CLM']\n", 862 | " \"\"\"\n", 863 | " def __call__(self, eopatch): \n", 864 | " return np.logical_not(eopatch.mask['CLM'].astype(np.bool))\n", 865 | " \n", 866 | "class NormalizedDifferenceIndex(EOTask): \n", 867 | " \"\"\"\n", 868 | " The tasks calculates user defined Normalised Difference Index (NDI) between two bands A and B as:\n", 869 | " NDI = (A-B)/(A+B).\n", 870 | " \"\"\"\n", 871 | " def __init__(self, feature_name, band_a, band_b):\n", 872 | " self.feature_name = feature_name\n", 873 | " self.band_a_fetaure_name = band_a.split('/')[0]\n", 874 | " self.band_b_fetaure_name = band_b.split('/')[0]\n", 875 | " self.band_a_fetaure_idx = int(band_a.split('/')[-1])\n", 876 | " self.band_b_fetaure_idx = int(band_b.split('/')[-1])\n", 877 | " \n", 878 | " def execute(self, eopatch):\n", 879 | " band_a = eopatch.data[self.band_a_fetaure_name][..., self.band_a_fetaure_idx]\n", 880 | " band_b = eopatch.data[self.band_b_fetaure_name][..., self.band_b_fetaure_idx]\n", 881 | " \n", 882 | " ndi = (band_a - band_b) / (band_a + band_b)\n", 883 | " \n", 884 | " eopatch.add_feature(FeatureType.DATA, self.feature_name, ndi[..., np.newaxis])\n", 885 | " \n", 886 | " return eopatch\n", 887 | " \n", 888 | "class EuclideanNorm(EOTask): \n", 889 | " \"\"\"\n", 890 | " The tasks calculates Euclidian Norm of all bands within an array:\n", 891 | " norm = sqrt(sum_i Bi**2),\n", 892 | " where Bi are the individual bands within user-specified feature array.\n", 893 | " \"\"\"\n", 894 | " def __init__(self, feature_name, in_feature_name):\n", 895 | " self.feature_name = feature_name\n", 896 | " self.in_feature_name = in_feature_name\n", 897 | " \n", 898 | " def execute(self, eopatch):\n", 899 | " arr = eopatch.data[self.in_feature_name]\n", 900 | " norm = np.sqrt(np.sum(arr**2, axis=-1))\n", 901 | " \n", 902 | " eopatch.add_feature(FeatureType.DATA, self.feature_name, norm[..., np.newaxis])\n", 903 | " return eopatch" 904 | ] 905 | }, 906 | { 907 | "cell_type": "markdown", 908 | "metadata": {}, 909 | "source": [ 910 | "### Create workflow" 911 | ] 912 | }, 913 | { 914 | "cell_type": "code", 915 | "execution_count": 21, 916 | "metadata": {}, 917 | "outputs": [ 918 | { 919 | "data": { 920 | "text/plain": [ 921 | "'/Users/AuerPower/Metis/git/crop-classification/work_flow'" 922 | ] 923 | }, 924 | "execution_count": 21, 925 | "metadata": {}, 926 | "output_type": "execute_result" 927 | } 928 | ], 929 | "source": [ 930 | "pwd" 931 | ] 932 | }, 933 | { 934 | "cell_type": "code", 935 | "execution_count": 41, 936 | "metadata": {}, 937 | "outputs": [], 938 | "source": [ 939 | "# Paths\n", 940 | "data_path = '/Users/AuerPower/Metis/git/crop-classification/data/intermediate'\n", 941 | "sentinel_path = '/Users/AuerPower/Metis/git/crop-classification/data/imagery/sentinel/S2A_MSIL1C_20170101T082332_N0204_R121_T34JEP_20170101T084543.SAFE'\n", 942 | "\n", 943 | "output_path = Path('output')\n", 944 | "shape_path = output_path/'shapes'\n", 945 | "patch_path = output_path/'patches'\n", 946 | "feature_path = output_path/'features'\n", 947 | "\n", 948 | "shape_path.mkdir(exist_ok=True, parents=True)\n", 949 | "patch_path.mkdir(exist_ok=True, parents=True)\n", 950 | "feature_path.mkdir(exist_ok=True, parents=True)" 951 | ] 952 | }, 953 | { 954 | "cell_type": "code", 955 | "execution_count": 42, 956 | "metadata": {}, 957 | "outputs": [ 958 | { 959 | "ename": "TypeError", 960 | "evalue": "Can't instantiate abstract class ImportFromJP2 with abstract methods execute", 961 | "output_type": "error", 962 | "traceback": [ 963 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 964 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 965 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 2\u001b[0m add_data = ImportFromJP2(feature=[\n\u001b[1;32m 3\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mFeatureType\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDATA\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'BANDS'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m ], folder=sentinel_path)\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;31m# TASK FOR CLOUD INFO\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 966 | "\u001b[0;32m~/opt/miniconda3/envs/metis/lib/python3.7/site-packages/eolearn/core/eotask.py\u001b[0m in \u001b[0;36m__new__\u001b[0;34m(cls, *args, **kwargs)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__new__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcls\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0;34m\"\"\"Stores initialization parameters and the order to the instance attribute `init_args`.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0mself\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__new__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcls\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 38\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0minit_args\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mOrderedDict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 967 | "\u001b[0;31mTypeError\u001b[0m: Can't instantiate abstract class ImportFromJP2 with abstract methods execute" 968 | ] 969 | } 970 | ], 971 | "source": [ 972 | "# Read in all available bands from disk\n", 973 | "add_data = ImportFromJP2(feature=[\n", 974 | " (FeatureType.DATA, 'BANDS')\n", 975 | "], folder=sentinel_path)\n", 976 | "\n", 977 | "# TASK FOR CLOUD INFO\n", 978 | "# cloud detection is performed at 80m resolution \n", 979 | "# and the resulting cloud probability map and mask \n", 980 | "# are scaled to EOPatch's resolution\n", 981 | "cloud_classifier = get_s2_pixel_cloud_detector(average_over=2, dilation_size=1, all_bands=True)\n", 982 | "add_clm = AddCloudMaskTask(cloud_classifier, 'BANDS', cm_size_y='80m', cm_size_x='80m', \n", 983 | " cmask_feature='CLM', # cloud mask name\n", 984 | " cprobs_feature='CLP' # cloud prob. map name\n", 985 | " )\n", 986 | "\n", 987 | "# TASKS FOR CALCULATING NEW FEATURES\n", 988 | "# NDVI: (B8a - B04)/(B8a + B04)\n", 989 | "# NORM: sqrt(B01^2 + B02^2 + ... + B12^2)\n", 990 | "ndvi = NormalizedDifferenceIndex('NDVI', 'BANDS/8', 'BANDS/3')\n", 991 | "norm = EuclideanNorm('NORM','BANDS')\n", 992 | "\n", 993 | "# TASK FOR VALID MASK\n", 994 | "# validate pixels using SentinelHub's cloud detection mask and region of acquisition \n", 995 | "add_sh_valmask = AddValidDataMaskTask(SentinelHubValidData(), \n", 996 | " 'VALID_DATA' # name of output mask\n", 997 | " )\n", 998 | "#Tasks for spatio temporal features\n", 999 | "max_min_b4_idx = AddMaxMinTemporalIndicesTask(data_feature='BANDS', \n", 1000 | " data_index=3, \n", 1001 | " amax_data_feature='ARGMAX_B4', \n", 1002 | " amin_data_feature='ARGMIN_B4')\n", 1003 | "max_min_ndvi_idx = AddMaxMinTemporalIndicesTask(data_feature='NDVI')\n", 1004 | "max_min_ndvi_slope_idx = AddMaxMinNDVISlopeIndicesTask()\n", 1005 | "spatio_temp_feat = AddSpatioTemporalFeaturesTask(data_feature='BANDS')" 1006 | ] 1007 | }, 1008 | { 1009 | "cell_type": "code", 1010 | "execution_count": null, 1011 | "metadata": {}, 1012 | "outputs": [], 1013 | "source": [] 1014 | } 1015 | ], 1016 | "metadata": { 1017 | "kernelspec": { 1018 | "display_name": "Python [conda env:metis] *", 1019 | "language": "python", 1020 | "name": "conda-env-metis-py" 1021 | }, 1022 | "language_info": { 1023 | "codemirror_mode": { 1024 | "name": "ipython", 1025 | "version": 3 1026 | }, 1027 | "file_extension": ".py", 1028 | "mimetype": "text/x-python", 1029 | "name": "python", 1030 | "nbconvert_exporter": "python", 1031 | "pygments_lexer": "ipython3", 1032 | "version": "3.7.4" 1033 | } 1034 | }, 1035 | "nbformat": 4, 1036 | "nbformat_minor": 2 1037 | } 1038 | -------------------------------------------------------------------------------- /work_flow/Visualization.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 8, 6 | "metadata": { 7 | "ExecuteTime": { 8 | "end_time": "2020-02-12T19:21:37.987659Z", 9 | "start_time": "2020-02-12T19:21:37.984009Z" 10 | } 11 | }, 12 | "outputs": [], 13 | "source": [ 14 | "import numpy as np\n", 15 | "import pandas as pd\n", 16 | "import geopandas as gpd\n", 17 | "\n", 18 | "from matplotlib.colors import ListedColormap\n", 19 | "import matplotlib.colors as colors\n", 20 | "import matplotlib.pyplot as plt\n", 21 | "import earthpy.plot as ep\n", 22 | "import plotly.figure_factory as ff\n", 23 | "import plotly.express as px\n", 24 | "import rasterio as rio\n", 25 | "from rasterio import features" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "## Plot errors for test set" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 9, 38 | "metadata": { 39 | "ExecuteTime": { 40 | "end_time": "2020-02-12T19:21:44.356171Z", 41 | "start_time": "2020-02-12T19:21:44.032645Z" 42 | } 43 | }, 44 | "outputs": [ 45 | { 46 | "data": { 47 | "image/png": "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\n", 48 | "text/plain": [ 49 | "
" 50 | ] 51 | }, 52 | "metadata": { 53 | "needs_background": "light" 54 | }, 55 | "output_type": "display_data" 56 | } 57 | ], 58 | "source": [ 59 | "# Plot errors for test set\n", 60 | "\n", 61 | "error_path = '/Users/AuerPower/Metis/git/crop-classification/data/intermediate/raster_results/rasterized_error.tiff'\n", 62 | "\n", 63 | "with rio.open(error_path) as src:\n", 64 | " error_ras = src.read(1, masked=True)\n", 65 | "\n", 66 | "#-1 is a false negative, 1 is a false positive, 0 is correctly predicted\n", 67 | "cmap = ListedColormap([\"springgreen\",\"magenta\", \"darkgreen\"])\n", 68 | "\n", 69 | "ep.plot_bands(error_ras,\n", 70 | " cmap=cmap,\n", 71 | " title=\"Error Map\\ndark green = correctly classified, magenta = false positive, lightgreen = false negative\",\n", 72 | " scale=False)\n", 73 | "plt.show()" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "## Aggregate results to the field polygons" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 4, 93 | "metadata": { 94 | "ExecuteTime": { 95 | "end_time": "2020-02-11T23:06:12.362896Z", 96 | "start_time": "2020-02-11T23:05:56.613815Z" 97 | } 98 | }, 99 | "outputs": [ 100 | { 101 | "data": { 102 | "text/html": [ 103 | "
\n", 104 | "\n", 117 | "\n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | "
layergndvi_1gndvi_2msi_1msi_2ndii_1ndii_2ndvi_1ndvi_2nrde_1nrde_2re_1re_2geometry
08.00.3920780.1220300.7974110.2353554.1883916.5552100.4138630.1661750.3478380.1206380.5768790.161764POINT (552665.000 6859815.000)
18.00.4954990.0992150.5699440.1218510.2815960.0989430.5721620.1160820.4672610.0818420.4087370.087773POINT (552425.000 6859805.000)
28.00.5070680.0781480.5699440.1218510.2815960.0989430.5613980.1114500.4672610.0818420.4087370.087773POINT (552435.000 6859805.000)
38.00.4668740.1030110.5993040.1340190.2594220.1060850.5025970.1474220.4450280.0767140.4406160.088595POINT (552445.000 6859805.000)
48.00.4659600.1163380.5993040.1340190.2594220.1060850.5013520.1626260.4450280.0767140.4406160.088595POINT (552455.000 6859805.000)
\n", 225 | "
" 226 | ], 227 | "text/plain": [ 228 | " layer gndvi_1 gndvi_2 msi_1 msi_2 ndii_1 ndii_2 \\\n", 229 | "0 8.0 0.392078 0.122030 0.797411 0.235355 4.188391 6.555210 \n", 230 | "1 8.0 0.495499 0.099215 0.569944 0.121851 0.281596 0.098943 \n", 231 | "2 8.0 0.507068 0.078148 0.569944 0.121851 0.281596 0.098943 \n", 232 | "3 8.0 0.466874 0.103011 0.599304 0.134019 0.259422 0.106085 \n", 233 | "4 8.0 0.465960 0.116338 0.599304 0.134019 0.259422 0.106085 \n", 234 | "\n", 235 | " ndvi_1 ndvi_2 nrde_1 nrde_2 re_1 re_2 \\\n", 236 | "0 0.413863 0.166175 0.347838 0.120638 0.576879 0.161764 \n", 237 | "1 0.572162 0.116082 0.467261 0.081842 0.408737 0.087773 \n", 238 | "2 0.561398 0.111450 0.467261 0.081842 0.408737 0.087773 \n", 239 | "3 0.502597 0.147422 0.445028 0.076714 0.440616 0.088595 \n", 240 | "4 0.501352 0.162626 0.445028 0.076714 0.440616 0.088595 \n", 241 | "\n", 242 | " geometry \n", 243 | "0 POINT (552665.000 6859815.000) \n", 244 | "1 POINT (552425.000 6859805.000) \n", 245 | "2 POINT (552435.000 6859805.000) \n", 246 | "3 POINT (552445.000 6859805.000) \n", 247 | "4 POINT (552455.000 6859805.000) " 248 | ] 249 | }, 250 | "execution_count": 4, 251 | "metadata": {}, 252 | "output_type": "execute_result" 253 | } 254 | ], 255 | "source": [ 256 | "fields = gpd.read_file('/Users/AuerPower/Metis/git/crop-classification/data/intermediate/samples.shp')\n", 257 | "fields.head()" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": null, 263 | "metadata": {}, 264 | "outputs": [], 265 | "source": [ 266 | "fig = px.scatter_mapbox(us_cities, lat=\"lat\", lon=\"lon\", hover_name=\"City\", hover_data=[\"State\", \"Population\"],\n", 267 | " color_discrete_sequence=[\"fuchsia\"], zoom=3, height=300)" 268 | ] 269 | }, 270 | { 271 | "cell_type": "markdown", 272 | "metadata": {}, 273 | "source": [ 274 | "## Plot a veg index" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": null, 280 | "metadata": {}, 281 | "outputs": [], 282 | "source": [ 283 | "## extract the mean and std of nrde (the most important according to RF model) and save as individual raster\n" 284 | ] 285 | }, 286 | { 287 | "cell_type": "markdown", 288 | "metadata": {}, 289 | "source": [ 290 | "## Plot model on new geographic area" 291 | ] 292 | }, 293 | { 294 | "cell_type": "code", 295 | "execution_count": null, 296 | "metadata": {}, 297 | "outputs": [], 298 | "source": [ 299 | "import pickle" 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "execution_count": null, 305 | "metadata": {}, 306 | "outputs": [], 307 | "source": [ 308 | "with open(\"/Users/AuerPower/Metis/git/crop-classification/outputs/Models/best_model.pkl\", \"rb\") as f:\n", 309 | " best_model = pickle.load(f)" 310 | ] 311 | }, 312 | { 313 | "cell_type": "code", 314 | "execution_count": 1, 315 | "metadata": { 316 | "ExecuteTime": { 317 | "end_time": "2020-02-11T21:59:55.336858Z", 318 | "start_time": "2020-02-11T21:59:55.334508Z" 319 | } 320 | }, 321 | "outputs": [], 322 | "source": [ 323 | "## predict on new data" 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": null, 329 | "metadata": {}, 330 | "outputs": [], 331 | "source": [ 332 | "## Load new data" 333 | ] 334 | } 335 | ], 336 | "metadata": { 337 | "kernelspec": { 338 | "display_name": "Python [conda env:metis] *", 339 | "language": "python", 340 | "name": "conda-env-metis-py" 341 | }, 342 | "language_info": { 343 | "codemirror_mode": { 344 | "name": "ipython", 345 | "version": 3 346 | }, 347 | "file_extension": ".py", 348 | "mimetype": "text/x-python", 349 | "name": "python", 350 | "nbconvert_exporter": "python", 351 | "pygments_lexer": "ipython3", 352 | "version": "3.7.4" 353 | } 354 | }, 355 | "nbformat": 4, 356 | "nbformat_minor": 2 357 | } 358 | -------------------------------------------------------------------------------- /work_flow/data_munging.R: -------------------------------------------------------------------------------- 1 | ## This script does basic GIS manipulations for getting the crop classifications 2 | ## in the right format for modeling 3 | 4 | library(raster) 5 | library(rgeos) 6 | library(rgdal) 7 | library(maptools) 8 | 9 | # create multiband raster and spatial points ------------------------------ 10 | 11 | # load orange river dataset and reproject 12 | dir <- "/Users/AuerPower/Metis/git/crop-classification/data/imagery/tile1/S2A_MSIL1C_20170101T082332_N0204_R121_T34JEP_20170101T084543_SAFE/GRANULE/L1C_T34JEP_A007983_20170101T084543/IMG_DATA/" 13 | 14 | orange_river <- readOGR("/Users/AuerPower/Metis/git/crop-classification/data/train", "train") 15 | crs(orange_river) 16 | rgb <- stack("/Users/AuerPower/Metis/git/crop-classification/work_flow/RGB.tiff") 17 | 18 | orange_river <- spTransform(orange_river,crs(rgb)) 19 | writeOGR(orange_river, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'orange_river_prj', driver = "ESRI Shapefile") 20 | 21 | ext <- extent(c(571678.5, 590107.4, 6816898, 6833887)) 22 | #ext <- drawExtent() 23 | # class : Extent 24 | # xmin : 571678.5 25 | # xmax : 590107.4 26 | # ymin : 6816898 27 | # ymax : 6833887 28 | 29 | #orange_river_crop <- crop(orange_river, ext) 30 | 31 | #writeOGR(orange_river_crop, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'crop_ext_prj', driver = "ESRI Shapefile") 32 | #plot(rgb[[1]]) 33 | #plot(orange_river) 34 | 35 | #crop_rgb <- crop(rgb, orange_river_crop) 36 | #boxes <- readOGR('/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'selected_orange_river_bboxes') 37 | 38 | ### Import imagery bands for raster 39 | img <- stack('/Users/AuerPower/Metis/git/crop-classification/data/intermediate/veg_indices.tiff') 40 | plot(img[[5]]) 41 | plot(orange_river, add=TRUE) 42 | 43 | ### Crop imagery and orange river to match 44 | orange_river <- crop(orange_river, img) 45 | img <- crop(img, orange_river) 46 | #writeOGR(orange_river, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'orange_river_crop_img', driver = "ESRI Shapefile") 47 | writeRaster(img, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate/veg_indices_crop.tiff') 48 | 49 | 50 | # sampling ---------------------------------------------------------------- 51 | 52 | orange_river <- readOGR('/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'orange_river_crop_img') 53 | img <- stack('/Users/AuerPower/Metis/git/crop-classification/data/intermediate/veg_indices_crop.tiff') 54 | 55 | ## convert shape to raster 56 | orange_river_ras <- rasterize(orange_river, img[[4]], 'Crop_Id_Ne') 57 | orange_river_region <- rasterize(orange_river, img[[4]], 'Field_Id') 58 | 59 | 60 | ## convert raster to points 61 | orange_river_points <- rasterToPoints(orange_river_ras, fun=NULL, spatial=TRUE) 62 | orange_river_region_points <- rasterToPoints(orange_river_region, fun=NULL, spatial=TRUE) 63 | writeOGR(orange_river_region_points, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 64 | 'fieldID_points', driver = "ESRI Shapefile") 65 | 66 | ### Extract img raster values to crop polygons 67 | #orange_river_buff <- buffer(orange_river, width=20) 68 | 69 | ### create points within polygons 70 | #samples <- spsample(orange_river_buff , n=10000, "random") 71 | #points <- SpatialPointsDataFrame(coords, data=coord_df, proj4string=crs(orange_river)) 72 | 73 | ### extract values from crop polygon and img bands 74 | #samples_img <- extract(img, samples, method='simple', sp=TRUE) 75 | samples_img <- extract(img, orange_river_points, method='bilinear', sp=TRUE) 76 | samples_img_df <- as.data.frame(samples_img, xy=TRUE) 77 | 78 | writeOGR(samples_img, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'samples', driver = "ESRI Shapefile" , overwrite_layer = TRUE) 79 | write.csv(samples_img_df, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate/samples_df.csv') 80 | 81 | # sampling v2 ------------------------------------------------------------- 82 | 83 | orange_river <- readOGR('/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'orange_river_crop_img') 84 | orange_river_boxes <- readOGR('/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'selected_orange_river_bboxes') 85 | 86 | paths <- list.files('/Users/AuerPower/Metis/git/crop-classification/data/intermediate/seasonal_veg', 87 | full.names = TRUE) 88 | img <- stack(paths) 89 | 90 | img <- crop(img, ext) 91 | writeRaster(img[[1]], "/Users/AuerPower/Metis/git/crop-classification/data/intermediate/template_img_ras.tiff") 92 | ## convert shape to raster 93 | orange_river_ras <- rasterize(orange_river, img[[1]], 'Crop_Id_Ne') 94 | orange_river_region <- rasterize(orange_river, img[[1]], 'Field_Id') 95 | 96 | ## convert raster to points 97 | orange_river_points <- rasterToPoints(orange_river_ras, fun=NULL, spatial=TRUE) 98 | orange_river_region_points <- rasterToPoints(orange_river_region, fun=NULL, spatial=TRUE) 99 | #orange_river_points <- merge(orange_river_points, orange_river_region_points) 100 | writeOGR(orange_river_region_points, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 101 | 'fieldID_points', driver = "ESRI Shapefile", overwrite_layer = TRUE) 102 | 103 | ### extract values from crop polygon and img bands 104 | samples_img <- extract(img, orange_river_points, method='bilinear', sp=TRUE) 105 | 106 | #writeOGR(samples_img, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'samples', driver = "ESRI Shapefile" , overwrite_layer = TRUE) 107 | samples_img <- readOGR('/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'samples') 108 | orange_river_region_points <-readOGR('/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 109 | 'fieldID_points') 110 | names(samples_img)[1] <- 'crop' 111 | #names(orange_river_region_points)[1] <- 'field_ID' 112 | ## extract to boxes 113 | extract_box <- crop(samples_img, ext) 114 | writeOGR(extract_box, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 'samples_subset', driver = "ESRI Shapefile" , overwrite_layer = TRUE) 115 | field_id_box <- crop(orange_river_region_points, ext) 116 | 117 | samples_merge <- merge(samples_img, orange_river_region_points) 118 | 119 | writeOGR(field_id_box, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 120 | 'fieldID_subset', driver = "ESRI Shapefile", overwrite_layer = TRUE) 121 | 122 | orange_crop <- crop(orange_river, ext) 123 | writeOGR(orange_crop, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 124 | 'orange_river_crop_ext', driver = "ESRI Shapefile", overwrite_layer = TRUE) 125 | 126 | 127 | # visualizing model results ----------------------------------------------- 128 | errors <- stack('/Users/AuerPower/Metis/git/crop-classification/data/intermediate/raster_results/rasterized_error.tiff') 129 | field_polygons <- readOGR('/Users/AuerPower/Metis/git/crop-classification/data/intermediate/', 'test_train_subset') 130 | prediction_ras <- raster('/Users/AuerPower/Metis/git/crop-classification/data/intermediate/raster_results/rasterized_prediction.tiff') 131 | 132 | Mode <- function(x, na.rm = TRUE) { 133 | if(na.rm){ 134 | x = x[!is.na(x)] 135 | } 136 | 137 | ux <- unique(x) 138 | return(ux[which.max(tabulate(match(x, ux)))]) 139 | } 140 | 141 | # drop train polygons 142 | field_polygons = field_polygons[field_polygons$split=='test',] 143 | aggregate_prediction <- extract(prediction_ras, field_polygons, fun=Mode, sp=TRUE) 144 | 145 | #aggregate_prediction <- aggregate_prediction[!is.na(aggregate_prediction$diff),] 146 | #aggregate_prediction <- aggregate_prediction[c(1,2,3,4,6,7,8)] 147 | aggregate_prediction$vinyard <- sub(8, 1, aggregate_prediction$Crop_Id_Ne) 148 | aggregate_prediction$vinyard <- sub(7, 0, aggregate_prediction$vinyard) 149 | aggregate_prediction$vinyard <- sub(6, 0, aggregate_prediction$vinyard) 150 | aggregate_prediction$vinyard <- sub(5, 0, aggregate_prediction$vinyard) 151 | aggregate_prediction$vinyard <- sub(4, 0, aggregate_prediction$vinyard) 152 | aggregate_prediction$vinyard <- sub(3, 0, aggregate_prediction$vinyard) 153 | aggregate_prediction$vinyard <- sub(2, 0, aggregate_prediction$vinyard) 154 | aggregate_prediction$vinyard <- sub(9, 0, aggregate_prediction$vinyard) 155 | aggregate_prediction$vinyard <- as.numeric(aggregate_prediction$vinyard) 156 | aggregate_prediction$diff <- aggregate_prediction$vinyard - aggregate_prediction$rasterized_prediction 157 | 158 | writeOGR(aggregate_prediction, '/Users/AuerPower/Metis/git/crop-classification/data/intermediate', 159 | 'prediction_polygons', driver = "ESRI Shapefile", overwrite_layer = TRUE) 160 | --------------------------------------------------------------------------------