Supervised classification Workflow Example¶
This example explains how to perform supervised classification.
Setup & Imports¶
We begin by importing the required modules and setting up the environment. & Download the sample quickbird satellite image for our module
! pip install nickyspatial
Requirement already satisfied: nickyspatial in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (0.1.1) Requirement already satisfied: folium>=0.19.5 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (0.19.5) Requirement already satisfied: geopandas>=1.0.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (1.0.1) Requirement already satisfied: ipympl>=0.9.7 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (0.9.7) Requirement already satisfied: ipywidgets>=8.1.7 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (8.1.7) Requirement already satisfied: matplotlib>=3.10.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (3.10.3) Requirement already satisfied: numexpr>=2.10.2 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (2.10.2) Requirement already satisfied: pandas>=2.2.3 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (2.2.3) Requirement already satisfied: plotly>=6.0.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (6.0.1) Requirement already satisfied: rasterio>=1.4.3 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (1.4.3) Requirement already satisfied: scikit-image>=0.25.2 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (0.25.2) Requirement already satisfied: scikit-learn>=1.6.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (1.6.1) Requirement already satisfied: scipy>=1.15.2 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (1.15.3) Requirement already satisfied: seaborn>=0.13.2 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (0.13.2) Requirement already satisfied: streamlit-folium>=0.24.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from nickyspatial) (0.25.0) Requirement already satisfied: branca>=0.6.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from folium>=0.19.5->nickyspatial) (0.8.1) Requirement already satisfied: jinja2>=2.9 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from folium>=0.19.5->nickyspatial) (3.1.5) Requirement already satisfied: numpy in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from folium>=0.19.5->nickyspatial) (1.24.4) Requirement already satisfied: requests in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from folium>=0.19.5->nickyspatial) (2.32.3) Requirement already satisfied: xyzservices in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from folium>=0.19.5->nickyspatial) (2025.4.0) Requirement already satisfied: pyogrio>=0.7.2 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from geopandas>=1.0.1->nickyspatial) (0.11.0) Requirement already satisfied: packaging in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from geopandas>=1.0.1->nickyspatial) (24.2) Requirement already satisfied: pyproj>=3.3.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from geopandas>=1.0.1->nickyspatial) (3.7.1) Requirement already satisfied: shapely>=2.0.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from geopandas>=1.0.1->nickyspatial) (2.1.0) Requirement already satisfied: ipython<10 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipympl>=0.9.7->nickyspatial) (8.30.0) Requirement already satisfied: pillow in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipympl>=0.9.7->nickyspatial) (11.0.0) Requirement already satisfied: traitlets<6 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipympl>=0.9.7->nickyspatial) (5.14.3) Requirement already satisfied: comm>=0.1.3 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipywidgets>=8.1.7->nickyspatial) (0.2.2) Requirement already satisfied: widgetsnbextension~=4.0.14 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipywidgets>=8.1.7->nickyspatial) (4.0.14) Requirement already satisfied: jupyterlab_widgets~=3.0.15 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipywidgets>=8.1.7->nickyspatial) (3.0.15) Requirement already satisfied: contourpy>=1.0.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from matplotlib>=3.10.1->nickyspatial) (1.3.1) Requirement already satisfied: cycler>=0.10 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from matplotlib>=3.10.1->nickyspatial) (0.12.1) Requirement already satisfied: fonttools>=4.22.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from matplotlib>=3.10.1->nickyspatial) (4.55.3) Requirement already satisfied: kiwisolver>=1.3.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from matplotlib>=3.10.1->nickyspatial) (1.4.7) Requirement already satisfied: pyparsing>=2.3.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from matplotlib>=3.10.1->nickyspatial) (3.2.0) Requirement already satisfied: python-dateutil>=2.7 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from matplotlib>=3.10.1->nickyspatial) (2.9.0.post0) Requirement already satisfied: pytz>=2020.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from pandas>=2.2.3->nickyspatial) (2024.1) Requirement already satisfied: tzdata>=2022.7 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from pandas>=2.2.3->nickyspatial) (2023.3) Requirement already satisfied: narwhals>=1.15.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from plotly>=6.0.1->nickyspatial) (1.39.0) Requirement already satisfied: affine in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from rasterio>=1.4.3->nickyspatial) (2.4.0) Requirement already satisfied: attrs in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from rasterio>=1.4.3->nickyspatial) (24.3.0) Requirement already satisfied: certifi in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from rasterio>=1.4.3->nickyspatial) (2025.1.31) Requirement already satisfied: click>=4.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from rasterio>=1.4.3->nickyspatial) (8.1.7) Requirement already satisfied: cligj>=0.5 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from rasterio>=1.4.3->nickyspatial) (0.7.2) Requirement already satisfied: click-plugins in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from rasterio>=1.4.3->nickyspatial) (1.1.1) Requirement already satisfied: networkx>=3.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from scikit-image>=0.25.2->nickyspatial) (3.4.2) Requirement already satisfied: imageio!=2.35.0,>=2.33 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from scikit-image>=0.25.2->nickyspatial) (2.36.1) Requirement already satisfied: tifffile>=2022.8.12 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from scikit-image>=0.25.2->nickyspatial) (2024.12.12) Requirement already satisfied: lazy-loader>=0.4 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from scikit-image>=0.25.2->nickyspatial) (0.4) Requirement already satisfied: joblib>=1.2.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from scikit-learn>=1.6.1->nickyspatial) (1.4.2) Requirement already satisfied: threadpoolctl>=3.1.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from scikit-learn>=1.6.1->nickyspatial) (3.5.0) Requirement already satisfied: streamlit>=1.35.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit-folium>=0.24.1->nickyspatial) (1.45.1) Requirement already satisfied: decorator in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipython<10->ipympl>=0.9.7->nickyspatial) (5.1.1) Requirement already satisfied: exceptiongroup in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipython<10->ipympl>=0.9.7->nickyspatial) (1.2.2) Requirement already satisfied: jedi>=0.16 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipython<10->ipympl>=0.9.7->nickyspatial) (0.19.2) Requirement already satisfied: matplotlib-inline in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipython<10->ipympl>=0.9.7->nickyspatial) (0.1.7) Requirement already satisfied: pexpect>4.3 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipython<10->ipympl>=0.9.7->nickyspatial) (4.9.0) Requirement already satisfied: prompt_toolkit<3.1.0,>=3.0.41 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipython<10->ipympl>=0.9.7->nickyspatial) (3.0.48) Requirement already satisfied: pygments>=2.4.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipython<10->ipympl>=0.9.7->nickyspatial) (2.18.0) Requirement already satisfied: stack_data in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipython<10->ipympl>=0.9.7->nickyspatial) (0.6.3) Requirement already satisfied: typing_extensions>=4.6 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from ipython<10->ipympl>=0.9.7->nickyspatial) (4.12.2) Requirement already satisfied: MarkupSafe>=2.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from jinja2>=2.9->folium>=0.19.5->nickyspatial) (3.0.2) Requirement already satisfied: six>=1.5 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib>=3.10.1->nickyspatial) (1.17.0) Requirement already satisfied: altair<6,>=4.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (5.5.0) Requirement already satisfied: blinker<2,>=1.5.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (1.9.0) Requirement already satisfied: cachetools<6,>=4.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (5.5.2) Requirement already satisfied: protobuf<7,>=3.20 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (6.30.2) Requirement already satisfied: pyarrow>=7.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (20.0.0) Requirement already satisfied: tenacity<10,>=8.1.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (9.1.2) Requirement already satisfied: toml<2,>=0.10.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (0.10.2) Requirement already satisfied: gitpython!=3.1.19,<4,>=3.0.7 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (3.1.44) Requirement already satisfied: pydeck<1,>=0.8.0b4 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (0.9.1) Requirement already satisfied: tornado<7,>=6.0.3 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (6.4.2) Requirement already satisfied: charset_normalizer<4,>=2 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from requests->folium>=0.19.5->nickyspatial) (3.4.1) Requirement already satisfied: idna<4,>=2.5 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from requests->folium>=0.19.5->nickyspatial) (3.10) Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from requests->folium>=0.19.5->nickyspatial) (2.3.0) Requirement already satisfied: jsonschema>=3.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from altair<6,>=4.0->streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (4.23.0) Requirement already satisfied: gitdb<5,>=4.0.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from gitpython!=3.1.19,<4,>=3.0.7->streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (4.0.12) Requirement already satisfied: parso<0.9.0,>=0.8.4 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from jedi>=0.16->ipython<10->ipympl>=0.9.7->nickyspatial) (0.8.4) Requirement already satisfied: ptyprocess>=0.5 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from pexpect>4.3->ipython<10->ipympl>=0.9.7->nickyspatial) (0.7.0) Requirement already satisfied: wcwidth in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from prompt_toolkit<3.1.0,>=3.0.41->ipython<10->ipympl>=0.9.7->nickyspatial) (0.2.13) Requirement already satisfied: executing>=1.2.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from stack_data->ipython<10->ipympl>=0.9.7->nickyspatial) (2.1.0) Requirement already satisfied: asttokens>=2.1.0 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from stack_data->ipython<10->ipympl>=0.9.7->nickyspatial) (3.0.0) Requirement already satisfied: pure_eval in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from stack_data->ipython<10->ipympl>=0.9.7->nickyspatial) (0.2.3) Requirement already satisfied: smmap<6,>=3.0.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from gitdb<5,>=4.0.1->gitpython!=3.1.19,<4,>=3.0.7->streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (5.0.2) Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from jsonschema>=3.0->altair<6,>=4.0->streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (2024.10.1) Requirement already satisfied: referencing>=0.28.4 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from jsonschema>=3.0->altair<6,>=4.0->streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (0.35.1) Requirement already satisfied: rpds-py>=0.7.1 in /Users/rabinatwayana/Rabina/anaconda3/envs/obia/lib/python3.10/site-packages (from jsonschema>=3.0->altair<6,>=4.0->streamlit>=1.35.0->streamlit-folium>=0.24.1->nickyspatial) (0.22.3)
Summary¶
In this notebook we will perform following steps
- Load a sample raster image.
- Perform segmentation on the raster.
- Add NDVI feature.
- Define classes and sample collection
- Apply supervised classification using Random Forest Classifier
- Explore additional funtions: Merge_regions, Enclosed_by, Touched_by
import os
import requests
import matplotlib.pyplot as plt
import pandas as pd
from nickyspatial import (
LayerManager,
SlicSegmentation,
RuleSet,
attach_ndvi,
attach_shape_metrics,
attach_spectral_indices,
layer_to_raster,
layer_to_vector,
plot_classification,
plot_sample,
plot_layer,
plot_layer_interactive,
read_raster,
plot_layer_interactive_plotly,
MergeRuleSet,
EnclosedByRuleSet,
TouchedByRuleSet,
SupervisedClassifier,
Layer
)
output_dir = "output"
os.makedirs(output_dir, exist_ok=True)
data_dir = "data"
os.makedirs(data_dir, exist_ok=True)
raster_path = os.path.join(data_dir, "sample.tif")
if not os.path.exists(raster_path):
url = "https://github.com/kshitijrajsharma/nickyspatial/raw/refs/heads/master/data/sample.tif"
print(f"Downloading sample raster from {url}...")
response = requests.get(url)
response.raise_for_status() # Ensure the download succeeded
with open(raster_path, "wb") as f:
f.write(response.content)
print(f"Downloaded sample raster to {raster_path}")
else:
print(f"Using existing raster at: {raster_path}")
Using existing raster at: data/sample.tif
Reading the Raster¶
We now read the raster data and print some basic information about the image.
image_data, transform, crs = read_raster(raster_path)
print(f"Image dimensions: {image_data.shape}")
print(f"Coordinate system: {crs}")
Image dimensions: (4, 877, 1164) Coordinate system: EPSG:32654
Performing Segmentation¶
Here we perform multi-resolution segmentation. A LayerManager
is used to keep track of all layers created in the process. nickyspatial packages uses a layer object which is an underlying vector segmentation tied up to the raster , similar concept as layer in ecognition
manager = LayerManager()
segmenter = SlicSegmentation(scale=20, compactness=0.50)
segmentation_layer = segmenter.execute(
image_data,
transform,
crs,
layer_manager=manager,
layer_name="Base_Segmentation",
)
print("Segmentation layer created:")
print(segmentation_layer)
Number of segments: 2552 Segmentation layer created: Layer 'Base_Segmentation' (type: segmentation, parent: None, objects: 2543)
Visualizing Segmentation¶
We utilize the built-in plotting function to visualize the segmentation. The image will be displayed inline.
# plt.close("all")
# %matplotlib inline
fig1 = plot_layer(layer=segmentation_layer, image_data=image_data, rgb_bands=(3, 2, 1), show_boundaries=True, figsize=(10,8))
plt.show()
fig1.savefig(os.path.join(output_dir, "1_segmentation.png"))
Adding NDVI feature¶
segmentation_layer.attach_function(
attach_ndvi,
name="ndvi_stats",
nir_column="band_4_mean",
red_column="band_3_mean",
output_column="NDVI",
)
segmentation_layer.attach_function(attach_shape_metrics, name="shape_metrics")
<nickyspatial.core.layer.Layer at 0x150bfbf70>
Sample data collection¶
Using plotly package, interactive map is plotted to collect the segments_id(sample) for supervised classification.
Just Hover the mouse in the map, segment_id will be displayed.
plot_layer_interactive_plotly(segmentation_layer, image_data, rgb_bands=(3,2,1), show_boundaries=True, figsize=(900,600))
# Sample Data for Classification
# This section defines the sample data used for classification.
# Each class is assigned with a list of segment IDs and a specific color for visualization.
samples={
"Water": [102,384,659,1142,1662,1710,2113,2182,2481,1024],
"Builtup": [467,1102,1431,1984,1227,1736,774,1065],
"Vegetation": [832,1778,2035,1417,1263,242,2049,2397],
}
classes_color= {
"Water": "#3437c2",
"Builtup":"#de1421",
"Vegetation": "#0f6b2f"
}
Sample Data Visualization¶
In this steps, defined sample segment is visualized.
sample_objects = segmentation_layer.objects.copy()
sample_objects["classification"] = None
for class_name in samples.keys():
sample_objects.loc[sample_objects["segment_id"].isin(samples[class_name]), "classification"] = class_name
# Step 3: Wrap the modified GeoDataFrame back into a Layer
sample_layer = Layer(name="Sample Classification", type="classification")
sample_layer.objects = sample_objects
fig = plot_sample(
sample_layer,
image_data=image_data,
rgb_bands=(3,2,1),
transform=transform,
class_field="classification",
class_color=classes_color,
figsize=(10,8)
)
plt.show()
# To get the columns/features name if the segmenatation layer.
# This is useful to define the features list in the following supervised classification task
segmentation_layer.objects.columns
Index(['segment_id', 'area_pixels', 'area_units', 'geometry', 'band_1_mean', 'band_1_std', 'band_1_min', 'band_1_max', 'band_1_median', 'band_2_mean', 'band_2_std', 'band_2_min', 'band_2_max', 'band_2_median', 'band_3_mean', 'band_3_std', 'band_3_min', 'band_3_max', 'band_3_median', 'band_4_mean', 'band_4_std', 'band_4_min', 'band_4_max', 'band_4_median', 'NDVI', 'perimeter', 'shape_index', 'compactness'], dtype='object')
Supervised Classification using Random Forest Classifier¶
In this step, we will define and execute the supervised classification.
# Parameters for defining Random Forest Classifier
# Source: https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html
params={"n_estimators":100,
"oob_score":True,
"random_state":42,
}
# Define features based on which classifier performs the classification
features=['band_1_mean','band_1_std', 'band_2_mean', 'band_2_std', 'band_3_mean', 'band_3_std', 'band_4_mean', 'band_4_std','NDVI']
# Define supervised classifier and execute it
RF_classification=SupervisedClassifier(name="RF Classification", classifier_type="Random Forest", classifier_params=params)
RF_classification_layer, accuracy, feature_importances = RF_classification.execute(segmentation_layer,samples=samples,layer_manager=manager,layer_name="RF Classification",features=features)
print("OOB SCORE",accuracy)
# Plot classification result
fig4 = plot_classification(RF_classification_layer, class_field="classification", class_color=classes_color,figsize=(10,8))
# Plot feature importance graph
ig, ax = plt.subplots(figsize=(6, 4))
feature_importances.plot.bar(ax=ax)
ax.set_title("Importances")
ax.set_xlabel("Features")
ax.set_ylabel("Importance (%)")
plt.tight_layout()
plt.show()
OOB SCORE 1.0
Applying merge rule¶
In this step we will further refine the classification. In this example, we will merge region based on class value i.e. merge adjacent segments if they share the same class label.
merger = MergeRuleSet("Merge Segmentation")
class_value=["Water","Vegetation"]
merged_layer = merger.execute(
source_layer=RF_classification_layer,
class_column_name="classification",
class_value=class_value,
layer_manager=manager,
layer_name="Merged RF Classification",
)
fig4 = plot_classification(merged_layer, class_field="classification", class_color=classes_color,figsize=(10,8))
Applying Enclosed_by rule¶
This rule is also applied based on class label. This function determine whether a object/segment is completely contained/surrounded within/by another object or class and return the updated layer.
This function is very helpful in applying the context-aware rules in classification.
In this example, we define the new class "Urban Vegetation" if "Vegetation" is enclosed by "Builtup".
enclosed_by_rule = EnclosedByRuleSet()
enclosed_by_layer = enclosed_by_rule.execute(
source_layer=merged_layer,
class_column_name="classification",
class_value_a="Vegetation",
class_value_b="Builtup",
new_class_name="Urban Vegetation",
layer_manager=manager,
layer_name="enclosed_by_layer",
)
classes_color["Urban Vegetation"]="#84f547"
fig4 = plot_classification(enclosed_by_layer, class_field="classification", class_color=classes_color)
Applying Touched_by rule¶
This rule is also applied based on class labels. This determines whether an object/segment is in direct contact with another object or class — that is, they share a boundary.
This function is very useful in implementing context-aware rules in classification, especially when spatial relationships between features matter.
In this example, we define a new class "Builtup near WaterBodies" if "Builtup" is touchedBy "Water".
touched_by_rule = TouchedByRuleSet()
touched_by_layer = touched_by_rule.execute(
source_layer=enclosed_by_layer,
class_column_name="classification",
class_value_a="Builtup",
class_value_b="Water",
new_class_name="Builtup near WaterBodies",
layer_manager=manager,
layer_name="touched_by_layer",
)
classes_color["Builtup near WaterBodies"]="#1df0e2"
fig4 = plot_classification(touched_by_layer, class_field="classification", class_color=classes_color)
# Applying merge rule to generate the final merged segments
merge_rule = MergeRuleSet("MergeByVegAndType")
merged_layer2 = merger.execute(
source_layer=touched_by_layer,
class_column_name="classification",
class_value=["Builtup near WaterBodies","Builtup"],
layer_manager=manager,
layer_name="Merged RF Classification 2",
)
fig4 = plot_classification(merged_layer2, class_field="classification", class_color=classes_color)