Skip To Content ArcGIS for Developers Sign In Dashboard

ArcGIS API for Python

Image Classification and Segmentation

Introduction

Image segmentation and classification are very important topics in GIS and remote sensing applications. Both approaches are to extracting features from imagery based on objects. Segmentation groups pixels in close proximity and having similar spectral characteristics into a segment, which doesn't need any training data and is considered as unsupervised learning. In contrast, image classification is a type of supervised learning which classifies each pixel to a class in the training data. In this guide, we are going to demonstrate both techniques using ArcGIS API for Python.

In [18]:
import arcgis
from arcgis import GIS
from arcgis.raster.analytics import *
from arcgis.features import FeatureSet, FeatureCollection
In [19]:
gis = GIS(profile="your_enterprise_profile")

Classification

In this example, we are going to perfrom a land cover classification using a Landsat image in Iowa and hand labelled training data. In the training data, there are four classes in total: Developed Area, Forest, Planted/Cultivated, and Water.

First, let's draw the training data on a map and visualize it.

In [20]:
items1 = gis.content.search("training_samples", item_type="Feature Layer")
items1[0]
Out[20]:
training_samples
training sample used for raster classification guideFeature Layer Collection by api_data_owner
Last Modified: July 30, 2019
0 comments, 15 views
In [28]:
map1 = gis.map('Iowa')
map1
In [21]:
defined_extent = {'spatialReference': {'latestWkid': 3857, 'wkid': 102100},
                  'xmin': -10357358.3716515,
                  'ymin': 5063187.75726388,
                  'xmax': -10340267.8481094,
                  'ymax': 5075204.7581259}
In [ ]:
map1.extent = defined_extent
map1.add_layer(items1[0])
In [15]:
map1.legend = True

We need to convert the training sample feature class into JSON format, which is the format the image classification requires.

In [23]:
query_result = items1[0].layers[0].query()
training_sample_json = query_result.to_json

Now let's search for Landsat data that will be used for image classification.

In [24]:
items2 = gis.content.search("title: multispectral landsat", item_type="Imagery Layer", outside_org=True) 
items2[0]
Out[24]:
Multispectral Landsat
Landsat 8 OLI, 30m multispectral and multitemporal 8-band imagery, with on-the-fly renderings and indices. This imagery layer is sourced from the Landsat on AWS collections and is updated daily with new imagery.Imagery Layer by esri_livingatlas
Last Modified: April 23, 2019
0 comments, 2 views
In [25]:
landsat_layer = items2[0].layers[0]

Set the analysis extent to a small region in Iowa so we don't process all landsat images.

In [26]:
arcgis.env.verbose = True
arcgis.env.analysis_extent = defined_extent

We can retrieve a landsat scene by OBJECTID.

In [27]:
filtered_layer = landsat_layer.filter_by('OBJECTID=3134102')

With the Landsat layer and the training samples, we are now ready to train a support vector machine (SVM) model.

In [30]:
classifier_definition = train_classifier(input_raster=filtered_layer, 
                                         input_training_sample_json=training_sample_json, 
                                         classifier_parameters={"method":"svm", 
                                                                "params":{"maxSampleClass":500}},
                                         gis=gis)
Submitted.
Executing...
Start Time: Tuesday, November 19, 2019 10:02:48 AM
Running script TrainClassifier...
Prepare training feature.
DEBUG: {'method': 'svm', 'params': {'maxSampleClass': 500}}
Training...
Succeeded at Tuesday, November 19, 2019 10:03:31 AM (Elapsed Time: 43.48 seconds)

If we print out classifier_definition, we can see that it contains information such as number of classes and coefficients that define the SVM model.

In [31]:
classifier_definition["Definitions"][0]["Classes"]
Out[31]:
[{'ClassValue': 10,
  'ClassName': 'Water',
  'Red': 84,
  'Green': 117,
  'Blue': 168},
 {'ClassValue': 20,
  'ClassName': 'Developed',
  'Red': 232,
  'Green': 209,
  'Blue': 209},
 {'ClassValue': 40,
  'ClassName': 'Forest',
  'Red': 133,
  'Green': 199,
  'Blue': 126},
 {'ClassValue': 80,
  'ClassName': 'Planted / Cultivated',
  'Red': 251,
  'Green': 246,
  'Blue': 93}]

Now we have the model, we are ready to apply the model to a landsat image to make prediction.

In [33]:
from arcgis.raster.analytics import classify

classified_output = classify(input_raster=filtered_layer,
                             input_classifier_definition=classifier_definition)
classified_output
Submitted.
Executing...
Start Time: Tuesday, November 19, 2019 10:04:38 AM
Running script Classify...
Image service {'name': 'Classify_FHAX9B', 'serviceUrl': 'https://datascienceqa.esri.com/server/rest/services/Hosted/Classify_FHAX9B/ImageServer'} already existed.
Classifying...
Finished
Updating service with data store URI.
Getting image service info...
Updating service: https://dev0002085.esri.com:6443/arcgis/admin/services/Hosted/Classify_FHAX9B.ImageServer/edit
Update item service: https://dev0002085.esri.com:6443/arcgis/admin/services/Hosted/Classify_FHAX9B.ImageServer successfully.
Succeeded at Tuesday, November 19, 2019 10:04:49 AM (Elapsed Time: 10.79 seconds)
Out[33]:
Classify_FHAX9B
Analysis Image Service generated from ClassifyImagery Layer by portaladmin
Last Modified: November 19, 2019
0 comments, 0 views

Now let's visualize the classification result and compare it with the original Landsat image.

In [17]:
map2 = gis.map('Iowa') # shows the Landsat layer
map2