\n",
+ "The next cell will submit a map inference job on CDSE through OpenEO.
\n",
+ "The first time you run this, you will be asked to authenticate with your CDSE account by clicking the link provided below the cell.
\n",
+ "Then sit back and wait untill your map is ready..."
+ ]
+ },
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Authenticated using refresh token.\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "2024-10-08 12:50:26,563 - openeo_gfmap.utils - INFO - Selected orbit state: DESCENDING. Reason: Orbit has more cumulative intersected area. 15.678082454846425 > 13.936101536993151\n",
- "WARNING:PrestoFeatureExtractor:No additional dependencies are defined. If you wish to add dependencies to your feature extractor, override the `dependencies` method in your class.\n",
- "WARNING:PrestoFeatureExtractor:No additional dependencies are defined. If you wish to add dependencies to your feature extractor, override the `dependencies` method in your class.\n"
- ]
- },
- {
- "ename": "InvalidProtobuf",
- "evalue": "[ONNXRuntimeError] : 7 : INVALID_PROTOBUF : Failed to load model because protobuf parsing failed.",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mInvalidProtobuf\u001b[0m Traceback (most recent call last)",
- "Cell \u001b[0;32mIn[10], line 17\u001b[0m\n\u001b[1;32m 14\u001b[0m parameters\u001b[38;5;241m.\u001b[39mclassifier_parameters\u001b[38;5;241m.\u001b[39mclassifier_url \u001b[38;5;241m=\u001b[39m model_url\n\u001b[1;32m 16\u001b[0m \u001b[38;5;66;03m# Launch the job\u001b[39;00m\n\u001b[0;32m---> 17\u001b[0m job_results \u001b[38;5;241m=\u001b[39m \u001b[43mgenerate_map\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 18\u001b[0m \u001b[43m \u001b[49m\u001b[43mspatial_extent\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 19\u001b[0m \u001b[43m \u001b[49m\u001b[43mtemporal_extent\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 20\u001b[0m \u001b[43m \u001b[49m\u001b[43moutput_path\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m./cropmap_newpresto.tif\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 21\u001b[0m \u001b[43m \u001b[49m\u001b[43mproduct_type\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mWorldCerealProduct\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mCROPTYPE\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 22\u001b[0m \u001b[43m \u001b[49m\u001b[43mcroptype_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 23\u001b[0m \u001b[43m \u001b[49m\u001b[43mpostprocess_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPostprocessParameters\u001b[49m\u001b[43m(\u001b[49m\u001b[43menable\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 24\u001b[0m \u001b[43m \u001b[49m\u001b[43mjob_options\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mpython-memory\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m4g\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 25\u001b[0m \u001b[43m \u001b[49m\u001b[43mout_format\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mGTiff\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 26\u001b[0m \u001b[43m)\u001b[49m\n",
- "File \u001b[0;32m~/git/worldcereal/worldcereal-classification/src/worldcereal/job.py:151\u001b[0m, in \u001b[0;36mgenerate_map\u001b[0;34m(spatial_extent, temporal_extent, output_path, product_type, cropland_parameters, croptype_parameters, postprocess_parameters, out_format, backend_context, tile_size, job_options)\u001b[0m\n\u001b[1;32m 138\u001b[0m \u001b[38;5;66;03m# First compute cropland map\u001b[39;00m\n\u001b[1;32m 139\u001b[0m cropland_mask \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 140\u001b[0m _cropland_map(\n\u001b[1;32m 141\u001b[0m inputs,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 148\u001b[0m ) \u001b[38;5;66;03m# Temporary fix to make this work as mask\u001b[39;00m\n\u001b[1;32m 149\u001b[0m )\n\u001b[0;32m--> 151\u001b[0m classes \u001b[38;5;241m=\u001b[39m \u001b[43m_croptype_map\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 152\u001b[0m \u001b[43m \u001b[49m\u001b[43minputs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 153\u001b[0m \u001b[43m \u001b[49m\u001b[43mcroptype_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcroptype_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 154\u001b[0m \u001b[43m \u001b[49m\u001b[43mcropland_mask\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcropland_mask\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 155\u001b[0m \u001b[43m \u001b[49m\u001b[43mpostprocess_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpostprocess_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 156\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 158\u001b[0m \u001b[38;5;66;03m# Submit the job\u001b[39;00m\n\u001b[1;32m 159\u001b[0m JOB_OPTIONS \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 160\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdriver-memory\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m4g\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 161\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mexecutor-memory\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m1g\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 165\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mudf-dependency-archives\u001b[39m\u001b[38;5;124m\"\u001b[39m: [\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mONNX_DEPS_URL\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m#onnx_deps\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n\u001b[1;32m 166\u001b[0m }\n",
- "File \u001b[0;32m~/git/worldcereal/worldcereal-classification/src/worldcereal/openeo/mapping.py:131\u001b[0m, in \u001b[0;36m_croptype_map\u001b[0;34m(inputs, croptype_parameters, postprocess_parameters, cropland_mask)\u001b[0m\n\u001b[1;32m 126\u001b[0m \u001b[38;5;66;03m# Run model inference on features\u001b[39;00m\n\u001b[1;32m 127\u001b[0m parameters \u001b[38;5;241m=\u001b[39m croptype_parameters\u001b[38;5;241m.\u001b[39mclassifier_parameters\u001b[38;5;241m.\u001b[39mmodel_dump(\n\u001b[1;32m 128\u001b[0m exclude\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mclassifier\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n\u001b[1;32m 129\u001b[0m )\n\u001b[0;32m--> 131\u001b[0m lookup_table \u001b[38;5;241m=\u001b[39m \u001b[43mload_model_lut\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 132\u001b[0m \u001b[43m \u001b[49m\u001b[43mcroptype_parameters\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mclassifier_parameters\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mclassifier_url\u001b[49m\n\u001b[1;32m 133\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 134\u001b[0m parameters\u001b[38;5;241m.\u001b[39mupdate({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlookup_table\u001b[39m\u001b[38;5;124m\"\u001b[39m: lookup_table})\n\u001b[1;32m 136\u001b[0m classes \u001b[38;5;241m=\u001b[39m apply_model_inference(\n\u001b[1;32m 137\u001b[0m model_inference_class\u001b[38;5;241m=\u001b[39mcroptype_parameters\u001b[38;5;241m.\u001b[39mclassifier,\n\u001b[1;32m 138\u001b[0m cube\u001b[38;5;241m=\u001b[39mfeatures,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 148\u001b[0m ],\n\u001b[1;32m 149\u001b[0m )\n",
- "File \u001b[0;32m~/git/worldcereal/worldcereal-classification/src/worldcereal/utils/models.py:83\u001b[0m, in \u001b[0;36mload_model_lut\u001b[0;34m(model_url)\u001b[0m\n\u001b[1;32m 70\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mload_model_lut\u001b[39m(model_url: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mdict\u001b[39m:\n\u001b[1;32m 71\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Load the class names to labels mapping from a CatBoost model.\u001b[39;00m\n\u001b[1;32m 72\u001b[0m \n\u001b[1;32m 73\u001b[0m \u001b[38;5;124;03m Parameters\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 81\u001b[0m \u001b[38;5;124;03m Look-up table with class names and labels.\u001b[39;00m\n\u001b[1;32m 82\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m---> 83\u001b[0m model \u001b[38;5;241m=\u001b[39m \u001b[43mvalidate_cb_model\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmodel_url\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmodel_url\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 84\u001b[0m metadata \u001b[38;5;241m=\u001b[39m model\u001b[38;5;241m.\u001b[39mget_modelmeta()\u001b[38;5;241m.\u001b[39mcustom_metadata_map\n\u001b[1;32m 85\u001b[0m class_params \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mloads(metadata[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mclass_params\u001b[39m\u001b[38;5;124m\"\u001b[39m])\n",
- "File \u001b[0;32m~/git/worldcereal/worldcereal-classification/src/worldcereal/utils/models.py:51\u001b[0m, in \u001b[0;36mvalidate_cb_model\u001b[0;34m(model_url)\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mvalidate_cb_model\u001b[39m(model_url: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ort\u001b[38;5;241m.\u001b[39mInferenceSession:\n\u001b[1;32m 33\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Validate a catboost model by loading it and checking if the required\u001b[39;00m\n\u001b[1;32m 34\u001b[0m \u001b[38;5;124;03m metadata is present. Checks for the `class_names` and `class_to_labels`\u001b[39;00m\n\u001b[1;32m 35\u001b[0m \u001b[38;5;124;03m fields are present in the `class_params` field of the custom metadata of\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[38;5;124;03m ONNX model loaded with ONNX runtime.\u001b[39;00m\n\u001b[1;32m 50\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m---> 51\u001b[0m model \u001b[38;5;241m=\u001b[39m \u001b[43mload_model_onnx\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmodel_url\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmodel_url\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 53\u001b[0m metadata \u001b[38;5;241m=\u001b[39m model\u001b[38;5;241m.\u001b[39mget_modelmeta()\u001b[38;5;241m.\u001b[39mcustom_metadata_map\n\u001b[1;32m 55\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mclass_params\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m metadata:\n",
- "File \u001b[0;32m~/git/worldcereal/worldcereal-classification/src/worldcereal/utils/models.py:29\u001b[0m, in \u001b[0;36mload_model_onnx\u001b[0;34m(model_url)\u001b[0m\n\u001b[1;32m 26\u001b[0m response \u001b[38;5;241m=\u001b[39m requests\u001b[38;5;241m.\u001b[39mget(model_url, timeout\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m120\u001b[39m)\n\u001b[1;32m 27\u001b[0m model \u001b[38;5;241m=\u001b[39m response\u001b[38;5;241m.\u001b[39mcontent\n\u001b[0;32m---> 29\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mort\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mInferenceSession\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m)\u001b[49m\n",
- "File \u001b[0;32m~/miniconda3/envs/worldcereal/lib/python3.10/site-packages/onnxruntime/capi/onnxruntime_inference_collection.py:419\u001b[0m, in \u001b[0;36mInferenceSession.__init__\u001b[0;34m(self, path_or_bytes, sess_options, providers, provider_options, **kwargs)\u001b[0m\n\u001b[1;32m 416\u001b[0m disabled_optimizers \u001b[38;5;241m=\u001b[39m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdisabled_optimizers\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdisabled_optimizers\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m kwargs \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 418\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 419\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_create_inference_session\u001b[49m\u001b[43m(\u001b[49m\u001b[43mproviders\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprovider_options\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdisabled_optimizers\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 420\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (\u001b[38;5;167;01mValueError\u001b[39;00m, \u001b[38;5;167;01mRuntimeError\u001b[39;00m) \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 421\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_enable_fallback:\n",
- "File \u001b[0;32m~/miniconda3/envs/worldcereal/lib/python3.10/site-packages/onnxruntime/capi/onnxruntime_inference_collection.py:454\u001b[0m, in \u001b[0;36mInferenceSession._create_inference_session\u001b[0;34m(self, providers, provider_options, disabled_optimizers)\u001b[0m\n\u001b[1;32m 452\u001b[0m sess \u001b[38;5;241m=\u001b[39m C\u001b[38;5;241m.\u001b[39mInferenceSession(session_options, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_model_path, \u001b[38;5;28;01mTrue\u001b[39;00m, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_read_config_from_model)\n\u001b[1;32m 453\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 454\u001b[0m sess \u001b[38;5;241m=\u001b[39m \u001b[43mC\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mInferenceSession\u001b[49m\u001b[43m(\u001b[49m\u001b[43msession_options\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_model_bytes\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_read_config_from_model\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 456\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m disabled_optimizers \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 457\u001b[0m disabled_optimizers \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m()\n",
- "\u001b[0;31mInvalidProtobuf\u001b[0m: [ONNXRuntimeError] : 7 : INVALID_PROTOBUF : Failed to load model because protobuf parsing failed."
- ]
- }
- ],
+ "outputs": [],
"source": [
- "from worldcereal.job import generate_map, CropLandParameters\n",
+ "from worldcereal.job import generate_map, CropLandParameters, PostprocessParameters\n",
"\n",
"# Initializes default parameters\n",
"parameters = CropLandParameters()\n",
@@ -565,7 +321,7 @@
" processing_period,\n",
" output_dir=output_dir,\n",
" cropland_parameters=parameters,\n",
- " postprocess_parameters=postprocess_parameters,\n",
+ " postprocess_parameters=PostprocessParameters,\n",
")"
]
},
@@ -573,14 +329,15 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The classification results will be automatically downloaded to your output_dir in .tif format.\n",
- "By default, OpenEO stores the class labels, confidence score and class probabilities in one file.\n",
+ "The classification results will be automatically downloaded to your *output_dir* in .tif format.\n",
"\n",
- "Using the function below, we split this information into separate .tif files, thereby adding metadata and a color map, to ease interpretation and visualization:\n",
- "- \"xxx_classification_start-date_end-date.tif\" --> contains the classification labels. A class look-up table is included in the .tif metadata.\n",
- "- \"xxx_confidence_start-date_end-date.tif\" --> contains the probability associated to the prediction [0 - 100]\n",
+ "The result will be a raster file containing two bands:\n",
+ "1. The label of the winning class\n",
+ "2. The probability of the winning class [0 - 100]\n",
"\n",
- "In case you chose to store the original per-class probabilities, these are NOT written to a separate file and need to be consulted in the original result downloaded from OpenEO."
+ "Using the function below, we split this information into separate .tif files, thereby adding metadata and a color map, to ease interpretation and visualization:\n",
+ "- \"cropland_classification_start-date_end-date.tif\" --> contains the classification labels. A class look-up table is included in the .tif metadata.\n",
+ "- \"cropland_confidence_start-date_end-date.tif\" --> contains the probability associated to the prediction [0 - 100]"
]
},
{
@@ -599,36 +356,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The resulting raster files can be visualized in QGIS, or using the function in the cell below..."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from utils import visualize_products\n",
- "\n",
- "visualize_products(rasters, port=8887)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Finally, use the cell below to visualize the look-up table for the classification product."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from utils import show_color_legend\n",
- "\n",
- "show_color_legend(rasters, \"cropland\")"
+ "The resulting raster files can be visualized in QGIS."
]
}
],
diff --git a/notebooks/worldcereal_v1_demo_custom_cropland_extended.ipynb b/notebooks/worldcereal_v1_demo_custom_cropland_extended.ipynb
new file mode 100644
index 00000000..eaf6490c
--- /dev/null
+++ b/notebooks/worldcereal_v1_demo_custom_cropland_extended.ipynb
@@ -0,0 +1,433 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "![](./resources/System_v1_custom_cropland.png)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Introduction\n",
+ "\n",
+ "This notebook guides you through the process of training a custom cropland classification model using publicly available and harmonized in-situ reference data for your area of interest. Afterwards, the model can be applied to your area and season of interest to generate a cropland extent map.\n",
+ "\n",
+ "Please note that for the purpose of this demo, the processing area is currently limited to 250 km² per model run. On average, one such run consumes 35 credits on the Copernicus Data Space Ecosystem."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Content\n",
+ " \n",
+ "- [Before you start](###-Before-you-start)\n",
+ "- [1. Define your region of interest](#1.-Define-your-region-of-interest)\n",
+ "- [2. Extract public reference data](#2.-Extract-public-reference-data)\n",
+ "- [3. Create your custom cropland class](#3.-Create-your-custom-cropland-class)\n",
+ "- [4. Prepare training features](#4.-Prepare-training-features)\n",
+ "- [5. Train custom classification model](#5.-Train-custom-classification-model)\n",
+ "- [6. Deploy your custom model](#6.-Deploy-your-custom-model)\n",
+ "- [7. Generate a map](#7.-Generate-a-map)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Before you start\n",
+ "\n",
+ "In order to run WorldCereal crop mapping jobs from this notebook, you need to create an account on the Copernicus Data Space Ecosystem (CDSE) registering [here](https://dataspace.copernicus.eu/). This is free of charge and will grant you a number of free openEO processing credits to continue this demo."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 1. Define your region of interest\n",
+ "\n",
+ "When running the code snippet below, an interactive map will be visualized.\n",
+ "Click the Rectangle button on the left hand side of the map to start drawing your region of interest.\n",
+ "\n",
+ "Currently, there is a maximum size of 250 km² for your area within this demo. Upon exceeding this limit, an error will be shown.\n",
+ "You can bypass this limit by altering the code below to:
\n",
+ "*map = ui_map(area_limit=750)*
\n",
+ "\n",
+ "Processing areas beyond 750 km² are currently not supported to avoid excessive credit usage (roughly 120 credits will be consumed for this size of a processing extent).\n",
+ "\n",
+ "The widget will automatically store the coordinates of the last rectangle you drew on the map."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.utils.map import ui_map\n",
+ "\n",
+ "map = ui_map()\n",
+ "map.show_map()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 2. Extract public reference data\n",
+ "\n",
+ "Here we query existing reference data that have already been processed by WorldCereal and are ready to use.\n",
+ "To increase the number of hits, we expand the search area by 250 km in all directions.\n",
+ "\n",
+ "We print the number of training samples retrieved per year."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.utils.refdata import query_public_extractions\n",
+ "\n",
+ "# retrieve the polygon you just drew\n",
+ "polygon = map.get_polygon_latlon()\n",
+ "\n",
+ "# Query our public database of training data\n",
+ "public_df = query_public_extractions(polygon, filter_cropland=False)\n",
+ "public_df.year.value_counts()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 3. Create your custom cropland class\n",
+ "\n",
+ "Run the next cell and select all land cover classes you would like to include in your \"cropland\" class. All classes that are not selected will be grouped under the \"other\" category. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# from utils import pick_croptypes\n",
+ "from utils import select_landcover\n",
+ "from IPython.display import display\n",
+ "\n",
+ "checkbox, checkbox_widgets = select_landcover(public_df)\n",
+ "display(checkbox)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Based on your selection, a custom target label is now generated for each sample. Verify that only land cover classes of your choice are appearing in the `downstream_class`, all others will fall under `other`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import get_custom_cropland_labels\n",
+ "\n",
+ "public_df = get_custom_cropland_labels(public_df, checkbox_widgets)\n",
+ "public_df[\"downstream_class\"].value_counts()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 4. Prepare training features\n",
+ "\n",
+ "Using a deep learning framework (Presto), we derive classification features for each sample. The resulting `encodings` and `targets` will be used for model training."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import prepare_training_dataframe\n",
+ "\n",
+ "training_dataframe = prepare_training_dataframe(public_df, task_type=\"cropland\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 5. Train custom classification model\n",
+ "We train a catboost model for the selected land cover classes. Class weights are automatically determined to balance the individual classes."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import train_cropland_classifier\n",
+ "\n",
+ "custom_model, report, confusion_matrix = train_cropland_classifier(training_dataframe)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Before training, the available training data has been automatically split into a calibration and validation part. By executing the next cell, you get an idea of how well the model performs on the independent validation set."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Print the classification report\n",
+ "print(report)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 6. Deploy your custom model\n",
+ "\n",
+ "Once trained, we have to upload our model to the cloud so it can be used by OpenEO for inference. Note that these models are only kept in cloud storage for a limited amount of time.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.utils.upload import deploy_model\n",
+ "from openeo_gfmap.backend import cdse_connection\n",
+ "from utils import get_input\n",
+ "\n",
+ "modelname = get_input(\"model\")\n",
+ "model_url = deploy_model(cdse_connection(), custom_model, pattern=modelname)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 7. Generate a map\n",
+ "\n",
+ "Using our custom model, we generate a map for our region and season of interest.\n",
+ "To determine your season of interest, you can consult the WorldCereal crop calendars (by executing the next cell), or check out the [USDA crop calendars](https://ipad.fas.usda.gov/ogamaps/cropcalendar.aspx)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import retrieve_worldcereal_seasons\n",
+ "\n",
+ "spatial_extent = map.get_processing_extent()\n",
+ "seasons = retrieve_worldcereal_seasons(spatial_extent)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now use the slider to select your processing period. Note that the length of the period is always fixed to a year.\n",
+ "Just make sure your season of interest is fully captured within the period you select."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import date_slider\n",
+ "\n",
+ "slider = date_slider()\n",
+ "slider.show_slider()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Set some other customization options:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.job import PostprocessParameters\n",
+ "import os\n",
+ "from pathlib import Path\n",
+ "\n",
+ "# Choose whether or not you want to spatially clean the classification results\n",
+ "postprocess_result = True\n",
+ "# Choose the postprocessing method you want to use [\"smooth_probabilities\", \"majority_vote\"]\n",
+ "# (\"smooth_probabilities will do limited spatial cleaning,\n",
+ "# while \"majority_vote\" will do more aggressive spatial cleaning, depending on the value of kernel_size)\n",
+ "postprocess_method = \"majority_vote\"\n",
+ "# Additional parameter for the majority vote method \n",
+ "# (the higher the value, the more aggressive the spatial cleaning,\n",
+ "# should be an odd number, not larger than 25, default = 5)\n",
+ "kernel_size = 5\n",
+ "# Do you want to save the intermediate results (before applying the postprocessing)\n",
+ "save_intermediate = True\n",
+ "# Do you want to save all class probabilities in the final product?\n",
+ "keep_class_probs = True\n",
+ "\n",
+ "postprocess_parameters = PostprocessParameters(enable=postprocess_result,\n",
+ " method=postprocess_method,\n",
+ " kernel_size=kernel_size,\n",
+ " save_intermediate=save_intermediate,\n",
+ " keep_class_probs=keep_class_probs)\n",
+ "\n",
+ "# Specify the local directory where the resulting maps should be downloaded to.\n",
+ "run = get_input(\"model run\")\n",
+ "output_dir = Path(os.getcwd()) / f'CROPLAND_{modelname}_{run}'\n",
+ "print(f\"Output directory: {output_dir}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We now have all information we need to generate our map!
\n",
+ "The next cell will submit a map inference job on CDSE through OpenEO.
\n",
+ "The first time you run this, you will be asked to authenticate with your CDSE account by clicking the link provided below the cell.
\n",
+ "Then sit back and wait untill your map is ready..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.job import generate_map, CropLandParameters\n",
+ "\n",
+ "# Initializes default parameters\n",
+ "parameters = CropLandParameters()\n",
+ "\n",
+ "# Change the URL to your custom classification model\n",
+ "parameters.classifier_parameters.classifier_url = model_url\n",
+ "\n",
+ "# Get processing period and area\n",
+ "processing_period = slider.get_processing_period()\n",
+ "processing_extent = map.get_processing_extent()\n",
+ "\n",
+ "# Launch the job\n",
+ "job_results = generate_map(\n",
+ " processing_extent,\n",
+ " processing_period,\n",
+ " output_dir=output_dir,\n",
+ " cropland_parameters=parameters,\n",
+ " postprocess_parameters=postprocess_parameters,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The classification results will be automatically downloaded to your *output_dir* in .tif format.\n",
+ "\n",
+ "For a model with two classes, you get a raster file containing a maximum of four bands:\n",
+ "1. The label of the winning class\n",
+ "2. The probability of the winning class [0 - 100]\n",
+ "3. and beyond (optional,depending on settings): Class probabilities of each class, ordered according to the look-up table. The look-up table for each product can be consulted in the 'results' object as produced by the 'generate_map' function.\n",
+ "\n",
+ "Using the function below, we split this information into separate .tif files, thereby adding metadata and a color map, to ease interpretation and visualization:\n",
+ "- \"xxx_classification_start-date_end-date.tif\" --> contains the classification labels. A class look-up table is included in the .tif metadata.\n",
+ "- \"xxx_confidence_start-date_end-date.tif\" --> contains the probability associated to the prediction [0 - 100]\n",
+ "\n",
+ "In case you chose to store the original per-class probabilities, these are NOT written to a separate file and need to be consulted in the original result downloaded from OpenEO."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import prepare_visualization\n",
+ "\n",
+ "rasters = prepare_visualization(job_results)\n",
+ "print(rasters)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The resulting raster files can be visualized in QGIS.\n",
+ "\n",
+ "In case you are running this script on your local environment, you can alternatively use the following cells to visualize the outputs directly in this notebook."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import visualize_products\n",
+ "\n",
+ "visualize_products(rasters, port=8887)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import show_color_legend\n",
+ "\n",
+ "show_color_legend(rasters, \"cropland\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "worldcereal",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/notebooks/worldcereal_v1_demo_custom_croptype.ipynb b/notebooks/worldcereal_v1_demo_custom_croptype.ipynb
index 5aa4730b..411f8f4c 100644
--- a/notebooks/worldcereal_v1_demo_custom_croptype.ipynb
+++ b/notebooks/worldcereal_v1_demo_custom_croptype.ipynb
@@ -11,99 +11,61 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "**Table of contents**
\n",
- "- [Before you start](#toc1_) \n",
- "- [Define a region of interest](#toc2_) \n",
- "- [Extract public training data](#toc3_) \n",
- "- [Select desired crops for prediction](#toc4_) \n",
- "- [Extract required model inputs](#toc5_) \n",
- "- [Train custom classification model](#toc6_) \n",
- "- [Deploy custom model](#toc7_) \n",
- "- [Generate a map](#toc8_) \n",
+ "### Introduction\n",
"\n",
- "\n",
- ""
+ "This notebook guides you through the process of training a custom crop type classification model using publicly available and harmonized in-situ reference data for your area and crop types of interest. Afterwards, the model can be applied to your season of interest to generate a crop type map.\n",
+ "\n",
+ "Please note that for the purpose of this demo, the processing area is limited to 250 km² per model run. On average, one such run consumes xxx credits on the Copernicus Data Space Ecosystem."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "#
[Before you start](#toc0_)\n",
- "\n",
- "In order to run WorldCereal crop mapping jobs from this notebook, you need to create an account on the Copernicus Data Space Ecosystem (CDSE) registering [here](https://dataspace.copernicus.eu/). This is free of charge and will grant you a number of free openEO processing credits to continue this demo."
+ "### Content\n",
+ " \n",
+ "- [Before you start](###-Before-you-start)\n",
+ "- [1. Define your region of interest](#1.-Define-your-region-of-interest)\n",
+ "- [2. Extract public reference data](#2.-Extract-public-reference-data)\n",
+ "- [3. Select your desired crop types](#3.-Select-your-desired-crop-types)\n",
+ "- [4. Prepare training features](#4.-Prepare-training-features)\n",
+ "- [5. Train custom classification model](#5.-Train-custom-classification-model)\n",
+ "- [6. Deploy your custom model](#6.-Deploy-your-custom-model)\n",
+ "- [7. Generate a map](#7.-Generate-a-map)\n"
]
},
{
- "cell_type": "code",
- "execution_count": 5,
+ "cell_type": "markdown",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "The autoreload extension is already loaded. To reload it, use:\n",
- " %reload_ext autoreload\n"
- ]
- }
- ],
"source": [
- "# TEMPORARY CELL\n",
+ "### Before you start\n",
"\n",
- "import sys\n",
- "sys.path.append('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/notebooks')\n",
- "%load_ext autoreload\n",
- "%autoreload 2"
+ "In order to run WorldCereal crop mapping jobs from this notebook, you need to create an account on the Copernicus Data Space Ecosystem (CDSE) registering [here](https://dataspace.copernicus.eu/). This is free of charge and will grant you a number of free openEO processing credits to continue this demo."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "#
[Define a region of interest](#toc0_)\n",
+ "### 1. Define your region of interest\n",
"\n",
"When running the code snippet below, an interactive map will be visualized.\n",
"Click the Rectangle button on the left hand side of the map to start drawing your region of interest.\n",
+ "\n",
"Currently, there is a maximum size of 250 km² for your area within this demo. Upon exceeding this limit, an error will be shown.\n",
+ "You can bypass this limit by altering the code below to:
\n",
+ "*map = ui_map(area_limit=750)*
\n",
+ "\n",
+ "Processing areas beyond 750 km² are currently not supported to avoid excessive credit usage (roughly 120 credits will be consumed for this size of a processing extent).\n",
+ "\n",
"The widget will automatically store the coordinates of the last rectangle you drew on the map."
]
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "ba074684b1b34f3babdc149124fe94a3",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "Map(center=[51.1872, 5.1154], controls=(ZoomControl(options=['position', 'zoom_in_text', 'zoom_in_title', 'zoo…"
- ]
- },
- "execution_count": 2,
- "metadata": {},
- "output_type": "execute_result"
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 19:08:09.833\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mhandle_draw\u001b[0m:\u001b[36m13\u001b[0m - \u001b[1mYour processing extent: (10.349941, 53.119306, 10.408676, 53.145054)\u001b[0m\n",
- "\u001b[32m2024-10-14 19:08:09.915\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mhandle_draw\u001b[0m:\u001b[36m19\u001b[0m - \u001b[1mArea of processing extent: 11.71 km²\u001b[0m\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"from worldcereal.utils.map import ui_map\n",
"\n",
@@ -115,41 +77,19 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "#
[Extract public training data](#toc0_)\n",
+ "### 2. Extract public reference data\n",
"\n",
"Here we query existing reference data that have already been processed by WorldCereal and are ready to use.\n",
- "To increase the number of hits, we expand the search area by 250 km in all directions."
+ "To increase the number of hits, we expand the search area by 250 km in all directions.\n",
+ "\n",
+ "We print the number of training samples retrieved per year."
]
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 19:08:17.731\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mget_processing_extent\u001b[0m:\u001b[36m112\u001b[0m - \u001b[1mYour processing extent: (10.349941, 53.119306, 10.408676, 53.145054)\u001b[0m\n",
- "\u001b[32m2024-10-14 19:08:17.733\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.refdata\u001b[0m:\u001b[36mquery_public_extractions\u001b[0m:\u001b[36m51\u001b[0m - \u001b[1mApplying a buffer of 250 km to the selected area ...\u001b[0m\n",
- "\u001b[32m2024-10-14 19:08:17.892\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.refdata\u001b[0m:\u001b[36mquery_public_extractions\u001b[0m:\u001b[36m81\u001b[0m - \u001b[1mQuerying WorldCereal global extractions database (this can take a while) ...\u001b[0m\n",
- "\u001b[32m2024-10-14 19:08:35.070\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.refdata\u001b[0m:\u001b[36mprocess_parquet\u001b[0m:\u001b[36m127\u001b[0m - \u001b[1mProcessing selected samples ...\u001b[0m\n",
- "\u001b[32m2024-10-14 19:08:35.463\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.refdata\u001b[0m:\u001b[36mprocess_parquet\u001b[0m:\u001b[36m130\u001b[0m - \u001b[1mExtracted and processed 582 samples from global database.\u001b[0m\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "year\n",
- "2018 582\n",
- "Name: count, dtype: int64"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"from worldcereal.utils.refdata import query_public_extractions\n",
"\n",
@@ -165,31 +105,16 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "#
[Select desired crops for prediction](#toc0_)\n",
+ "### 3. Select your desired crop types\n",
"\n",
- "Run the next cell and select all crop types you wish to include in your model. All the crops that are not selected will be grouped under the \"other_crop\" category. The model will be trained in a multi-class setting."
+ "Run the next cell and select all crop types you wish to include in your model. All the crops that are not selected will be grouped under the \"other\" category."
]
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "b1be511b4fd1451abc657b389f3df5d6",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "VBox(children=(Checkbox(value=False, description='unspecified_wheat (192 samples)'), Checkbox(value=False, des…"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
+ "outputs": [],
"source": [
"from utils import pick_croptypes\n",
"from IPython.display import display\n",
@@ -207,24 +132,9 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "downstream_class\n",
- "other 252\n",
- "unspecified_wheat 192\n",
- "maize 138\n",
- "Name: count, dtype: int64"
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"from utils import get_custom_croptype_labels\n",
"\n",
@@ -236,36 +146,16 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "#
[Extract required model inputs](#toc0_)\n",
+ "### 4. Prepare training features\n",
"\n",
- "Here we prepare presto inputs features for each sample by using a model pretrained on WorldCereal data. The resulting `encodings` and `targets` will be used for model training."
+ "Using a deep learning framework (Presto), we derive classification features for each sample. The resulting `encodings` and `targets` will be used for model training."
]
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 19:09:21.714\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mutils\u001b[0m:\u001b[36mprepare_training_dataframe\u001b[0m:\u001b[36m324\u001b[0m - \u001b[1mPresto URL: https://artifactory.vgt.vito.be/artifactory/auxdata-public/worldcereal/models/PhaseII/presto-ss-wc-ft-ct_croptype_CROPTYPE0_30D_random_time-token=month_balance=True_augment=True.pt\u001b[0m\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 19:09:21.893\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.train.data\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m35\u001b[0m - \u001b[1mAugmentation is enabled. The horizontal jittering of the selected window will be performed.\u001b[0m\n",
- "\u001b[32m2024-10-14 19:09:21.895\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.train.data\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m51\u001b[0m - \u001b[1mOriginal dataset size: 582\u001b[0m\n",
- "\u001b[32m2024-10-14 19:09:21.896\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.train.data\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m57\u001b[0m - \u001b[1mDataset size after 1 repeats: 582\u001b[0m\n",
- "\u001b[32m2024-10-14 19:09:21.896\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mutils\u001b[0m:\u001b[36mprepare_training_dataframe\u001b[0m:\u001b[36m340\u001b[0m - \u001b[1mComputing Presto embeddings ...\u001b[0m\n",
- "100%|██████████| 3/3 [00:02<00:00, 1.14it/s]\n",
- "\u001b[32m2024-10-14 19:09:24.543\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mutils\u001b[0m:\u001b[36mprepare_training_dataframe\u001b[0m:\u001b[36m348\u001b[0m - \u001b[1mDone.\u001b[0m\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"from utils import prepare_training_dataframe\n",
"\n",
@@ -276,81 +166,33 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "#
[Train custom classification model](#toc0_)\n",
+ "### 5. Train custom classification model\n",
"We train a catboost model for the selected crop types. Class weights are automatically determined to balance the individual classes."
]
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 19:09:31.606\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mutils\u001b[0m:\u001b[36mtrain_classifier\u001b[0m:\u001b[36m395\u001b[0m - \u001b[1mSplit train/test ...\u001b[0m\n",
- "\u001b[32m2024-10-14 19:09:31.617\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mutils\u001b[0m:\u001b[36mtrain_classifier\u001b[0m:\u001b[36m414\u001b[0m - \u001b[1mComputing class weights ...\u001b[0m\n",
- "\u001b[32m2024-10-14 19:09:31.621\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mutils\u001b[0m:\u001b[36mtrain_classifier\u001b[0m:\u001b[36m427\u001b[0m - \u001b[1mClass weights: {'maize': 1.409, 'other': 0.771, 'unspecified_wheat': 1.006}\u001b[0m\n",
- "\u001b[32m2024-10-14 19:09:31.661\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mutils\u001b[0m:\u001b[36mtrain_classifier\u001b[0m:\u001b[36m467\u001b[0m - \u001b[1mTraining CatBoost classifier ...\u001b[0m\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Learning rate set to 0.04805\n",
- "0:\tlearn: 1.0586911\ttest: 1.0637480\tbest: 1.0637480 (0)\ttotal: 91.7ms\tremaining: 12m 13s\n",
- "25:\tlearn: 0.5650713\ttest: 0.6863680\tbest: 0.6863680 (25)\ttotal: 768ms\tremaining: 3m 55s\n",
- "50:\tlearn: 0.3771754\ttest: 0.5571138\tbest: 0.5571138 (50)\ttotal: 1.39s\tremaining: 3m 36s\n",
- "75:\tlearn: 0.2801689\ttest: 0.4972990\tbest: 0.4972990 (75)\ttotal: 2.04s\tremaining: 3m 32s\n",
- "100:\tlearn: 0.2221873\ttest: 0.4668236\tbest: 0.4668236 (100)\ttotal: 2.64s\tremaining: 3m 26s\n",
- "125:\tlearn: 0.1820294\ttest: 0.4457419\tbest: 0.4457419 (125)\ttotal: 3.2s\tremaining: 3m 20s\n",
- "150:\tlearn: 0.1503336\ttest: 0.4347274\tbest: 0.4347274 (150)\ttotal: 3.78s\tremaining: 3m 16s\n",
- "175:\tlearn: 0.1263781\ttest: 0.4280751\tbest: 0.4280751 (175)\ttotal: 4.35s\tremaining: 3m 13s\n",
- "200:\tlearn: 0.1079100\ttest: 0.4259335\tbest: 0.4256174 (197)\ttotal: 4.92s\tremaining: 3m 11s\n",
- "225:\tlearn: 0.0934925\ttest: 0.4247271\tbest: 0.4247271 (225)\ttotal: 5.49s\tremaining: 3m 8s\n",
- "250:\tlearn: 0.0830328\ttest: 0.4214331\tbest: 0.4214331 (250)\ttotal: 6.07s\tremaining: 3m 7s\n",
- "275:\tlearn: 0.0740736\ttest: 0.4203690\tbest: 0.4201436 (274)\ttotal: 6.63s\tremaining: 3m 5s\n",
- "300:\tlearn: 0.0669315\ttest: 0.4195972\tbest: 0.4190787 (298)\ttotal: 7.21s\tremaining: 3m 4s\n",
- "325:\tlearn: 0.0610666\ttest: 0.4212918\tbest: 0.4190787 (298)\ttotal: 7.8s\tremaining: 3m 3s\n",
- "Stopped by overfitting detector (50 iterations wait)\n",
- "\n",
- "bestTest = 0.419078654\n",
- "bestIteration = 298\n",
- "\n",
- "Shrink model to first 299 iterations.\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"from utils import train_classifier\n",
"\n",
"custom_model, report, confusion_matrix = train_classifier(training_dataframe)"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Before training, the available training data has been automatically split into a calibration and validation part. By executing the next cell, you get an idea of how well the model performs on the independent validation set."
+ ]
+ },
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- " precision recall f1-score support\n",
- "\n",
- " maize 0.84 0.93 0.88 28\n",
- " other 0.85 0.80 0.83 51\n",
- "unspecified_wheat 0.82 0.82 0.82 38\n",
- "\n",
- " accuracy 0.84 117\n",
- " macro avg 0.84 0.85 0.84 117\n",
- " weighted avg 0.84 0.84 0.84 117\n",
- "\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"# Print the classification report\n",
"print(report)"
@@ -360,50 +202,30 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "#
[Deploy custom model](#toc0_)\n",
+ "### 6. Deploy your custom model\n",
"\n",
- "Once trained, we have to upload our model to the cloud so it can be used for inference. Note that these models are only kept in cloud storage for a limited amount of time.\n"
+ "Once trained, we have to upload our model to the cloud so it can be used by OpenEO for inference. Note that these models are only kept in cloud storage for a limited amount of time.\n"
]
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 19:10:03.213\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.upload\u001b[0m:\u001b[36mdeploy_model\u001b[0m:\u001b[36m205\u001b[0m - \u001b[1mDeploying model ...\u001b[0m\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Authenticated using refresh token.\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 19:10:07.957\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.upload\u001b[0m:\u001b[36mdeploy_model\u001b[0m:\u001b[36m211\u001b[0m - \u001b[1mDeployed to: s3://OpenEO-artifacts/fd307620ba8a0a07c44a2dc28541b181d5c03cb4/2024/10/14/demo_croptype_multiclass_DE_custommodel.onnx\u001b[0m\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"from worldcereal.utils.upload import deploy_model\n",
"from openeo_gfmap.backend import cdse_connection\n",
+ "from utils import get_input\n",
"\n",
- "model_url = deploy_model(cdse_connection(), custom_model, pattern=\"demo_croptype_multiclass_DE\")"
+ "modelname = get_input(\"model\")\n",
+ "model_url = deploy_model(cdse_connection(), custom_model, pattern=modelname)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "#
[Generate a map](#toc0_)\n",
+ "### 7. Generate a map\n",
"\n",
"Using our custom model, we generate a map for our region and season of interest.\n",
"To determine your season of interest, you can consult the WorldCereal crop calendars (by executing the next cell), or check out the [USDA crop calendars](https://ipad.fas.usda.gov/ogamaps/cropcalendar.aspx)."
@@ -411,27 +233,9 @@
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 19:10:13.168\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mget_processing_extent\u001b[0m:\u001b[36m112\u001b[0m - \u001b[1mYour processing extent: (10.349941, 53.119306, 10.408676, 53.145054)\u001b[0m\n"
- ]
- },
- {
- "data": {
- "image/png": "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/tTtzZgxA8HBwQUpgYiIiF5SBTq94uPjg2bNmsHLywtdunTB4sWLkZiYmKfdrFmzsHbtWmzcuBGmpqZP3d64ceOQlJSkucTFxRX8HhAREdFLoUChw9DQELt27cKOHTtQrVo1zJ8/H56enoiJidG0mTNnDr788kv8+uuv8Pb2fub21Go1rKystC5ERET0airwRFKVSoXAwEAEBwfjjz/+gImJCTZt2gQAmD17NqZOnYqdO3fC399f78USERHRy6tAczqOHj2KPXv2oGXLlihbtiyOHj2K27dvo2rVqpg1axYmTJiANWvWwM3NDTdv3gQAWFpawtLS8oUUT0RERC+PAoUOKysr/Pbbb5g3bx6Sk5Ph6uqKuXPnok2bNhg2bBgePnyId955R+s2kyZNwuTJk/VZMxEREb2EChQ6qlatip07d+a7LjY2Vh/1EBER0SuK/3uFiIiIFMHQQURERIpg6CAiIiJFMHQQERGRIhg6iIiISBEMHURERKQIhg4iIiJSBEMHERERKYKhg4iIiBTB0EFERESKYOggIiIiRTB0EBERkSIYOoiIiEgRDB1ERESkCIYOIiIiUgRDBxERESmCoYOIiIgUwdBBREREimDoICIiIkUwdBAREZEiGDqIiIhIEQwdREREpAiGDiIiIlIEQwcREREpgqGDiIiIFMHQQURERIpg6CAiIiJFMHQQERGRIhg6iIiISBEMHURERKQIhg4iIiJSBEMHERERKYKhg4iIiBTB0EFERESKYOggIiIiRTB0EBERkSIYOoiIiEgRDB30SjM2s4OBobq4yyAqsQwM1TA2syvuMug1YVTcBRC9SGbWzmgwJAqZaQnFXQpRiWRsZgcza+fiLoNeEwwd9Mozs3bmiyoRUQnA0ytERESkCIYOIiIiUgRDBxERESmCoYOIiIgUwdBBREREimDoICIiIkUwdBAREZEiGDqIiIhIEQwdREREpAiGDiIiIlIEQwe9EtzGuqHsx2WRmZWpWbY3ei9Ug1T45KdP9NZP7J1Y2I+y16ntuuPrUHNKTdSYVANek70wf898zToRwac/fYrqE6vDe7I3guYE4c9bf+qtTsrr0saNWFWrFlb4+mJp1apY36wZJCenSNs8OHkysh8+1FOF/5qjUuHh/ft6327i5ctYExCAJZUrY3WdOrhz/rxmXViTJljs7o4Vvr5Y4euLE998o/f+ifi/V+iV4WLrgi2nt6Bzrc4AgKUHl8Lf1b/A28nKzoKRYdGfGhVsKmDHhzvgYO2ApAdJqDWtFvxc/RBYKRBbTm/Bb5d/Q9TEKBgbGWPatmn4fOPnWD90fZH7pbxSb97ErqFD0ev4cVi7ugIA/jl1ClCpirTdw8HBqP3JJzA0MdFHmXqVk5UFAyPt/fjXIUPgPXgwavTrh4sbNuCX995Dz8OHNeubfvcdPNq1U7pUeo3wSAe9MgYEDsDSg0sBAEkPknDkryNoXaO1Zv3Za2fRcGZD+E31Q7WJ1TBj+wzNun5L+2Hk2pFoPa81fIJ9AADLDi6Db7AvfIJ94D/NH7F3YjXtJ26eiFpTa6HS55Ww/ez2fOsJrBQIB2sHAIC1uTWqOFRBzJ0YzfqMzAykZ6VDRJCcnowKNhX0Nhak7X58PAyMjGBm9++/cC/n5wfV/0NH4uXLCG/bFqtq18YKHx/8sWCBpt0clQoHJ0/GmsBALKlcGdFr1wIAdg0dCgBYExCAFb6+SL11Cw9TUvDLoEFYXacOlnt7Y9fQocjOfHT0LaxJE0R++inCGjXCQmdnHJs9GxfCwrAmIAALXV1xISxMq+bjc+bk6RMA4o8fx7qmTbHK3x8r/fxwKTwcAJAUG4v/2Nvj0JQpWNuwIU7Nn6+1vdRbt3Dr1ClU69ULAFC5c2ckxcQgKTZWH0NMpBspQZKSkgSAJCUlFXcp9JJxHeMqZ6+dlSrjq8i1u9fkh30/yNjwsTJp8yQZvX60iIgkpyVL+sN0ERF5kPFAfIN95XjMcRER6bukr9ScUlNS0lJERGTfhX3iMc5DbiTeEBGR1PRUSU1PlZjbMYKBkIg/IkREZMfZHVL5i8rPre/c9XNi+6GtXE+8LiIi2dnZ8lHYR2I+3FzKfVxO/Kb4afom/cvJzpaITp1kvo2NbHr7bTk6a5YkX7smIiLZWVmy0t9f7kRHi4jIw9RUWeblJTdPnhQRkdmAHJw8WUREEq9cke/t7CTp6lXNuoyUfx+3XwYNkv+uXPmoz5wc2fnee3L8669FRGRt48aypWtXycnOlpTr1+UbU1M58MUXIiJy4+hRWeDoqNnO0/pMS0yUFTVrSsqN/++Xt29LiIuL3I+Pl3sxMTIbkPOhofmOQfyJE7KkalWtZatq15ar+/dr6ltSpYosq1FDtnTtKolXrhRqrOn1pOv7N0+v0Culd73eWHFoBSKiIhA6MBShR0M169IepmH4T8MRFRcFA5UB4u7GISouCv5uj07BdPXvCktTSwDAz2d+Rp/6feBY2hEAYK42f7SRFMBCbYEOvh0AAPXd6+PK7SvPrOna3Wvo8J8OCOkVAqfSTgCAU1dP4cLNC7g++zqsTK0wduNYvL/mfSwfsFyfw0H/pzIwQIfwcCRcuIBr+/cjZscOHJ0+Hb1OnED2w4dIOHcO27p107R/mJKChPPnUc7PDwDgNXAgAKC0uzvKN2iA6wcOwKpHjzz9XI6IwI0jR3Bi7lwAQFZaGgweO/VSuUsXqAwMYOnkBDN7e1R6+20AQLlatZAaH4+s9HQYmZo+tU916dJI+usvhLdp82+nIrh78SKsXF1hZGqKKt27P30cnjidJCKav99ctQpWzs4QEfzxn/9gY7t2GPDYnA8ifWDooFdKv8B+8Jvqh8rlKuONcm9orft80+coZ1UOf0z4A0aGRui0oBPSM9M16y3Vljr1YWpsqvnb0MAQ2TnZT217494NNP+mOca3HY8u/l00y5cfWo4gzyCUNi8NAOhbvy/e/O5NnfqnwrOrUgV2VarAZ8gQbGjdGle2bIFbq1Yws7dH36go3Tf0tLkgIng7IgKl3d3zXZ0bKABAZWgIw/9fNzA0BPBoHsaz+hQRlPH2RrfffsuzOik2FsYWFnmCRa5Szs5IuXZNM9dDRJASFwcrFxcAgJWz8/+7UcHv/fex/5NPkJaQoHVKiqioOKeDXilOpZ0wo9MMzOw8M8+6xAeJqGBTAUaGRrh48yJ2nd/11O2092mPlYdX4mbSTQDAg4wHeJDxoEC1xN+LR7O5zTCm9Rj0Deirtc7d3h17ovdovm2z9cxW1Chfo0DbJ92lXL+O6wcPaq6nJyYiKSYGpT08YOvpCWNzc5xbuVKzPvHPP5F2967m+n+X/n+uUGwsrv/+O8o3aAAAMClVChlJSZp2Hm+9hWNffaUJD+mJiUj8s3DfSsqvz/IBAUi8fBlX9+7VtLsVFaXTN2gsypZF2Zo1cX71agDApfBwWLu5wdrNDTlZWUj95x9N20vh4TAvV46Bg/SORzroldM/sH++y8e3HY/eS3oj9Ego3Ozd0LRK06duo1HlRhjfdjxaftMSKpUKJoYm2DBsQ4HqmLhlIq7evYpvd3+Lb3d/CwD4sPmH6B/YHyOCRiD6ZjS8gr1gYmgCR2tHLOy9sEDbJ93lZGXh8JQpSIqJgZG5OXKyslC9b19U6vDoNFnHrVuxb9QoHJ8zB5KdDbMyZdA29N9Tc4ZqNdYEBiLt9m00nT9fc1TAf/RorG/aFEZmZnjn11/RdN487B8zBit8faEyMIChsTEazZwJm0qVClzz0/rsuHUr9n/6KfaNGoXszExYubjg7YgInbbZcuFC7OjXD0e//BImVlZos2IFACArIwMb27ZFdkYGVAYGMLO3R8ctWwpcM9HzqOTxk3rFLDk5GdbW1khKSoKVlVVxl0NEhDkqFUampMDEUrfTb0SvI13fv3l6hYiIiBTB0ytERM/wSck5GEz00uORDiIiIlIEQwcREREpgqGDiIiIFMHQQURERIpg6CAiIiJFMHQQERGRIhg6iIiISBEMHURERKQIhg4iIiJSBEMHERERKYKhg4iIiBTB0EFERESKYOggIiIiRTB0EBERkSIYOoiIiEgRDB1ERESkCIYOIiIiUgRDBxERESmCoYOIiIgUwdBBREREimDoICIiIkUwdBAREZEiGDqIiIhIEQwdREREpAiGDiIiIlIEQwcREREpgqGDiIiIFMHQQURERIpg6CAiIiJFMHQQERGRIhg6iIiISBEMHURERKQIhg4iIiJSBEMHERERKYKhg4iIiBTB0EFERESKYOggIiIiRTB0EBERkSIYOoiIiEgRDB1ERESkCIYOIiIiUgRDBxERESmCoYOIiIgUwdBBREREimDoICIiIkUwdBAREZEiGDqIiIhIEQwdREREpAiGDiIiIlIEQwcREREpgqGDiIiIFMHQQURERIpg6CAiIiJFMHQQERGRIhg6iIiISBEMHURERKQIhg4iIiJSBEMHERERKYKhg4iIiBTB0EFERESKYOggIiIiRTB0EBERkSIYOoiIiEgRRsVdwMsiLSkOmWkJxV0GEb1CjM3sYGbtXNxlAOBr3MukJO03BcXQoYO0pDj8vtAXOdkZxV0KEb1CDAzVaDAkqtjfQPga93IpKftNYfD0ig4y0xL4ZCQivcvJzigRRxf4GvdyKSn7TWEwdBAREZEiGDqIiIhIEQwdREREpAiGDiIiIlIEQwcREREpgqGDiIiIFMHQQURERIpg6CAiIiJFMHQQERGRIhg6iIiISBEMHURERKQIhg4iIiJSBEMHERERKYKhg4iIiBTB0EFERESKYOggIiIiRTB0EBERkSIYOoiIiEgRDB1ERESkCIYOIiIiUgRDBxERESmCoYOIiIgUwdBBREREimDoICIiIkUwdBAREZEiGDqIiIhIEQwdREREpAiGDiIiIlIEQwcREREpgqGDiIiIFMHQQURERIpg6CAiIiJFMHQQERGRIhg6iIiISBEMHURERKQIhg4iIiJSBEMHERERKYKhg4iIiBSht9Bx7tw5dO7cGW5ublCpVJg3b56+Nk1ERESvAL2FjgcPHsDd3R1fffUVHBwc9LVZIiIiekUUOHRs2LABXl5eMDMzg52dHZo3b47U1FTUrl0bs2fPRrdu3aBWq19ErURERPQSMypI4/j4eHTv3h2zZs1Cx44dkZKSggMHDkBECtV5RkYGMjIyNNeTk5MLtR0iIiIq+QocOrKystCpUye4uroCALy8vArd+YwZMxAcHFzo2xMREdHLo0CnV3x8fNCsWTN4eXmhS5cuWLx4MRITEwvd+bhx45CUlKS5xMXFFXpbREREVLIVKHQYGhpi165d2LFjB6pVq4b58+fD09MTMTExhepcrVbDyspK60JERESvpgJPJFWpVAgMDERwcDD++OMPmJiYYNOmTS+iNiIiInqFFGhOx9GjR7Fnzx60bNkSZcuWxdGjR3H79m1UrVoVDx8+xPnz5wEADx8+xPXr1xEVFQVLS0tUqlTphRRPREREL48ChQ4rKyv89ttvmDdvHpKTk+Hq6oq5c+eiTZs2iI2NRc2aNTVt58yZgzlz5qBx48aIjIzUd91ERET0kilQ6KhatSp27tyZ7zo3N7dCf3WWiIiIXn383ytERESkCIYOIiIiUgRDBxERESmCoYOIiIgUwdBBREREimDoICIiIkUwdBAREZEiGDqIiIhIEQwdREREpAiGDiIiIlIEQwcREREpgqGDiIiIFMHQQURERIpg6CAiIiJFMHQQERGRIhg6iIiISBEMHURERKQIhg4iIiJSBEMHERERKYKhg4iIiBTB0EFERESKYOggIiIiRTB0EBERkSIYOoiIiEgRDB1ERESkCIYOIiIiUgRDBxERESmCoYOIiIgUwdBBREREimDoICIiIkUwdBAREZEiGDqIiIhIEQwdREREpAiGDiIiIlIEQwcREREpgqGDiIiIFMHQQURERIpg6NCBsZkdDAzVxV0GEb1iDAzVMDaz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N0fHjh31XmfTpk2xfPlytG/fHjY2NpgwYUKeeoub0jXqsm/t2bMH5ubm+Pzzz/HBBx/g2LFjWt9uAYAPPvgAgwYNgr+/PwICArBu3TqcOXMG7u7uRaovISEBXbp0wYABA+Dt7Y1SpUrhxIkTmDVrFjp06IDmzZujfv36ePvttzFz5kx4enrixo0b2L59O95++23N6U1TU1P07dsXc+bMQXJyMkaOHImuXbvCwcGhSPV9//33CAgIQKtWrTBt2jRUrFgR586dw6effory5ctj+vTpsLW1Rd++fTFgwAB899138PHxwd9//41bt26ha9eucHV1hUqlwrZt2/Dmm2/CzMwMlpaWRaorl5eXF3r27KkV4kePHo3atWtj6tSpePfdd3H48GF8//33WLBggdZte/bsicmTJ+Phw4ea15eiysjIwM2bN5GdnY1//vkHO3fuxIwZM9CuXTv06dMHBgYGz308J02ahGbNmsHDwwPdunVDVlYWduzYgc8++0wvNepFMc0lKVF69+4tnTt3FhGRXbt2SdWqVUWtVou3t7dERkZqTYjKnQT5xx9/aG6fmJgoAGTfvn16qedZk4p27twpAQEBYmZmJlZWVlKnTh1ZtGiRZj0A+c9//iMtWrQQtVotrq6usnbt2hdak4hoTY4szBgWVrt27eTNN9/Md93JkycFgMydO1cAyNatW6V69epiYmIitWvX1po0mt+EwMLS51jlSklJEXNzcxk+fLheahTR3u+TkpKka9euYmVlJc7OzrJ8+XKdJmlaW1vLsmXL9FbTi6ixsHTZt06ePCmbNm2SSpUqiampqbRr104WLVokT760TpkyRezt7cXS0lIGDBggI0eOlHr16hWpvvT0dBk7dqz4+fmJtbW1mJubi6enp4wfP14ePHggIiLJycnywQcfiJOTkxgbG4uzs7P07NlTrl69KiKPJpL6+PjIggULxMnJSUxNTaVTp05y9+7dItWWKzY2Vvr16ycODg6a/j/44AO5c+eOpk1aWpqMGjVKHB0dxcTERCpVqiRLly7VrJ8yZYo4ODiISqV66gRsXeT3vIyNjRW1Wq31eG3YsEGqVasmxsbG4uLiIrNnz86zrcTERFGr1WJubi4pKSmFrunx2gAIADEyMpIyZcpI8+bNZenSpZKdna1p97zHU0QkPDxcfH19xcTEROzt7aVTp05Frk+fVCJ6PLn4kmrdujUqVaqE77//vrhLoRcgMjISQUFBSExMfOa57JIsLi4Obm5uOH78OPz8/PSyzZdhv38ZaiyMFi1awMHBAatWrSrWOiZPnoyIiIg8p4SIXpTX+vRKYmIiDh06hMjIyHx/spqouGVmZiI+Ph5jx45FvXr19BI4Xob9/mWoUVcPHjxASEgIWrVqBUNDQ6xduxa7d+/Grl27irs0IsW91qFjwIABOH78OEaPHo0OHToUdzlEeRw8eBBBQUGoXLkyNmzYoJdtvgz7/ctQo65UKhW2b9+OadOmISMjA56enggPD8934iTRq46nV4iIiEgR/HEwIiIiUgRDBxERESmCoYOIiIgUwdBBREREimDoICIiIkUwdBAREZEiGDqIiIhIEQwdREREpIj/AYudtDwNOhQRAAAAAElFTkSuQmCC",
- "text/plain": [
- "
"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
+ "outputs": [],
"source": [
"from utils import retrieve_worldcereal_seasons\n",
"\n",
@@ -449,24 +253,9 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "58fbf1920eb141448a8240dec13e496b",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "VBox(children=(HTML(value=\"\\n \\n
\n",
+ "The next cell will submit a map inference job on CDSE through OpenEO.
\n",
+ "The first time you run this, you will be asked to authenticate with your CDSE account by clicking the link provided below the cell.
\n",
+ "Then sit back and wait untill your map is ready..."
+ ]
+ },
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 20:20:20.647\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mutils\u001b[0m:\u001b[36mget_processing_period\u001b[0m:\u001b[36m120\u001b[0m - \u001b[1mSelected processing period: 2018-12-01 to 2019-11-30\u001b[0m\n",
- "\u001b[32m2024-10-14 20:20:20.717\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mget_processing_extent\u001b[0m:\u001b[36m112\u001b[0m - \u001b[1mYour processing extent: (10.349941, 53.119306, 10.408676, 53.145054)\u001b[0m\n",
- "INFO:openeo.rest.connection:Found OIDC providers: ['CDSE']\n",
- "INFO:openeo.rest.connection:No OIDC provider given, but only one available: 'CDSE'. Using that one.\n",
- "INFO:openeo.rest.connection:Using default client_id 'sh-b1c3a958-52d4-40fe-a333-153595d1c71e' from OIDC provider 'CDSE' info.\n",
- "INFO:openeo.rest.connection:Found refresh token: trying refresh token based authentication.\n",
- "INFO:openeo.rest.auth.oidc:Doing 'refresh_token' token request 'https://identity.dataspace.copernicus.eu/auth/realms/CDSE/protocol/openid-connect/token' with post data fields ['grant_type', 'client_id', 'refresh_token'] (client_id 'sh-b1c3a958-52d4-40fe-a333-153595d1c71e')\n",
- "INFO:openeo.rest.connection:Obtained tokens: ['access_token', 'id_token', 'refresh_token']\n",
- "INFO:openeo.rest.auth.config:Storing refresh token for issuer 'https://identity.dataspace.copernicus.eu/auth/realms/CDSE' (client 'sh-b1c3a958-52d4-40fe-a333-153595d1c71e')\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Authenticated using refresh token.\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "2024-10-14 20:20:35,372 - openeo_gfmap.utils - INFO - Selected orbit state: ASCENDING. Reason: Orbit has more cumulative intersected area. 0.9639606281260852 > 0.5250584645381887\n",
- "INFO:openeo_gfmap.utils:Selected orbit state: ASCENDING. Reason: Orbit has more cumulative intersected area. 0.9639606281260852 > 0.5250584645381887\n",
- "WARNING:PrestoFeatureExtractor:No additional dependencies are defined. If you wish to add dependencies to your feature extractor, override the `dependencies` method in your class.\n",
- "WARNING:PrestoFeatureExtractor:No additional dependencies are defined. If you wish to add dependencies to your feature extractor, override the `dependencies` method in your class.\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "0:00:00 Job 'j-2410145b1b3c43b8851ed611261b9ecb': send 'start'\n",
- "0:00:20 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:00:25 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:00:32 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:00:40 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:00:50 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:01:03 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:01:19 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:01:39 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:02:03 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:02:33 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:03:11 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:03:58 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:04:57 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:05:58 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:06:58 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:07:58 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:08:59 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:09:59 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:10:59 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:12:00 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:13:00 Job 'j-2410145b1b3c43b8851ed611261b9ecb': running (progress N/A)\n",
- "0:14:01 Job 'j-2410145b1b3c43b8851ed611261b9ecb': finished (progress 100%)\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "INFO:openeo.rest.job:Downloading Job result asset 'cropland-raw_20181201_20191130.tif' from https://openeo.creo.vito.be/openeo/jobs/j-2410145b1b3c43b8851ed611261b9ecb/results/assets/ZGNjYWI2ZDktODQ2Yy00OGE5LTlkOTQtNDk3MTQ2Y2IyMjg1/990ac36cfcb6a2797bcf85bfa5b3ed7c/cropland-raw_20181201_20191130.tif?expires=1729535690 to /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/cropland-raw_20181201_20191130.tif\n",
- "INFO:openeo.rest.job:Downloading Job result asset 'cropland_20181201_20191130.tif' from https://openeo.creo.vito.be/openeo/jobs/j-2410145b1b3c43b8851ed611261b9ecb/results/assets/ZGNjYWI2ZDktODQ2Yy00OGE5LTlkOTQtNDk3MTQ2Y2IyMjg1/1199815155d5ed90ed8be9d0eede8b30/cropland_20181201_20191130.tif?expires=1729535690 to /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/cropland_20181201_20191130.tif\n",
- "INFO:openeo.rest.job:Downloading Job result asset 'croptype-raw_20181201_20191130.tif' from https://openeo.creo.vito.be/openeo/jobs/j-2410145b1b3c43b8851ed611261b9ecb/results/assets/ZGNjYWI2ZDktODQ2Yy00OGE5LTlkOTQtNDk3MTQ2Y2IyMjg1/6b7a8e0051698e4ecafda95322eeda9a/croptype-raw_20181201_20191130.tif?expires=1729535690 to /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/croptype-raw_20181201_20191130.tif\n",
- "INFO:openeo.rest.job:Downloading Job result asset 'croptype_20181201_20191130.tif' from https://openeo.creo.vito.be/openeo/jobs/j-2410145b1b3c43b8851ed611261b9ecb/results/assets/ZGNjYWI2ZDktODQ2Yy00OGE5LTlkOTQtNDk3MTQ2Y2IyMjg1/2662e69753718ad3f2abade4416eb16e/croptype_20181201_20191130.tif?expires=1729535690 to /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/croptype_20181201_20191130.tif\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
- "from worldcereal.job import WorldCerealProductType, generate_map, CropTypeParameters\n",
+ "from worldcereal.job import PostprocessParameters, WorldCerealProductType, generate_map, CropTypeParameters\n",
"\n",
"# Initializes default parameters\n",
"parameters = CropTypeParameters()\n",
"\n",
"# Change the URL to your custom classification model\n",
"parameters.classifier_parameters.classifier_url = model_url\n",
- "parameters.save_mask = save_mask\n",
+ "parameters.save_mask = True\n",
"\n",
"# Get processing period and area\n",
"processing_period = slider.get_processing_period()\n",
@@ -622,7 +321,7 @@
" output_dir=output_dir,\n",
" product_type=WorldCerealProductType.CROPTYPE,\n",
" croptype_parameters=parameters,\n",
- " postprocess_parameters=postprocess_parameters,\n",
+ " postprocess_parameters=PostprocessParameters,\n",
")"
]
},
@@ -630,36 +329,23 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The classification results will be automatically downloaded to your output_dir in .tif format.\n",
- "By default, OpenEO stores the class labels, confidence score and class probabilities in one file.\n",
+ "The classification results will be automatically downloaded to your *output_dir* in .tif format.
\n",
+ "You will get two outputs, one containing the cropland mask and one containing the crop type results.
\n",
"\n",
- "Using the function below, we split this information into separate .tif files, thereby adding metadata and a color map, to ease interpretation and visualization:\n",
- "- \"xxx_classification_start-date_end-date.tif\" --> contains the classification labels. A class look-up table is included in the .tif metadata.\n",
- "- \"xxx_confidence_start-date_end-date.tif\" --> contains the probability associated to the prediction [0 - 100]\n",
+ "The result will be a raster file containing two bands:\n",
+ "1. The label of the winning class\n",
+ "2. The probability of the winning class [0 - 100]\n",
"\n",
- "In case you chose to store the original per-class probabilities, these are NOT written to a separate file and need to be consulted in the original result downloaded from OpenEO."
+ "Using the function below, we split this information into separate .tif files, thereby adding metadata and a color map, to ease interpretation and visualization:\n",
+ "- \"croptype_classification_start-date_end-date.tif\" --> contains the classification labels. A class look-up table is included in the .tif metadata.\n",
+ "- \"croptype_confidence_start-date_end-date.tif\" --> contains the probability associated to the prediction [0 - 100]"
]
},
{
"cell_type": "code",
- "execution_count": 18,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 20:35:48.639\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mutils\u001b[0m:\u001b[36m_get_colormap\u001b[0m:\u001b[36m540\u001b[0m - \u001b[1mAssigning random color map for product croptype. \u001b[0m\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "{'cropland-raw': {'classification': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/cropland-raw_classification_20181201_20191130.tif'), 'confidence': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/cropland-raw_confidence_20181201_20191130.tif')}, 'cropland': {'classification': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/cropland_classification_20181201_20191130.tif'), 'confidence': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/cropland_confidence_20181201_20191130.tif')}, 'croptype-raw': {'classification': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/croptype-raw_classification_20181201_20191130.tif'), 'confidence': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/croptype-raw_confidence_20181201_20191130.tif')}, 'croptype': {'classification': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/croptype_classification_20181201_20191130.tif'), 'confidence': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPTYPE_germany/croptype_confidence_20181201_20191130.tif')}}\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"from utils import prepare_visualization\n",
"\n",
@@ -671,63 +357,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The resulting raster files can be visualized in QGIS, or using the function in the cell below..."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 25,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "1382fa85ebf645e8809a579f3c5a1265",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "Map(center=[53.1321915, 10.379311000000001], controls=(ZoomControl(options=['position', 'zoom_in_text', 'zoom_…"
- ]
- },
- "execution_count": 25,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from utils import visualize_products\n",
- "\n",
- "visualize_products(rasters, port=8887)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Finally, use the cell below to visualize the look-up table for the classification product."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 24,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAOIAAAB8CAYAAAB0fGzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAYyklEQVR4nO3de1xN+f748ddulHZlVFRDKFSUhNCFoR2ZxrjlYFwyU8glzNEckngw7uMybo+f66AcdzM4x+Bg6Ci3cisdUiQ1JxWjg+MxJLTX7w/f1mmrdmXQbvbn+Xjsx8Nen89a67PWw3t9Puuz13qnkCRJQhCEamVQ3Q0QBEEEoiDoBBGIgqADRCAKgg4QgSgIOkAEoiDoABGIgqADRCAKgg6opa3w8D+OIqlfvq+2vHUKg1r0+uzT6m6GIFRIayBK6pcEfLX/fbXlrfv7//tTdTdBECpFDE3fsi1btmBmZlbdzRBqGBGIb9ngwYO5fft2dTdDqGG0Dk2FqlMqlSiVyupuhlDD6HWPqFKpCA0NZfLkyVhaWmJlZcWqVasoLCxkwoQJmJub06RJE7Zt2yavM23aNFq0aIFSqcTe3p6pU6fy7Nkzufz1oalCoSjzUywnJ4chQ4ZgYWGBhYUFvXr1Ij09/f2cAEFn6HUgAuzYsYM6depw/vx5pk2bRlhYGAEBATg5OXHp0iWCgoIICQkhNzcXAFNTU6KiokhNTWXt2rXs3r2bBQsWlLv9vLw8+ZOdnU379u3p2rUrAE+fPsXX1xdjY2Pi4uKIj4+nQYMG+Pn58fTp0/dy/IJu0PtAbNWqFbNnz8bR0ZG//OUv1K9fH0NDQyZNmoSDgwOzZs1CkiTOnTsHwMyZM+ncuTP29vZ89tlnTJ8+nV27dpW7/Y8++kj+LFy4kEePHrF//6uZ6N27dyNJEtHR0bi5udGyZUs2bNjAb7/9xqFDh97L8Qu6Qe/vEd3c3OR/KxQKrK2tad26tbzM0NAQCwsLfv31VwD27t3LypUruXXrFr/99htFRUUUFRVVuJ81a9awc+dO4uPjqVevHgCXL18mMzOTOnXqaNR9+vQpGRkZb+PwhBpC7wPR0NBQ47tCoShzmVqtJiEhgSFDhvDNN9+wYsUKzM3N+emnn5gyZYrWfcTExDB58mQOHDiAs7OzvFytVtO2bVt2795dah1LS8vfcVRCTaP3gVgVZ8+exdbWlpkzZ8rLfvnlF63rpKenM2jQIJYuXYq/v79Gmbu7O7t27aJ+/fqYm5u/iyYLNYTe3yNWhZOTEzk5OezYsYPbt2+zbt06rfeHBQUF9O3bFz8/PwYNGsTdu3flD0BgYCA2Njb069ePuLg4MjMzOXXqFJMnTxYzp3pGBGIV9OnTh/DwcMLCwnBzc+P48ePMnTu33Pr37t0jLS2NH3/8kQYNGmh8AExMTDh16hTNmjVj0KBBtGzZkqCgIB4+fIiFhcX7OixBByi0ZXE7dOhQjX/WtHfv3tXdDEGokOgRBUEHiEAUBB0gAlEQdIAIREHQAVp/R1QY1KrRL9cqDMTPpELNoHXWVBCE90MMTQVBB4hAFAQdoPUm6uiJE7ws8dJrTVPL2JhP/fyquxmCUCGtgfjy2TO2tnTTVkWnfZn2r+pugiBUihiavgGVSsXEiROruxnCH4gIRC1iY2NRKBTk5+dXd1OEPzgRiDrkxYsX1d0EoZrofSAWFhYSFhaGjY0NxsbGeHl5cebMGbKysvD19QXAysoKhUJBcHCwvJ5arWb69OnUr18fa2trpkyZglqtlsufP39OREQEjRo1wtTUlI4dO3Ls2DG5vLi3/cc//oGHhwdGRkYa5YJ+0ftAnDp1Knv27CEqKoqkpCRat27Np59+iqGhIfv27QMgJSWFvLw8Vq1aJa+3Y8cOatWqxblz51i9ejUrV65kz549cvmIESOIi4tj586dXL16laCgIPr06UNycrLG/iMiIpg/fz5paWl4enq+n4MWdE6F7yPW9FlTbe8jPnnyBAsLCzZt2sSXX34JQFFREU5OTgwdOhQ/Pz98fX25f/8+9evXl9dTqVQUFhYSHx8vL+vRowd2dnZs2rSJjIwMHB0dycrKokmTJnKdgIAAGjZsyNq1a4mNjcXX15e9e/cyYMCAd3D0Qk2i1w9jZmRk8OLFCzp37iwv++CDD/D29ub69ev4afkNsmT2N4CGDRvKmd4SExORJAkXFxeNOoWFhXTr1k1jWYcOHX7vYQh/AHodiMWDgZKZt4uVtayk8jK9wav7R4VCwcWLF0vVez0dv6mpaZXbLfzx6HUgOjg4YGRkxJkzZ2jWrBnwamgaHx/PsGHDMDIykpdVRbt27ZAkibt378oTPoKgjV4HoqmpKaGhoUybNo369evTtGlTVqxYwb179xg/frzcsx0+fJg+ffqgVCor9SfXnJycCAwMJDg4mGXLluHu7s6DBw+IjY2lWbNm/OlPNffVMuHd0OtABFi8eDHwapbz0aNHtGvXjqNHj8qZ1ubMmcOMGTMICQnhyy+/ZMuWLZXabnR0NAsWLGDq1KncuXMHS0tLPDw8RA8plEmvZ00FQVfo/e+IgqALRCAKgg4QgSgIOkAEoiDoAK2zprWMjWv0y7W1jI2ruwmCUCkii5sg6AAxNBUEHSACURB0gNZ7xGOHj/FCqrlvjRsqDPHv5V9xRUGoZloD8YX0gmtfpL2vtrx1rttaVncTBKFSxNC0hisrwdWBAwdwdHSkVq1aBAcHv7UkWL1799ZIF/K2bNmypVIP0/+RiUCs4Tp16kReXh716tWTl4WEhDBgwAB++eUXVq1aVWYdfaTLWfn0/u2Lms7IyIiPPvpI/v7o0SPy8/Px9/fH1tZWXl6yjqB79LpHLCtRcHBwsPzGhkqlYvz48Vqzte3fvx83NzeUSiWWlpb4+Phw7949AGbPno2rqyubNm2iSZMmKJVKAgICSl2Ro6OjcXFxwdjYGCcnJ1asWKGxj8ePHxMaGkqDBg0wNjbG2dlZTlRV8iofGxuLhYUFAN26dUOhUBAbG1tmT3Du3Dl8fHwwMTHB1taW0NBQHj9+LJc/ffqU4OBgzMzMsLGxYeHChZU+r+vWrcPZ2Vn+fvz4cRQKhfzKGUBgYCCjR4/WWC8mJgZXV1dMTU3x9fUlMzNTo/zgwYO0b98eY2NjmjZtyowZM3j+/Llcvn37djp27EidOnWwtrZm0KBB5OTkAFSYla+66XUgVoa2bG13795lyJAhBAUFkZqayqlTp/jiiy801s/KymL79u0cOHCAEydOkJ6ezsiRI+XyjRs3Mn36dObOnUtqairLli1j8eLFrF27FniVzqNnz57ExcURHR3N9evXWb58uZw9oKROnTqRkpICwL59+8jLy6NTp06l6l29epVPPvmEvn37kpyczP79+7ly5YpGu6ZMmcLx48fZt28fMTExJCUlcerUqUqdM5VKRVpaGnl5ecCri0X9+vU5efKkXCcuLg6VSiV/Lyws5NtvvyUqKor4+HgePXrEuHHj5PJjx44RGBjIxIkTSUlJISoqir179zJ9+nS5zvPnz5kzZw7JyckcOnSI/Px8hg4dCkDjxo21ZuWrbmJoWgEXFxfmzp0LvHrzfuPGjcTExDB06FByc3N58eIFAwcOxM7ODgBXV1eN9QsKCti6dauczW3Dhg106dKF9PR0HB0dmTdvHkuWLGHgwIEANG3alGnTprF27VomTpzIiRMniI+PJyUlRe5litN6vM7IyAhra2sALC0tyx2OLl26lMGDBzN58mR52bp162jXrh2//vorJiYmbN68maioKPz9X/38Ex0dTaNGjSp1zpydnbGxsSE2NpahQ4cSGxvLlClTmDdvHi9fviQzM5OcnByNQHz58iVr1qyhRYsWwKsLwYgRI1Cr1RgYGLBgwQLCw8MZMWIEAM2bN2fx4sUMHz6cpUuXolAoNC4kzZo1k3vmO3fu0KhRIywtLQGwtrbWyMqnC0QgVkBbtrY2bdrg5+eHq6srn3zyCX5+fgwcOBArKyu5vq2trUZKRU9PTwwMDEhNTcXc3Jzs7GzGjh1LaGioXOfly5dyYqukpCQaNGigMdT7vS5fvsytW7c08rAW7y8jIwMTExOeP3+Ot7e3XG5mZkbr1q0rvQ8fHx9iY2Pp168fly5dYv/+/axbt46LFy9y7do1HBwcNO5ha9euLQchvDrPL1684NGjR1haWnL58mUuXLigMbxVq9UUFBRw9+5dGjRoQGJiInPmzOHKlSs8ePBAPqZ///vflb6IVBe9DkQDAwNef9T29bT32rK1ffDBB/z8888kJCTw888/s3nzZiIjI4mLi6NNmzYV7r94O+vXry9zCAmUat/boFarCQkJ4euvvy5VZmtry40bN373PlQqFStWrODs2bM4ODhgY2ODj48PJ0+eJCUlRaM3BKhVS/O/YnEWvZKZ8b755hsGDRpUal9WVlY8efIEf39//Pz82LZtG9bW1uTn59OlSxeN+0hdpdeBaGVlJd/HFEtOTsbe3r7S21AoFHh7e+Pt7c2sWbNo1aoVe/bskQMxJyeH7OxsGjduDMCFCxdQq9Xy8M3W1paMjAw5wfHr3N3dycvLIzU19a31iu7u7qSkpODg4FBmuYODA4aGhiQkJMjD4CdPnnDt2jWaN29eqX0UT3Tt2LFDDjqVSsXOnTtJTU3V6Nkq2+a0tLRy25ycnEx+fj4LFy6kadOmwKuJtJLeNCvf+6DXgditWzfCwsL46aefaNGiBRs2bCA7O7vSgZiQkMCJEyfw9/fHxsaGpKQksrOzNRILK5VKgoKCWL58OQUFBYwbN45evXrh6OgIvJpZ/eqrrzA3N+ezzz7jxYsXJCYmkpOTQ2RkJN27d8fT05MBAwawYsUKnJycuHXrFk+ePCEgIOCNjjsiIgIvLy/GjRvH2LFjqVOnDmlpaRw8eJANGzZgZmbGqFGjiIiIwMrKioYNGzJ37twq/QcuvtBs376d3bt3A+Dr68vo0aMpKioq1SNWZNasWfTu3Rs7Ozs+//xzatWqxbVr17hw4QJLliyhSZMm1K5dm9WrVzNhwgRSU1OZOXOmxjbs7OzeKCvf+6DXs6YjR46UP507d8bMzIz+/ftXev26dety9uxZevfujaOjI5MnT2bmzJkMHz5crmNvb8+QIUPo06cP3bp1o1mzZkRHR8vlISEhREVFsW3bNtq0aUOXLl34/vvv5au6gYEBR44coXPnzgwfPhxnZ2cmTZr0u4Zbbm5unDp1iqysLHx8fGjTpg2RkZHY2NjIdb777jt8fX3p378/vr6+uLq60rVr1yrtR6VSoVar8fHxkc9Fo0aNSt0fVoa/vz+HDx/m5MmTeHh44OHhwaJFi+T7bysrK/7617/y97//HRcXF+bMmcPy5cs1tmFraytn5bOxsdGpv3FZYRa3mv6saXVmcZs9ezZ79+7l2rVr1dYGoWbQ6x5REHSFCEShyk6fPo2ZmVm5H6HqxNBUqLKCggL50bGylDezKZRPr2dNhTejVCpFsL1lWgPRUGFYo1+uNVQYVlxJEHSAyOImCDpATNYIgg4QgSgIOkDrPeLx48cpLCx8X21562rXrk2PHj2quxmCUCGtgVhYWEjt2rXfV1veupp8ERH0ixia/gGVlQLkXdi7d6/8upLw+4hAFAQdIAJRR9SEl1eFd0evA7GiLG0PHz4kKCgICwsLlEolfn5+cnKmykhISKBbt26YmppSt25dunfvTm5urrzv0NBQpkyZgpWVFZ07dwbg1KlTeHp6YmxsjI2NDV9//bVGkKpUKsaNG8ekSZOwsLDAwsKC8PBwjaxvr9OW3Qz+lwkuJiYGT09PTExM6NChA4mJiRrb2bp1K3Z2dpiYmNC7d285W53w++l1IIL2LG3BwcGcP3+eAwcOcOHCBUxMTPj0008pKCiocLvJycn4+vri4ODA2bNnSUhI4PPPP+fly5dyne3btyNJEqdPn2br1q3k5OTQs2dP2rVrR1JSEps3b2bXrl1ERkaWarNarSY+Pp4NGzbw/fffs3LlynLboi27WUmRkZEsWrSIxMRE6tWrR2BgoJyq4/z58wQHBzNmzBiuXLlCnz59mDVrVmVOsVAJFT70XdNnTbU99K1SqSgsLCQ+Pl5e1qNHD+zs7IiIiMDJyYm4uDj5hdj//ve/NGnShGXLlhESEqJ134GBgWRkZJCQkFDuvh88eMC//vW/PwQ7Y8YM9uzZw82bNzEweHWN3LJlC2PHjuXhw4eYmJigUqnIzc3lxo0b8kTJ/PnzWb9+PXfu3JG37erqyurVq8vcd1paGs7OzmRnZ9OoUSNiY2Px9fXl6NGjcta2s2fP8vHHH8t1hg0bxv379zl+/Li8nZCQEDZv3vxO8uroG73vEcvL0paamoqBgYFGJrO6devSunVrrl+/XuF2k5KS6N69u9Y67du31/iempqKt7e3HIQAH3/8Mc+fP+fWrVvyMi8vL43ZSm9vb3JycjQSBJeUmJhIv379sLOzo06dOnTo0AF4ld2spJLnomHDhgByxrritpX0+nfhzel9IJaXpU3bVb4yU/aV6SVMTU1LrVPett/0Z4Li7GYmJiZs27aNixcvcvToUaD0BFHJc/F6FjXR671beh+I5XFxcZHvw4o9fvyYq1evaiSHKo+7uzv//Oc/q7zP+Ph4jYmXM2fOYGRkpJE97fz58xqBkZCQQMOGDfnwww9LbTMtLU3Obta1a1datmwp93JVbdvrw+zyht1C1YlALIejoyP9+vVj7NixnD59mqtXrzJ8+HA+/PBDhg0bVuH64eHhJCUlMWbMGJKTk7lx4wabNm0qNRwsafz48eTm5jJ+/HhSU1M5fPgw06ZNY+LEiZiYmMj1cnNzCQsL48aNG+zdu5elS5eWmaMU0Mhudvv2bQ4fPlwqu1ll/PnPf+bEiRN8++23pKens3HjRv72t79VeTtC2UQgahEdHY2Hhwd9+/bFw8ODp0+fcvToUZRKZYXrtm3blhMnTpCWloaXlxeenp7s3r271FC4JFtbW44cOUJSUhJt27Zl5MiRDB06tNQfgAkMDKSoqAhPT09Gjx7NqFGjyg3EymQ3qwwvLy82b97MunXrcHNzY//+/cyePbvK2xHKptezpjVRRTOiQs0kekRB0AEiEN9Qz549y81iVpW/JSgIIJJHvbFNmzaV+4RN8Z//ehdiY2Pf2baF6iMC8Q1VNWW8IGijNRBr165do1+urckTTYJ+EVncBEEHiMkaQdABIhAFQQdovUeMiYmp1Lt3ukqpVFb4BoQg6AKtgVhQUFCjn0w5dOhQdTdBECpFDE3fo0uXLqFQKMjKyqrupgg6Rq8DMTg4GIVCwfz58zWWF+dwyc/Pr6aW/c/7So0oVC+9DkQAY2NjlixZwv3796u7KYIe0/tA9PX1xd7ennnz5mmtV1F2tbIcPXqUli1bYmxsTJcuXbh586ZG+X/+8x+GDh1Ko0aNUCqVtGrViujoaLk8ODiYuLg41qxZg0KhkIe1RUVFjBo1iqZNm6JUKnF0dGTJkiVaM7kJuk3vA9HAwIBFixaxfv16MjIyyqxT2exqJWVnZxMQEECPHj24cuUKX331FVOnTtWo8+zZM9zd3Tl06BApKSlMmjSJsWPHEhMTA8CqVavw9vZmxIgR5OXlkZeXR+PGjVGr1dja2vLDDz+QmprKggULWLhwoUYQCzWMpMXBgwe1Feu8itofFBQk9erVS5IkSVKpVNLgwYMlSZKkkydPSoB0//59SZIkafr06VLz5s2loqIied3o6GjJyMhIevLkSZnbjoyMlBwdHSW1Wi0vmzdvngRImZmZ5bZp8ODB0qhRo+TvPj4+0oQJE7QfqCRJERERUvfu3SusJ+gmve8Riy1ZsoQff/yRS5culSqrbHa119cpK9taSUVFRSxYsAA3Nzfq1auHmZkZ+/fv15pOo9j69evp0KEDVlZWmJmZsWLFikqtJ+gmEYj/p2PHjgwYMICIiIhSZdIbZFeTKvEI73fffceyZcsIDw8nJiaGK1euEBAQUOG95549ewgLCyM4OJhjx45x5coVxo8fL9L212DiNagSFi5ciIuLi5xusJiLiws//PADarVa7hXLyq72+jr79u3TCOLXs56dOXOGPn368MUXXwCvgvfmzZuYm5vLdYyMjCgqKiq1nqenp8bPGuXd3wo1g+gRS3BwcGDMmDGsWrVKY3lls6uVNG7cOLKysjSyra1fv16jjpOTEzExMZw5c4a0tDQmTpxIZmamRh17e3suXLhAVlYW+fn5qNVqnJycSExM5MiRI6SnpzNv3jzi4uLe7skQ3i9tN5D6NFlT7N69e5KZmZnGZI0kSVJcXJzk4eEhGRkZSdbW1lJYWJj07Nkzrds/dOiQ5OTkJNWuXVvq1KmTtH37do3JmgcPHkj9+/eXzMzMJCsrKyk8PFwKDQ2VfHx85G3cuHFD8vLykpRKpbxuYWGhNHLkSMnc3FyqW7euNHLkSGnOnDmSnZ1dlc6PoDsqzOJW0581rcntF/SHGJoKgg4QgSgIOkAEoiDoABGIgqADtP6OqFQqa/TLtZX5GxWCoAtEFjdB0AFiaCoIOkAEoiDoABGIgqADRCAKgg4QgSgIOkAEoiDoABGIgqAD/j+o569B3cXuaAAAAABJRU5ErkJggg==",
- "text/plain": [
- "
"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": [
- "from utils import show_color_legend\n",
- "\n",
- "show_color_legend(rasters, \"croptype\")"
+ "The resulting raster files can be visualized in QGIS."
]
}
],
diff --git a/notebooks/worldcereal_v1_demo_custom_croptype_extended.ipynb b/notebooks/worldcereal_v1_demo_custom_croptype_extended.ipynb
new file mode 100644
index 00000000..1fff3dcf
--- /dev/null
+++ b/notebooks/worldcereal_v1_demo_custom_croptype_extended.ipynb
@@ -0,0 +1,440 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "![](./resources/System_v1_custom_croptype.png)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Introduction\n",
+ "\n",
+ "This notebook guides you through the process of training a custom crop type classification model using publicly available and harmonized in-situ reference data for your area and crop types of interest. Afterwards, the model can be applied to your season of interest to generate a crop type map.\n",
+ "\n",
+ "Please note that for the purpose of this demo, the processing area is limited to 250 km² per model run. On average, one such run consumes xxx credits on the Copernicus Data Space Ecosystem."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Content\n",
+ " \n",
+ "- [Before you start](###-Before-you-start)\n",
+ "- [1. Define your region of interest](#1.-Define-your-region-of-interest)\n",
+ "- [2. Extract public reference data](#2.-Extract-public-reference-data)\n",
+ "- [3. Select your desired crop types](#3.-Select-your-desired-crop-types)\n",
+ "- [4. Prepare training features](#4.-Prepare-training-features)\n",
+ "- [5. Train custom classification model](#5.-Train-custom-classification-model)\n",
+ "- [6. Deploy your custom model](#6.-Deploy-your-custom-model)\n",
+ "- [7. Generate a map](#7.-Generate-a-map)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Before you start\n",
+ "\n",
+ "In order to run WorldCereal crop mapping jobs from this notebook, you need to create an account on the Copernicus Data Space Ecosystem (CDSE) registering [here](https://dataspace.copernicus.eu/). This is free of charge and will grant you a number of free openEO processing credits to continue this demo."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 1. Define your region of interest\n",
+ "\n",
+ "When running the code snippet below, an interactive map will be visualized.\n",
+ "Click the Rectangle button on the left hand side of the map to start drawing your region of interest.\n",
+ "\n",
+ "Currently, there is a maximum size of 250 km² for your area within this demo. Upon exceeding this limit, an error will be shown.\n",
+ "You can bypass this limit by altering the code below to: \n",
+ "*map = ui_map(area_limit=750)* \n",
+ "\n",
+ "Processing areas beyond 750 km² are currently not supported to avoid excessive credit usage (roughly 120 credits will be consumed for this size of a processing extent).\n",
+ "\n",
+ "The widget will automatically store the coordinates of the last rectangle you drew on the map."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.utils.map import ui_map\n",
+ "\n",
+ "map = ui_map()\n",
+ "map.show_map()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 2. Extract public reference data\n",
+ "\n",
+ "Here we query existing reference data that have already been processed by WorldCereal and are ready to use.\n",
+ "To increase the number of hits, we expand the search area by 250 km in all directions.\n",
+ "\n",
+ "We print the number of training samples retrieved per year."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.utils.refdata import query_public_extractions\n",
+ "\n",
+ "# retrieve the polygon you just drew\n",
+ "polygon = map.get_polygon_latlon()\n",
+ "\n",
+ "# Query our public database of training data\n",
+ "public_df = query_public_extractions(polygon)\n",
+ "public_df.year.value_counts()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 3. Select your desired crop types\n",
+ "\n",
+ "Run the next cell and select all crop types you wish to include in your model. All the crops that are not selected will be grouped under the \"other\" category."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import pick_croptypes\n",
+ "from IPython.display import display\n",
+ "\n",
+ "checkbox, checkbox_widgets = pick_croptypes(public_df, samples_threshold=100)\n",
+ "display(checkbox)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Based on your selection, a custom target label is now generated for each sample. Verify that only crops of your choice are appearing in the `downstream_class`, all others will fall under `other`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import get_custom_croptype_labels\n",
+ "\n",
+ "public_df = get_custom_croptype_labels(public_df, checkbox_widgets)\n",
+ "public_df[\"downstream_class\"].value_counts()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 4. Prepare training features\n",
+ "\n",
+ "Using a deep learning framework (Presto), we derive classification features for each sample. The resulting `encodings` and `targets` will be used for model training."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import prepare_training_dataframe\n",
+ "\n",
+ "training_dataframe = prepare_training_dataframe(public_df, task_type=\"croptype\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 5. Train custom classification model\n",
+ "We train a catboost model for the selected crop types. Class weights are automatically determined to balance the individual classes."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import train_classifier\n",
+ "\n",
+ "custom_model, report, confusion_matrix = train_classifier(training_dataframe)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Before training, the available training data has been automatically split into a calibration and validation part. By executing the next cell, you get an idea of how well the model performs on the independent validation set."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Print the classification report\n",
+ "print(report)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 6. Deploy your custom model\n",
+ "\n",
+ "Once trained, we have to upload our model to the cloud so it can be used by OpenEO for inference. Note that these models are only kept in cloud storage for a limited amount of time.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.utils.upload import deploy_model\n",
+ "from openeo_gfmap.backend import cdse_connection\n",
+ "from utils import get_input\n",
+ "\n",
+ "modelname = get_input(\"model\")\n",
+ "model_url = deploy_model(cdse_connection(), custom_model, pattern=modelname)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 7. Generate a map\n",
+ "\n",
+ "Using our custom model, we generate a map for our region and season of interest.\n",
+ "To determine your season of interest, you can consult the WorldCereal crop calendars (by executing the next cell), or check out the [USDA crop calendars](https://ipad.fas.usda.gov/ogamaps/cropcalendar.aspx)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import retrieve_worldcereal_seasons\n",
+ "\n",
+ "spatial_extent = map.get_processing_extent()\n",
+ "seasons = retrieve_worldcereal_seasons(spatial_extent)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now use the slider to select your processing period. Note that the length of the period is always fixed to a year.\n",
+ "Just make sure your season of interest is fully captured within the period you select."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import date_slider\n",
+ "\n",
+ "slider = date_slider()\n",
+ "slider.show_slider()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Set some other customization options:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.job import PostprocessParameters\n",
+ "import os\n",
+ "from pathlib import Path\n",
+ "\n",
+ "# Choose whether you want to store the cropland mask as separate output file\n",
+ "save_mask = True\n",
+ "\n",
+ "# Choose whether or not you want to spatially clean the classification results\n",
+ "postprocess_result = True\n",
+ "# Choose the postprocessing method you want to use [\"smooth_probabilities\", \"majority_vote\"]\n",
+ "# (\"smooth_probabilities will do limited spatial cleaning,\n",
+ "# while \"majority_vote\" will do more aggressive spatial cleaning, depending on the value of kernel_size)\n",
+ "postprocess_method = \"majority_vote\"\n",
+ "# Additional parameter for the majority vote method \n",
+ "# (the higher the value, the more aggressive the spatial cleaning,\n",
+ "# should be an odd number, not larger than 25, default = 5)\n",
+ "kernel_size = 5\n",
+ "# Do you want to save the intermediate results (before applying the postprocessing)\n",
+ "save_intermediate = True\n",
+ "# Do you want to save all class probabilities in the final product? (default is False)\n",
+ "keep_class_probs = True\n",
+ "\n",
+ "postprocess_parameters = PostprocessParameters(enable=postprocess_result,\n",
+ " method=postprocess_method,\n",
+ " kernel_size=kernel_size,\n",
+ " save_intermediate=save_intermediate,\n",
+ " keep_class_probs=keep_class_probs)\n",
+ "\n",
+ "# Specify the local directory where the resulting maps should be downloaded to.\n",
+ "run = get_input(\"model run\")\n",
+ "output_dir = Path(os.getcwd()) / f'CROPTYPE_{modelname}_{run}'\n",
+ "print(f\"Output directory: {output_dir}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We now have all information we need to generate our map! \n",
+ "The next cell will submit a map inference job on CDSE through OpenEO. \n",
+ "The first time you run this, you will be asked to authenticate with your CDSE account by clicking the link provided below the cell. \n",
+ "Then sit back and wait untill your map is ready..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.job import WorldCerealProductType, generate_map, CropTypeParameters\n",
+ "\n",
+ "# Initializes default parameters\n",
+ "parameters = CropTypeParameters()\n",
+ "\n",
+ "# Change the URL to your custom classification model\n",
+ "parameters.classifier_parameters.classifier_url = model_url\n",
+ "parameters.save_mask = save_mask\n",
+ "\n",
+ "# Get processing period and area\n",
+ "processing_period = slider.get_processing_period()\n",
+ "processing_extent = map.get_processing_extent()\n",
+ "\n",
+ "# Launch the job\n",
+ "job_results = generate_map(\n",
+ " processing_extent,\n",
+ " processing_period,\n",
+ " output_dir=output_dir,\n",
+ " product_type=WorldCerealProductType.CROPTYPE,\n",
+ " croptype_parameters=parameters,\n",
+ " postprocess_parameters=postprocess_parameters,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The classification results will be automatically downloaded to your *output_dir* in .tif format.\n",
+ "\n",
+ "For a model with two classes, you get a raster file containing up to four bands:\n",
+ "1. The label of the winning class\n",
+ "2. The probability of the winning class [0 - 100]\n",
+ "3. and beyond (optional, depending on settings): Class probabilities of each class, ordered according to the look-up table. The look-up table for each product can be consulted in the 'results' object as produced by the 'generate_map' function.\n",
+ "\n",
+ "Using the function below, we split this information into separate .tif files, thereby adding metadata and a color map, to ease interpretation and visualization:\n",
+ "- \"croptype_classification_start-date_end-date.tif\" --> contains the classification labels. A class look-up table is included in the .tif metadata.\n",
+ "- \"croptype_confidence_start-date_end-date.tif\" --> contains the probability associated to the prediction [0 - 100]\n",
+ "\n",
+ "In case you chose to store the original per-class probabilities, these are NOT written to a separate file and need to be consulted in the original result downloaded from OpenEO.\n",
+ "\n",
+ "Note that in case you chose to apply post-processing AND save intermediate results, you will also get a \"croptype-raw_xxx.tif\" output, which holds the classification labels and probabilities BEFORE post-processing.\n",
+ "\n",
+ "Also note that if you chose to save the cropland mask as a separate output, you will also get a cropland (and potentially cropland-raw) product."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import prepare_visualization\n",
+ "\n",
+ "rasters = prepare_visualization(job_results)\n",
+ "print(rasters)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The resulting raster files can be visualized in QGIS.\n",
+ "\n",
+ "In case you are running this script on your local environment, you can alternatively use the following cells to visualize the outputs directly in this notebook."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import visualize_products\n",
+ "\n",
+ "visualize_products(rasters, port=8887)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import show_color_legend\n",
+ "\n",
+ "show_color_legend(rasters, \"croptype\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "worldcereal",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/notebooks/worldcereal_v1_demo_default_cropland.ipynb b/notebooks/worldcereal_v1_demo_default_cropland.ipynb
new file mode 100644
index 00000000..259b9ff0
--- /dev/null
+++ b/notebooks/worldcereal_v1_demo_default_cropland.ipynb
@@ -0,0 +1,267 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "![](./resources/System_v1_cropland.png)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Introduction\n",
+ "\n",
+ "This notebook contains a short demo on how to use the WorldCereal system to generate a cropland extent map for your area and season of interest. \n",
+ "The map is generated using a default model trained by the WorldCereal consortium to distinguish cropland from all other land use.\n",
+ "\n",
+ "Please note that for the purpose of this demo, the processing area is currently limited to 250 km² per model run. On average, one such run consumes 35 credits on the Copernicus Data Space Ecosystem.\n",
+ "\n",
+ "\n",
+ "\n",
+ "Cropland definition: \n",
+ "Cropland is defined here as land used for temporary crops, i.e. crops with a less-than-1-year growing cycle which must be newly sown or planted for further production after the harvest. Sugar cane, asparagus, and cassava are also considered temporary crops, even though they remain in the field for more than 1 year. This cropland definition thus excludes perennial crops as well as (temporary) pastures.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Content\n",
+ " \n",
+ "- [Before you start](###-Before-you-start)\n",
+ "- [1. Define your region of interest](#1.-Define-your-region-of-interest)\n",
+ "- [2. Define your year of interest](#2.-Define-your-year-of-interest)\n",
+ "- [3. Set some other options](#3.-Set-some-other-options)\n",
+ "- [4. Generate your map](#4.-Generate-your-map)\n",
+ "- [5. Final notes](#5.-Final-notes)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Before you start\n",
+ "\n",
+ "In order to run WorldCereal crop mapping jobs from this notebook, you need to create an account on the Copernicus Data Space Ecosystem,\n",
+ "by completing the form [here](https://dataspace.copernicus.eu/).\n",
+ "This is free of charge and will grant you a number of free openEO processing credits to continue this demo."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 1. Define your region of interest\n",
+ "\n",
+ "When running the code snippet below, an interactive map will be visualized.\n",
+ "Click the Rectangle button on the left hand side of the map to start drawing your region of interest.\n",
+ "\n",
+ "Currently, there is a maximum size of 250 km² for your area within this demo. Upon exceeding this limit, an error will be shown.\n",
+ "You can bypass this limit by altering the code below to: \n",
+ "*map = ui_map(area_limit=750)* \n",
+ "\n",
+ "Processing areas beyond 750 km² are currently not supported to avoid excessive credit usage (roughly 120 credits will be consumed for this size of a processing extent).\n",
+ "\n",
+ "The widget will automatically store the coordinates of the last rectangle you drew on the map."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.utils.map import ui_map\n",
+ "\n",
+ "map = ui_map()\n",
+ "map.show_map()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 2. Define your year of interest\n",
+ "\n",
+ "The default WorldCereal cropland model always uses a time series of exactly one year as input for the model.\n",
+ "\n",
+ "However, instead of just using a calendar year (January 1st - December 31st), we recommend to define the exact start and end date of your time series, or processing period, based on the timing of the local growing seasons.\n",
+ "\n",
+ "Take the following example for Western Europe, where we typically have a winter season (s1) and summer season (s2):\n",
+ "\n",
+ "\n",
+ " \n",
+ "
\n",
+ "\n",
+ "\n",
+ "The best timing to start and end the time series in this case would be October (green vertical line), as for both seasons this would result in nicely capturing the growing season within the time series. It would not make sense in this case to define the year from June to June (red vertical line), as you will miss the start of the summer season and the end of the winter season in your time series.\n",
+ "\n",
+ "So if you would like to map temporary crops in Western Europe for the year 2021, we would recommend to define your processing period as October 1st 2020 - September 30th 2021.\n",
+ "\n",
+ "In case you do not know the typical seasonality of crops in your area of interest, you can consult the WorldCereal crop calendars using the function below.\n",
+ "\n",
+ "Note that in case your area of interest is located in an extremely heterogeneous part of the world, the WorldCereal seasons cannot be retrieved at the moment. As a fall-back, please consult the [USDA crop calendars](https://ipad.fas.usda.gov/ogamaps/cropcalendar.aspx)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import retrieve_worldcereal_seasons\n",
+ "\n",
+ "spatial_extent = map.get_processing_extent()\n",
+ "seasons = retrieve_worldcereal_seasons(spatial_extent)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Execute the next cell to select your processing period:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import date_slider\n",
+ "\n",
+ "slider = date_slider()\n",
+ "slider.show_slider()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 3. Set some other options"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "from pathlib import Path\n",
+ "from utils import get_input\n",
+ "\n",
+ "# Specify the local directory where the resulting maps should be downloaded to.\n",
+ "run = get_input('model run')\n",
+ "output_dir = Path(os.getcwd()) / f'CROPLAND_default_{run}'\n",
+ "print(f\"Output directory: {output_dir}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 4. Generate your map\n",
+ "\n",
+ "We now have all information we need to generate our map! \n",
+ "The next cell will submit a map inference job on CDSE through OpenEO. \n",
+ "The first time you run this, you will be asked to authenticate with your CDSE account by clicking the link provided below the cell. \n",
+ "Then sit back and wait untill your map is ready..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.job import generate_map, PostprocessParameters\n",
+ "\n",
+ "processing_period = slider.get_processing_period()\n",
+ "processing_extent = map.get_processing_extent()\n",
+ "\n",
+ "# Launch the job on CDSE through OpenEO\n",
+ "results = generate_map(\n",
+ " processing_extent,\n",
+ " processing_period,\n",
+ " output_dir=output_dir,\n",
+ " postprocess_parameters=PostprocessParameters,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The classification results will be automatically downloaded to your *output_dir* in .tif format. \n",
+ "\n",
+ "The result will be a raster file containing two bands:\n",
+ "1. The label of the winning class\n",
+ "2. The probability of the winning class [0 - 100]\n",
+ "\n",
+ "Using the function below, we split all this information into separate .tif files, thereby adding metadata and a color map, to ease interpretation and visualization:\n",
+ "- \"cropland_classification_start-date_end-date.tif\" --> contains the classification labels. The class look-up table is included in the .tif metadata.\n",
+ "- \"cropland_confidence_start-date_end-date.tif\" --> contains the probability associated to the prediction"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import prepare_visualization\n",
+ "\n",
+ "filepaths = prepare_visualization(results)\n",
+ "filepaths"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The resulting raster files can be visualized in QGIS."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 5. Final notes\n",
+ "\n",
+ "Both the quantity and quality of training data are main drivers affecting the quality of the cropland extent map. \n",
+ "Using the figure below, you get a relative indication how much training data was available for training our current default cropland model:\n",
+ "\n",
+ "\n",
+ " \n",
+ "
\n",
+ "\n",
+ "In case you own good quality reference data on land cover and/or crop types, consider contributing these data to the WorldCereal project through our [Reference Data Module](https://ewoc-rdm-ui.iiasa.ac.at/)."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "worldcereal",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/notebooks/worldcereal_v1_demo_default_cropland_EXTENDED.ipynb b/notebooks/worldcereal_v1_demo_default_cropland_EXTENDED.ipynb
deleted file mode 100644
index ca5b377d..00000000
--- a/notebooks/worldcereal_v1_demo_default_cropland_EXTENDED.ipynb
+++ /dev/null
@@ -1,451 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "![](./resources/System_v1_cropland.png)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This notebook contains a short demo on how to use the WorldCereal system to generate a temporary crop extent map for your area and season of interest.\n",
- "The map is generated using a default model trained by the WorldCereal consortium to distinguish temporary crops from all other land use.\n",
- "\n",
- "Please note that for the purpose of this demo, the processing area is currently limited to 250 km² per model run."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Content\n",
- " \n",
- "- [Before you start](###-Before-you-start)\n",
- "- [1. Define your region of interest](#1.-Define-your-region-of-interest)\n",
- "- [2. Define your year of interest](#2.-Define-your-year-of-interest)\n",
- "- [3. Set some other options](#3.-Set-some-other-options)\n",
- "- [4. Generate your map](#2.-Generate-your-map)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Before you start\n",
- "\n",
- "In order to run this notebook, you need to create an account on the Copernicus Data Space Ecosystem,\n",
- "by completing the form [HERE](https://identity.dataspace.copernicus.eu/auth/realms/CDSE/login-actions/registration?client_id=cdse-public&tab_id=eRKGqDvoYI0)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "# TEMPORARY CELL\n",
- "\n",
- "import sys\n",
- "sys.path.append('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/notebooks')\n",
- "%load_ext autoreload\n",
- "%autoreload 2"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 1. Define your region of interest\n",
- "\n",
- "When running the code snippet below, an interactive map will be visualized. Click the Rectangle button on the left hand side of the map to start drawing your region of interest. When finished, execute the second cell to store the coordinates of your region of interest.\n",
- "\n",
- "In case your region exceeds the 250 km² limit, you will be asked to draw again."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "e27f91e03cf6427cb43d889e53cd466c",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "Map(center=[51.1872, 5.1154], controls=(ZoomControl(options=['position', 'zoom_in_text', 'zoom_in_title', 'zoo…"
- ]
- },
- "execution_count": 2,
- "metadata": {},
- "output_type": "execute_result"
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 19:02:03.002\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mhandle_draw\u001b[0m:\u001b[36m13\u001b[0m - \u001b[1mYour processing extent: (-2.299034, 51.209393, -2.267434, 51.224876)\u001b[0m\n",
- "\u001b[32m2024-10-14 19:02:03.086\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mhandle_draw\u001b[0m:\u001b[36m19\u001b[0m - \u001b[1mArea of processing extent: 3.88 km²\u001b[0m\n"
- ]
- }
- ],
- "source": [
- "from worldcereal.utils.map import ui_map\n",
- "\n",
- "map = ui_map()\n",
- "map.show_map()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 2. Define your year of interest\n",
- "\n",
- "The default WorldCereal temporary crop model always uses a time series of exactly one year as input for the model.\n",
- "\n",
- "However, instead of just using a calendar year (January 1st - December 31st), we recommend to define the exact start and end date of your time series, or processing period, based on the timing of the local growing seasons.\n",
- "\n",
- "Take the following example for Western Europe, where we typically have a winter season (s1) and summer season (s2):\n",
- "\n",
- "\n",
- "
\n",
- "
\n",
- "\n",
- "\n",
- "The best timing to start and end the time series in this case would be October (green vertical line), as for both seasons this would result in nicely capturing the growing season within the time series. It would not make sense in this case to define the year from June to June (red vertical line), as you will miss the start of the summer season and the end of the winter season in your time series.\n",
- "\n",
- "So if you would like to map temporary crops in Western Europe for the year 2021, we would recommend to define your processing period as October 1st 2020 - September 30th 2021.\n",
- "\n",
- "In case you do not know the typical seasonality of crops in your area of interest, you can consult the WorldCereal crop calendars using the function below.\n",
- "\n",
- "Note that in case your area of interest is located in an extremely heterogeneous part of the world, the WorldCereal seasons cannot be retrieved at the moment. As a fall-back, please consult the [USDA crop calendars](https://ipad.fas.usda.gov/ogamaps/cropcalendar.aspx)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-14 19:02:11.265\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mget_processing_extent\u001b[0m:\u001b[36m112\u001b[0m - \u001b[1mYour processing extent: (-2.299034, 51.209393, -2.267434, 51.224876)\u001b[0m\n"
- ]
- },
- {
- "data": {
- "image/png": "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",
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": [
- "from utils import retrieve_worldcereal_seasons\n",
- "\n",
- "spatial_extent = map.get_processing_extent()\n",
- "seasons = retrieve_worldcereal_seasons(spatial_extent)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Execute the next cell to select your processing period:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "5b646621b65e4f5eb02a40eda8f95e00",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "VBox(children=(HTML(value=\"\\n \\n
0.0631313673349114\n",
- "WARNING:PrestoFeatureExtractor:No additional dependencies are defined. If you wish to add dependencies to your feature extractor, override the `dependencies` method in your class.\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "0:00:00 Job 'j-241014a157564fe2aa11cfc08be67c3a': send 'start'\n",
- "0:00:16 Job 'j-241014a157564fe2aa11cfc08be67c3a': created (progress 0%)\n",
- "0:00:22 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:00:29 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:00:38 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:00:48 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:01:02 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:01:20 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:01:42 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:02:07 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:02:38 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:03:16 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:04:04 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:05:04 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:06:05 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:07:06 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:08:08 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:09:08 Job 'j-241014a157564fe2aa11cfc08be67c3a': running (progress N/A)\n",
- "0:10:09 Job 'j-241014a157564fe2aa11cfc08be67c3a': finished (progress 100%)\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "INFO:openeo.rest.job:Downloading Job result asset 'cropland-raw_20211201_20221130.tif' from https://openeo.creo.vito.be/openeo/jobs/j-241014a157564fe2aa11cfc08be67c3a/results/assets/ZGNjYWI2ZDktODQ2Yy00OGE5LTlkOTQtNDk3MTQ2Y2IyMjg1/069a930f1ee92b4b285afda2f08e88c3/cropland-raw_20211201_20221130.tif?expires=1729530975 to /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_ENGLAND/cropland-raw_20211201_20221130.tif\n",
- "INFO:openeo.rest.job:Downloading Job result asset 'cropland_20211201_20221130.tif' from https://openeo.creo.vito.be/openeo/jobs/j-241014a157564fe2aa11cfc08be67c3a/results/assets/ZGNjYWI2ZDktODQ2Yy00OGE5LTlkOTQtNDk3MTQ2Y2IyMjg1/6462b4d77c6a8bac07319fd3f9f6fbd4/cropland_20211201_20221130.tif?expires=1729530975 to /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_ENGLAND/cropland_20211201_20221130.tif\n"
- ]
- }
- ],
- "source": [
- "from worldcereal.job import generate_map\n",
- "\n",
- "processing_period = slider.get_processing_period()\n",
- "processing_extent = map.get_processing_extent()\n",
- "\n",
- "# Launch the job on CDSE through OpenEO\n",
- "results = generate_map(\n",
- " processing_extent,\n",
- " processing_period,\n",
- " output_dir=output_dir,\n",
- " postprocess_parameters=postprocess_parameters,\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The classification results will be automatically downloaded to your output_dir in .tif format.\n",
- "By default, OpenEO stores the class labels and confidence score in one file.\n",
- "\n",
- "Using the function below, we split this information into separate .tif files, thereby adding metadata and a color map, to ease interpretation and visualization:\n",
- "- \"xxx_classification_start-date_end-date.tif\" --> contains the classification labels. A class look-up table is included in the .tif metadata.\n",
- "- \"xxx_confidence_start-date_end-date.tif\" --> contains the probability associated to the prediction [0 - 100]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "{'cropland-raw': {'classification': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_ENGLAND/cropland-raw_classification_20211201_20221130.tif'), 'confidence': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_ENGLAND/cropland-raw_confidence_20211201_20221130.tif')}, 'cropland': {'classification': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_ENGLAND/cropland_classification_20211201_20221130.tif'), 'confidence': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_ENGLAND/cropland_confidence_20211201_20221130.tif')}}\n"
- ]
- }
- ],
- "source": [
- "from utils import prepare_visualization\n",
- "\n",
- "rasters = prepare_visualization(results)\n",
- "print(rasters)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The resulting raster files can be visualized in QGIS, or using the function in the cell below..."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "4d40017e7b1b41e5af029f9a32a9da0d",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "Map(center=[51.217128, -2.2832285], controls=(ZoomControl(options=['position', 'zoom_in_text', 'zoom_in_title'…"
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from utils import visualize_products\n",
- "\n",
- "visualize_products(rasters, port=8889)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Finally, use the cell below to visualize the look-up table for the classification product."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAOIAAABQCAYAAAAEEqmpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAMUklEQVR4nO3db0xT5x4H8G+Z9I90m0yQDMoApR3rghlM+bOxCSrJ3CArksyomRaZQxgqi1IoJiauwJTBlGRTluvAF0yHyswyVJw0o9rMRRG6KKBuhG5TGQPNsolSDH3uCy/ncgYUuBfpqf19XsFznvP0OU2+nHOe9vwQMcYYCCFO5eHsCRBCKIiECAIFkRABoCASIgAUREIEgIJIiABQEAkRAAoiIQIww9HG06dPw2azTddcppxEIkFiYqKzp0HIuBwG0WazQSKRTNdcppwr/xEh7oUuTf8H8fHxyM7OdvY0yCOEguhAY2MjRCIRent7nT0V8oijIArI/fv3nT0F4iRuH0SbzYacnBz4+flBKpUiJiYGZrMZVqsVCQkJAABfX1+IRCJotVpuP7vdjoKCAvj4+GDOnDnYunUr7HY7t31gYAB5eXlQKBTw8vLCwoULcerUKW770Nn2xIkTiIqKglgs5m0n7sXtg6jT6VBTU4PKykq0tLQgPDwcr732Gjw9PVFbWwsAaG1tRVdXF8rLy7n9vvjiC8yYMQPff/89PvnkE+zZswc1NTXc9rS0NJhMJhw8eBCXLl3C2rVrkZycjB9//JH3+nl5eSgsLMSVK1cQHR09PQdNBEfk6HnEuro6l181TUpKGnN7X18fvL29sX//fqxZswYAMDg4CJVKhZUrV2Lp0qVISEhAT08PfHx8uP3i4+Nhs9lw7tw5ri0xMRFBQUHYv38/Ojo6oFQqYbVa8cwzz3B9NBoN/P39sXfvXjQ2NiIhIQFHjx5FamrqQzh64kocfnzxqOvo6MD9+/fx8ssvc22PPfYYYmNj0dbWhqVLl4657/z583m/+/v7448//gAANDc3gzEGtVrN62Oz2bB48WJe24IFC/7fwyCPALcO4tDFgEgkGrFttLbhPD09R/Qfuke02+0QiUS4cOHCiH4ymYz3u5eX16TnTR49bh3E0NBQiMVimM1mzJ07F8CDS9Nz585h1apVEIvFXNtkREREgDGG33//nVvwIcQRtw6il5cXMjMzkZ+fDx8fH4SEhGD37t3o7u5GVlYWd2Y7fvw4kpOTIZPJIJfLxx1XpVJh9erV0Gq1KCsrQ2RkJG7fvo3GxkbMnTsXy5cvn4ajI67ErYMIALt27QLwYJXzzz//REREBOrr6/H0008DAHbs2IFt27bhnXfewZo1a3DgwIEJjVtVVYWioiLodDpcv34dTz31FKKiougMSUbl1qumhAiF23+OSIgQUBAJEQAKIiECQEEkRAAcrppKJBKXfrjWlReaiHtxuGpKCJkedGlKiABQEAkRAIf3iA0nTqB/2MOurkbq4YGlr7/u7GkQMi6HQey32xG+PnO65jLlLv1rn7OnQMiE0KWpE1itVohEIjQ1NT3010pKSuKV+CDCREEkRAAoiJNAVdbIw+L2QWSMoaysDEqlEhKJBAqFAnq9nrt8PHToEBYvXgyZTIbPPvsMdrsdBoMBgYGBkEgkCA8Px9dff82NN7TfwYMHERcXB6lUirCwMHz77bdjzmFwcBDp6ekICQmBTCaDUqlESUkJryqcVqtFUlISysvLERAQAG9vb6SlpeHu3btcn7t370Kr1UIul8PPzw/FxcUP500jU87tg1hQUACDwQC9Xo/W1lYcOXIEgYGB3Ha9Xo+srCy0tbVBo9GgvLwcH330EXbt2oVLly4hJSUFy5cvh8Vi4Y2r0+mwadMmWCwWJCYm4s0338SNGzdGnYPdbkdAQAAOHz6M9vZ2FBUVobi4GFVVVbx+Z8+exeXLl9HQ0ICamhocO3aMV1lu69atOH36NGpra2E0GtHS0oIzZ85M3ZtFHppxn0d09VVTR88j3rlzBz4+PtizZw82bNjA22a1WhESEoLS0lJs2bKFaw8ICEBGRga2b9/OtcXHx0OhUKC6uprbr7CwENu2bQPwIGhhYWF46623UFhYyPW5cOHCmMWj8vPz0dTUhIaGBgAPzohGoxGdnZ2YMePBYvf69evR2dmJhoYG3LlzB7Nnz0ZlZSVWr17NHZ9CoYBGo5nwA83EOdz6jNjW1gabzYYlS5aM2Wd4UP766y/cvHmTV/UNAOLi4tDW1sZri42N5X728PBAdHT0iD7DVVRUYMGCBfD19YVcLsfu3bvx66+/8vqo1WouhAC/clxHRwcGBgZ4ryuXyxEeHj7maxLhcOsgTuRrtqNVWftfqr45UlNTg5ycHGi1Wpw6dQoWiwVZWVkYGBjg9XNUOY6+Muza3DqIarUaEokERqNxQv2feOIJ+Pv7w2w289rNZvOIGqY//PAD9zNjDOfPn8dzzz036rhmsxnR0dHIzs5GZGQkQkND0dHRMaljCQ0NhaenJ+91+/r6cPny5UmNQ5zDrYtHPf7449i8eTP0ej0kEgleffVV3Lp1CxcvXsSyZctG3Sc3Nxfbt2+HUqnEiy++iOrqapw9exYXL17k9du3bx9UKhXCw8Oxd+9e/PLLL8jMHP1+W6VS4cCBAzh58iRCQ0Px5ZdfwmQywdvbe8LHIpfLkZ6ejry8PPj6+sLf3x8ffPDBpEtBEudw6yACwIcffghvb28YDAZcv34dfn5+XPn90WzatAl///03dDoduru78eyzz6K2thYvvPACr9/OnTvx8ccfo7m5GUFBQTh27BgUCsWoY2ZkZMBisWDVqlVgjCE1NRVbtmxBZWXlpI6ltLQUfX19SElJwcyZM7Fx40b09fVNagziHG69avowTGRFlJB/cut7REKEgoJIiAC4/T3iVAsODqaPEsik0RmREAFweEaUeni49MO1Ug/6O0NcA1VxI0QA6JRBiABQEAkRAIf3iEajEffu3ZuuuUw5mUzm8MkKQoTCYRDv3bvn0v9fsK6uztlTIGRC6NJ0GjU1NUEkEsFqtTp7KkRg3DqIWq0WIpEIhYWFvPbGxkaIRCL09vY6aWb/FR8fj+zsbGdPgzxkbh1EAJBKpSgpKUFPT4+zp0LcmNsHMSEhAcHBwTAYDA77nTlzBtHR0ZBKpfDz88P7778/4gn6f6qvr0dYWBikUileeeUVXLt2jbf91q1bWLlyJRQKBWQyGZ5//nlewSitVguTyYRPP/0UIpGIu6ydSNU34lrcPogeHh7YuXMnKioqxnwq/saNG1i2bBkiIiLQ0tKCzz//HIcOHYJerx9z3N9++w0ajQaJiYmwWCzYuHEjdDodr09/fz8iIyNRV1eH1tZWbN68GRkZGVzFgPLycsTGxiItLQ1dXV3o6upCYGDghKu+ERfCHPjmm28cbRa88ea/du1a9sYbbzDGGIuPj2crVqxgjDH23XffMQCsp6eHMcZYQUEBmzdvHhscHOT2raqqYmKxmPX19Y06tl6vZ0qlktntdq7NYDAwAKyzs3PMOa1YsYKlp6dzvy9atIi99957jg+UMZaXl8eWLFkybj8iTG5/RhxSUlKCI0eOjPr/KNrb2xEbGwuPYd9djYuLw8DAAH7++edRx2tvb0dMTAyvqNTwCmvAg8LCRUVFmD9/PmbPng25XI6vvvpqRPW20Uyk6htxHRTE/1i4cCFSU1ORl5c3YhtjbMwqbWO1swl8hbe0tBRlZWXIzc2F0WiExWKBRqMZ995zolXfiOug5xGHKS4uhlqtRn19Pa9drVbj8OHDsNvt3FnRbDZDLBZj3rx5o46lVqtRW1vLC/HwCmtDYyQnJ+Ptt98G8CC8165dw6xZs7g+YrF4RAGo4VXfhky26hsRFjojDhMaGop3332XV8YeALKysnDz5k1kZWWhvb0dx48fR35+PrKzszFz5sxRx9qwYQOsVitycnJw9epVHD16FBUVFbw+KpUKRqMRZrMZV65cQXZ2Njo7O3l9goODcf78eVitVvT29sJut0OlUqG5uRknT57ETz/9BIPBAJPJNLVvBplejm4g3WmxZkh3dzeTy+W8xRrGGDOZTCwqKoqJxWI2Z84clpOTw/r7+x2OX1dXx1QqFZNIJOyll15i1dXVvMWa27dvs5SUFCaXy5mvry/Lzc1lmZmZbNGiRdwYV69eZTExMUwmk3H72mw2tm7dOjZr1iz25JNPsnXr1rEdO3awoKCgSb0/RDjGreLm6t81deX5E/dBl6aECAAFkRABoCASIgAUREIEwOHniDKZzKUfrpXJZM6eAiETQlXcCBEAujQlRAAoiIQIAAWREAGgIBIiABREQgSAgkiIAFAQCRGAfwMShaprE0W8AwAAAABJRU5ErkJggg==",
- "text/plain": [
- "
"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": [
- "from utils import show_color_legend\n",
- "\n",
- "show_color_legend(rasters, \"cropland\")\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "# Add section where user can check the availability of cropland reference data!"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "worldcereal",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.10.0"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/notebooks/worldcereal_v1_demo_default_cropland_SHORT.ipynb b/notebooks/worldcereal_v1_demo_default_cropland_SHORT.ipynb
deleted file mode 100644
index 3de91d98..00000000
--- a/notebooks/worldcereal_v1_demo_default_cropland_SHORT.ipynb
+++ /dev/null
@@ -1,424 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "![](./resources/System_v1_cropland.png)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This notebook contains a short demo on how to use the WorldCereal system to generate a temporary crop extent map for your area and season of interest.\n",
- "The map is generated using a default model trained by the WorldCereal consortium to distinguish temporary crops from all other land use.\n",
- "\n",
- "Please note that for the purpose of this demo, the processing area is currently limited to 250 km² per model run."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Content\n",
- " \n",
- "- [Before you start](###-Before-you-start)\n",
- "- [1. Define your region of interest](#1.-Define-your-region-of-interest)\n",
- "- [2. Define your year of interest](#2.-Define-your-year-of-interest)\n",
- "- [3. Set some other options](#3.-Set-some-other-options)\n",
- "- [4. Generate your map](#2.-Generate-your-map)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Before you start\n",
- "\n",
- "In order to run this notebook, you need to create an account on the Copernicus Data Space Ecosystem,\n",
- "by completing the form [HERE](https://identity.dataspace.copernicus.eu/auth/realms/CDSE/login-actions/registration?client_id=cdse-public&tab_id=eRKGqDvoYI0)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "# TEMPORARY CELL\n",
- "\n",
- "import sys\n",
- "sys.path.append('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/notebooks')\n",
- "%load_ext autoreload\n",
- "%autoreload 2"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 1. Define your region of interest\n",
- "\n",
- "When running the code snippet below, an interactive map will be visualized. Click the Rectangle button on the left hand side of the map to start drawing your region of interest. When finished, execute the second cell to store the coordinates of your region of interest.\n",
- "\n",
- "In case your region exceeds the 250 km² limit, you will be asked to draw again."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "659014fc3caa44a991c98b8ee67056e7",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "Map(center=[51.1872, 5.1154], controls=(ZoomControl(options=['position', 'zoom_in_text', 'zoom_in_title', 'zoo…"
- ]
- },
- "execution_count": 2,
- "metadata": {},
- "output_type": "execute_result"
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-10 14:26:31.019\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mhandle_draw\u001b[0m:\u001b[36m141\u001b[0m - \u001b[1mYour processing extent: (4.515724, 50.982641, 4.609108, 51.020018)\u001b[0m\n",
- "\u001b[32m2024-10-10 14:26:31.093\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mhandle_draw\u001b[0m:\u001b[36m148\u001b[0m - \u001b[1mArea of processing extent: 28.52 km²\u001b[0m\n"
- ]
- }
- ],
- "source": [
- "from worldcereal.utils.map import ui_map\n",
- "\n",
- "map = ui_map()\n",
- "map.show_map()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 2. Define your year of interest\n",
- "\n",
- "The default WorldCereal temporary crop model always uses a time series of exactly one year as input for the model.\n",
- "\n",
- "However, instead of just using a calendar year (January 1st - December 31st), we recommend to define the exact start and end date of your time series, or processing period, based on the timing of the local growing seasons.\n",
- "\n",
- "Take the following example for Western Europe, where we typically have a winter season (s1) and summer season (s2):\n",
- "\n",
- "\n",
- "
\n",
- "
\n",
- "\n",
- "\n",
- "The best timing to start and end the time series in this case would be October (green vertical line), as for both seasons this would result in nicely capturing the growing season within the time series. It would not make sense in this case to define the year from June to June (red vertical line), as you will miss the start of the summer season and the end of the winter season in your time series.\n",
- "\n",
- "So if you would like to map temporary crops in Western Europe for the year 2021, we would recommend to define your processing period as October 1st 2020 - September 30th 2021.\n",
- "\n",
- "In case you do not know the typical seasonality of crops in your area of interest, you can consult the WorldCereal crop calendars using the function below.\n",
- "\n",
- "Note that in case your area of interest is located in an extremely heterogeneous part of the world, the WorldCereal seasons cannot be retrieved at the moment. As a fall-back, please consult the [USDA crop calendars](https://ipad.fas.usda.gov/ogamaps/cropcalendar.aspx)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "\u001b[32m2024-10-10 14:26:45.056\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mworldcereal.utils.map\u001b[0m:\u001b[36mget_processing_extent\u001b[0m:\u001b[36m236\u001b[0m - \u001b[1mYour processing extent: (4.515724, 50.982641, 4.609108, 51.020018)\u001b[0m\n"
- ]
- },
- {
- "data": {
- "image/png": "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DhECzgRg37V92D5se1GXQp8Af4UCoxMTpcGiRJ+KvL5/8/YKERERyYJXOoiIiKhQeKWDiIiIihWGDiIiIpIFQwcRERHJgqGDiIiIZMHQQURERLJg6CAiIiJZMHQQERGRLBg6iIiISBYMHURERCQLhg4iIiKSBUMHERERyYKhg4iIiGTB0EFERESyYOggIiIiWTB0EBERkSwYOoiIiEgWDB1EREQkC4YOIiIikgVDBxEREcmCoYOIiIhkwdBBREREsmDoICIiIlkwdBAREZEsGDqIiIhIFgwdREREJAuGDiIiIpIFQwcRERHJgqGDiIiIZMHQQURERLJg6CAiIiJZMHQQERGRLBg6iIiISBYMHURERCQLhg4iIiKSBUMHERERyYKhg4iIiGTB0EFERESyYOggIiIiWTB0EBERkSwYOoiIiEgWDB1EREQkC4YOIiIikgVDBxEREcmCoYOIiIhkwdBBREREsmDoICIiIlkwdBAREZEsGDqIiIhIFgwdREREJAuGDiIiIpIFQwcRERHJgqGDiIiIZMHQQURERLJg6CAiIiJZMHQQERGRLBg6iIiISBYMHURERCQLhg4iIiKSBUMHERERyYKhg4iIiGTB0EFERESyYOggIiIiWTB0EBERkSy0irqAkiI5PhJpybFFXQYRlUDaembQM7Yu6jKKHb6uFkxJPp8YOvIgOT4Sp1d4IDPjdVGXQkQlkIamEg2HhJbYN4qPga+rBVeSzyfeXsmDtORYPjGIqMAyM17zE/07+LpacCX5fGLoICIiIlkwdBAREZEsGDqIiIhIFgwdREREJAuGDiIiIpIFQwcRERHJgqGDiIiIZMHQQURERLJg6CAiIiJZMHQQERGRLBg6iIiISBYMHURERCQLhg4iIiKSBUMHERERyYKhg4iIiGTB0EFERESyYOggIiIiWTB0EBERkSwYOoiIiEgWDB1EREQkC4YOIiIikgVDBxEREcmCoYOIiIhkwdBBREREsmDoICIiIlkwdBAREZEsGDqIiIhIFgwdREREJAuGDiIiIpIFQwcRERHJgqGDiIiIZMHQQURERLJg6CAiIiJZMHQQERGRLBg6iIiISBYMHURERCQLhg4iIiKSBUMHERERyUJtoePGjRvo0qUL7OzsoFAosHjxYnV1TURERJ8AtYWOpKQk2NvbY968ebCwsFBXt0RERPSJyHfo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",
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": [
- "from utils import retrieve_worldcereal_seasons\n",
- "\n",
- "spatial_extent = map.get_processing_extent()\n",
- "seasons = retrieve_worldcereal_seasons(spatial_extent)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Execute the next cell to select your processing period:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "f3ed0a9f8b6e44368f676b4652854537",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "VBox(children=(HTML(value=\"\\n \\n
2.9861386687313125\n",
- "INFO:openeo_gfmap.utils:Selected orbit state: ASCENDING. Reason: Orbit has more cumulative intersected area. 3.0794083284461435 > 2.9861386687313125\n",
- "WARNING:PrestoFeatureExtractor:No additional dependencies are defined. If you wish to add dependencies to your feature extractor, override the `dependencies` method in your class.\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "0:00:00 Job 'j-2410101e92934a5da839ca7a10984c2b': send 'start'\n",
- "0:00:14 Job 'j-2410101e92934a5da839ca7a10984c2b': created (progress 0%)\n",
- "0:00:19 Job 'j-2410101e92934a5da839ca7a10984c2b': created (progress 0%)\n",
- "0:00:25 Job 'j-2410101e92934a5da839ca7a10984c2b': created (progress 0%)\n",
- "0:00:33 Job 'j-2410101e92934a5da839ca7a10984c2b': created (progress 0%)\n",
- "0:00:43 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:00:56 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:01:11 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:01:31 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:01:55 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:02:25 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:03:02 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:03:49 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:04:47 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:05:48 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:06:48 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:07:48 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:08:48 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:09:49 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:10:49 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:11:49 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:12:50 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:13:50 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:14:50 Job 'j-2410101e92934a5da839ca7a10984c2b': running (progress N/A)\n",
- "0:15:51 Job 'j-2410101e92934a5da839ca7a10984c2b': finished (progress 100%)\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "INFO:openeo.rest.job:Downloading Job result asset 'cropland_2020-01-01Z.tif' from https://openeo.creo.vito.be/openeo/jobs/j-2410101e92934a5da839ca7a10984c2b/results/assets/ZGNjYWI2ZDktODQ2Yy00OGE5LTlkOTQtNDk3MTQ2Y2IyMjg1/5ef2ad85691d9dd85a2280ff0cbbd4db/cropland_2020-01-01Z.tif?expires=1729176998 to /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_2020-01-01Z.tif\n"
- ]
- }
- ],
- "source": [
- "from worldcereal.job import generate_map\n",
- "\n",
- "processing_period = slider.get_processing_period()\n",
- "processing_extent = map.get_processing_extent()\n",
- "\n",
- "# Launch the job on CDSE through OpenEO\n",
- "results = generate_map(\n",
- " processing_extent,\n",
- " processing_period,\n",
- " output_dir=output_dir,\n",
- " postprocess_parameters=postprocess_parameters,\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The classification results will be automatically downloaded to your output_dir in .tif format.\n",
- "By default, OpenEO stores the class labels and confidence score in one file.\n",
- "\n",
- "Using the function below, we split this information into separate .tif files, thereby adding metadata and a color map, to ease interpretation and visualization:\n",
- "- \"xxx_classification_start-date_end-date.tif\" --> contains the classification labels. A class look-up table is included in the .tif metadata.\n",
- "- \"xxx_confidence_start-date_end-date.tif\" --> contains the probability associated to the prediction [0 - 100]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "WARNING:rasterio._env:CPLE_AppDefined in /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_2020-01-01Z.tif: /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_2020-01-01Z.tif:Nonstandard tile width 100, convert file\n",
- "WARNING:rasterio._env:CPLE_AppDefined in /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_2020-01-01Z.tif: /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_2020-01-01Z.tif:Nonstandard tile length 100, convert file\n",
- "WARNING:rasterio._env:CPLE_AppDefined in /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_2020-01-01Z.tif: TIFFReadDirectory:Sum of Photometric type-related color channels and ExtraSamples doesn't match SamplesPerPixel. Defining non-color channels as ExtraSamples.\n",
- "WARNING:rasterio._env:CPLE_AppDefined in /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_2020-01-01Z.tif:Nonstandard tile width 100, convert file\n",
- "WARNING:rasterio._env:CPLE_AppDefined in /home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_2020-01-01Z.tif:Nonstandard tile length 100, convert file\n",
- "WARNING:rasterio._env:CPLE_AppDefined in TIFFReadDirectory:Sum of Photometric type-related color channels and ExtraSamples doesn't match SamplesPerPixel. Defining non-color channels as ExtraSamples.\n",
- "INFO:rasterio._env:GDAL signalled an error: err_no=1, msg='TIFFSetField:/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_classification_20181001_20190930.tif: Cannot modify tag \"PhotometricInterpretation\" while writing'\n",
- "INFO:rasterio._env:GDAL signalled an error: err_no=1, msg='TIFFSetField:/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_confidence_20181001_20190930.tif: Cannot modify tag \"PhotometricInterpretation\" while writing'\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "{'cropland': {'classification': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_classification_20181001_20190930.tif'),\n",
- " 'confidence': PosixPath('/home/jeroendegerickx/git/worldcereal/worldcereal-classification/CROPLAND_test_nopostprocess/cropland_confidence_20181001_20190930.tif')}}"
- ]
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from utils import prepare_visualization\n",
- "\n",
- "filepaths = prepare_visualization(results)\n",
- "filepaths"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The resulting raster files can be visualized in QGIS."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "# Add section where user can check the availability of cropland reference data!"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "worldcereal",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.10.0"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/notebooks/worldcereal_v1_demo_default_cropland_extended.ipynb b/notebooks/worldcereal_v1_demo_default_cropland_extended.ipynb
new file mode 100644
index 00000000..0e62d718
--- /dev/null
+++ b/notebooks/worldcereal_v1_demo_default_cropland_extended.ipynb
@@ -0,0 +1,316 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "![](./resources/System_v1_cropland.png)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Introduction\n",
+ "\n",
+ "This notebook contains a short demo on how to use the WorldCereal system to generate a cropland extent map for your area and season of interest.
\n",
+ "The map is generated using a default model trained by the WorldCereal consortium to distinguish cropland from all other land use.\n",
+ "\n",
+ "Please note that for the purpose of this demo, the processing area is currently limited to 250 km² per model run. On average, one such run consumes 35 credits on the Copernicus Data Space Ecosystem.\n",
+ "\n",
+ "
\n",
+ "Cropland definition: \n",
+ "Cropland is defined here as land used for temporary crops, i.e. crops with a less-than-1-year growing cycle which must be newly sown or planted for further production after the harvest. Sugar cane, asparagus, and cassava are also considered temporary crops, even though they remain in the field for more than 1 year. This cropland definition thus excludes perennial crops as well as (temporary) pastures.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Content\n",
+ " \n",
+ "- [Before you start](###-Before-you-start)\n",
+ "- [1. Define your region of interest](#1.-Define-your-region-of-interest)\n",
+ "- [2. Define your year of interest](#2.-Define-your-year-of-interest)\n",
+ "- [3. Set some other options](#3.-Set-some-other-options)\n",
+ "- [4. Generate your map](#4.-Generate-your-map)\n",
+ "- [5. Final notes](#5.-Final-notes)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Before you start\n",
+ "\n",
+ "In order to run WorldCereal crop mapping jobs from this notebook, you need to create an account on the Copernicus Data Space Ecosystem,\n",
+ "by completing the form [here](https://dataspace.copernicus.eu/).\n",
+ "This is free of charge and will grant you a number of free openEO processing credits to continue this demo."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 1. Define your region of interest\n",
+ "\n",
+ "When running the code snippet below, an interactive map will be visualized.\n",
+ "Click the Rectangle button on the left hand side of the map to start drawing your region of interest.\n",
+ "\n",
+ "Currently, there is a maximum size of 250 km² for your area within this demo. Upon exceeding this limit, an error will be shown.\n",
+ "You can bypass this limit by altering the code below to:
\n",
+ "*map = ui_map(area_limit=750)*
\n",
+ "\n",
+ "Processing areas beyond 750 km² are currently not supported to avoid excessive credit usage (roughly 120 credits will be consumed for this size of a processing extent).\n",
+ "\n",
+ "The widget will automatically store the coordinates of the last rectangle you drew on the map."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.utils.map import ui_map\n",
+ "\n",
+ "map = ui_map()\n",
+ "map.show_map()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 2. Define your year of interest\n",
+ "\n",
+ "The default WorldCereal cropland model always uses a time series of exactly one year as input for the model.\n",
+ "\n",
+ "However, instead of just using a calendar year (January 1st - December 31st), we recommend to define the exact start and end date of your time series, or processing period, based on the timing of the local growing seasons.\n",
+ "\n",
+ "Take the following example for Western Europe, where we typically have a winter season (s1) and summer season (s2):\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "\n",
+ "The best timing to start and end the time series in this case would be October (green vertical line), as for both seasons this would result in nicely capturing the growing season within the time series. It would not make sense in this case to define the year from June to June (red vertical line), as you will miss the start of the summer season and the end of the winter season in your time series.\n",
+ "\n",
+ "So if you would like to map temporary crops in Western Europe for the year 2021, we would recommend to define your processing period as October 1st 2020 - September 30th 2021.\n",
+ "\n",
+ "In case you do not know the typical seasonality of crops in your area of interest, you can consult the WorldCereal crop calendars using the function below.\n",
+ "\n",
+ "Note that in case your area of interest is located in an extremely heterogeneous part of the world, the WorldCereal seasons cannot be retrieved at the moment. As a fall-back, please consult the [USDA crop calendars](https://ipad.fas.usda.gov/ogamaps/cropcalendar.aspx)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import retrieve_worldcereal_seasons\n",
+ "\n",
+ "spatial_extent = map.get_processing_extent()\n",
+ "seasons = retrieve_worldcereal_seasons(spatial_extent)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Execute the next cell to select your processing period:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import date_slider\n",
+ "\n",
+ "slider = date_slider()\n",
+ "slider.show_slider()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 3. Set some other options"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.job import PostprocessParameters\n",
+ "import os\n",
+ "from pathlib import Path\n",
+ "from utils import get_input\n",
+ "\n",
+ "# Choose whether or not you want to spatially clean the classification results\n",
+ "postprocess_result = True\n",
+ "# Choose the postprocessing method you want to use [\"smooth_probabilities\", \"majority_vote\"]\n",
+ "# (\"smooth_probabilities will do limited spatial cleaning,\n",
+ "# while \"majority_vote\" will do more aggressive spatial cleaning, depending on the value of kernel_size)\n",
+ "postprocess_method = \"majority_vote\"\n",
+ "# Additional parameter for the majority vote method \n",
+ "# (the higher the value, the more aggressive the spatial cleaning,\n",
+ "# should be an odd number, not larger than 25, default = 5)\n",
+ "kernel_size = 5\n",
+ "# Do you want to save the intermediate results (before applying the postprocessing)\n",
+ "save_intermediate = True\n",
+ "# Do you want to save all class probabilities in the final product? \n",
+ "keep_class_probs = True\n",
+ "\n",
+ "postprocess_parameters = PostprocessParameters(enable=postprocess_result,\n",
+ " method=postprocess_method,\n",
+ " kernel_size=kernel_size,\n",
+ " save_intermediate=save_intermediate,\n",
+ " keep_class_probs=keep_class_probs)\n",
+ "\n",
+ "# Specify the local directory where the resulting maps should be downloaded to.\n",
+ "run = get_input('model run')\n",
+ "output_dir = Path(os.getcwd()) / f'CROPLAND_default_{run}'\n",
+ "print(f\"Output directory: {output_dir}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 4. Generate your map\n",
+ "\n",
+ "We now have all information we need to generate our map!
\n",
+ "The next cell will submit a map inference job on CDSE through OpenEO.
\n",
+ "The first time you run this, you will be asked to authenticate with your CDSE account by clicking the link provided below the cell.
\n",
+ "Then sit back and wait untill your map is ready..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from worldcereal.job import generate_map\n",
+ "\n",
+ "processing_period = slider.get_processing_period()\n",
+ "processing_extent = map.get_processing_extent()\n",
+ "\n",
+ "# Launch the job on CDSE through OpenEO\n",
+ "results = generate_map(\n",
+ " processing_extent,\n",
+ " processing_period,\n",
+ " output_dir=output_dir,\n",
+ " postprocess_parameters=postprocess_parameters,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The classification results will be automatically downloaded to your *output_dir* in .tif format.
\n",
+ "For a model with two classes, you get a raster file containing up to four bands:\n",
+ "1. The label of the winning class\n",
+ "2. The probability of the winning class [0 - 100]\n",
+ "3. and beyond (optional, depending on settings): Class probabilities of each class, ordered according to the look-up table. The look-up table for each product can be consulted in the 'results' object as produced by the 'generate_map' function.\n",
+ "\n",
+ "Using the function below, we split this information into separate .tif files, thereby adding metadata and a color map, to ease interpretation and visualization:\n",
+ "- \"cropland_classification_start-date_end-date.tif\" --> contains the classification labels. A class look-up table is included in the .tif metadata.\n",
+ "- \"cropland_confidence_start-date_end-date.tif\" --> contains the probability associated to the prediction [0 - 100]\n",
+ "\n",
+ "The individual class probabilities are currently NOT saved to a separate file and need to be consulted in the original output from OpenEO.\n",
+ "\n",
+ "Note that in case you chose to apply post-processing AND save intermediate results, you will also get a \"cropland-raw_xxx.tif\" output, which holds the classification labels and probabilities BEFORE post-processing."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import prepare_visualization\n",
+ "\n",
+ "rasters = prepare_visualization(results)\n",
+ "print(rasters)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The resulting raster files can be visualized in QGIS.\n",
+ "\n",
+ "In case you are running this script on your local environment, you can alternatively use the following cells to visualize the outputs directly in this notebook."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import visualize_products\n",
+ "\n",
+ "visualize_products(rasters, port=8889)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from utils import show_color_legend\n",
+ "\n",
+ "show_color_legend(rasters, \"cropland\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 5. Final notes\n",
+ "\n",
+ "Both the quantity and quality of training data are main drivers affecting the quality of the cropland extent map.
\n",
+ "Using the figure below, you get a relative indication how much training data was available for training our current default cropland model:\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "In case you own good quality reference data on land cover and/or crop types, consider contributing these data to the WorldCereal project through our [Reference Data Module](https://ewoc-rdm-ui.iiasa.ac.at/)."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "worldcereal",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/src/worldcereal/parameters.py b/src/worldcereal/parameters.py
index 69a1fa44..7b9b0e7e 100644
--- a/src/worldcereal/parameters.py
+++ b/src/worldcereal/parameters.py
@@ -167,7 +167,7 @@ class PostprocessParameters(BaseModel):
method: str (default="smooth_probabilities")
The method to use for postprocessing. Must be one of ["smooth_probabilities", "majority_vote"]
kernel_size: int (default=5)
- Used for majority vote postprocessing. Must be smaller than 25.
+ Used for majority vote postprocessing. Must be an odd number, larger than 1 and smaller than 25.
save_intermediate: bool (default=False)
Whether to save intermediate results (before applying the postprocessing).
The intermediate results will be saved in the GeoTiff format.
@@ -206,9 +206,17 @@ def check_parameters(self):
)
if self.method == "majority_vote":
+ if self.kernel_size % 2 == 0:
+ raise ValueError(
+ f"Kernel size for majority filtering should be an odd number, got {self.kernel_size}"
+ )
if self.kernel_size > 25:
raise ValueError(
- f"Kernel size must be smaller than 25, got {self.kernel_size}"
+ f"Kernel size for majority filtering should be an odd number smaller than 25, got {self.kernel_size}"
+ )
+ if self.kernel_size < 3:
+ raise ValueError(
+ f"Kernel size for majority filtering should be an odd number larger than 1, got {self.kernel_size}"
)
return self