Code Example: Support Vector Machine Classification Using ENVITasks
This code example performs an end-to-end SVM classification using ENVITasks. It performs the following steps:
- Extracts an ENVIExamples object from an attribute image and training data ROIs.
- Normalizes the examples to a common range of data values.
- Shuffles the examples to create a random distribution of data.
- Splits the examples into training and evaluation sets.
- Uses an iterative trainer to train a SVM supervised classifier.
- Plots a loss profile.
- Prints a confusion matrix and accuracy metrics from the trained classifier.
- Runs the classifier.
- Displays the classification image.
Follow these steps to run the code example:
- Get the sample data files from our website or from the ENVI Resource DVD in the classification directory. Copy these files to your local drive.
- Copy and paste the code into the IDL Editor.
- Update the following lines to include the full path where you saved the sample data:
- file = 'AttributeImage.dat'
- ROIfile = 'TrainingDataROIs.xml'
- Update the following line to include the full path where you want to save the trained classifier:
- classifierURI = 'TrainedSVMClassifierTasks.epo'
- Save the file as SVMClassificationUsingTasks.pro.
- Compile and run the code.
PRO SVMClassificationUsingTasks
COMPILE_OPT IDL2
e = ENVI()
file = 'AttributeImage.dat'
raster = e.OpenRaster(file)
ROIfile = 'TrainingDataROIs.xml'
rois = e.OpenROI(ROIfile)
extractTask = ENVITask('ExtractExamplesFromRaster')
extractTask.INPUT_RASTER = raster
extractTask.INPUT_ROIS = rois
extractTask.Execute
outExamples = extractTask.OUTPUT_EXAMPLES
normalizeTask = ENVITask('ApplyGainOffsetToExamples')
normalizeTask.INPUT_EXAMPLES = outExamples
normalizeTask.Execute
gain = normalizeTask.OUTPUT_GAIN
offset = normalizeTask.OUTPUT_OFFSET
normalizedExamples = normalizeTask.OUTPUT_EXAMPLES
shuffleTask = ENVITask('ShuffleExamples')
shuffleTask.INPUT_EXAMPLES = normalizedExamples
shuffleTask.Execute
splitTask = ENVITask('SplitExamples')
splitTask.INPUT_EXAMPLES = shuffleTask.OUTPUT_EXAMPLES
splitTask.SPLIT_FRACTION = 0.8
splitTask.Execute
splitExamples = splitTask.OUTPUT_EXAMPLES
SVMTask = ENVITask('CreateSVMClassifier')
SVMTask.CLASS_NAMES = outExamples.CLASS_NAMES
SVMTask.NATTRIBUTES = outExamples.NATTRIBUTES
SVMTask.NCLASSES = outExamples.NCLASSES
SVMTask.Execute
iterativeTask = ENVITask('CreateIterativeTrainer')
iterativeTask.CONVERGENCE_CRITERION = 0.0001
iterativeTask.MAXIMUM_ITERATIONS = 1
iterativeTask.Execute
trainTask = ENVITask('TrainClassifier')
trainTask.CLASSIFIER = SVMTask.OUTPUT_CLASSIFIER
trainTask.EXAMPLES = splitExamples[0]
trainTask.TRAINER = iterativeTask.OUTPUT_TRAINER
trainTask.Execute
classifier = trainTask.TRAINED_CLASSIFIER
classifierURI = 'TrainedSVMClassifierTasks.epo'
classifier.Save, URI=classifierURI
evaluateTask = ENVITask('EvaluateClassifier')
evaluateTask.CLASSIFIER = classifier
evaluateTask.EXAMPLES = splitExamples[1]
evaluateTask.Execute
confusionMatrix = evaluateTask.OUTPUT_CONFUSION_MATRIX
Print, confusionMatrix
columnTotals = confusionMatrix.ColumnTotals()
FOR i=0, (SVMTask.NCLASSES)-1 DO $
Print, 'Ground truth total for ', $
SVMTask.CLASS_NAMES[i],': ', $
columnTotals[i]
rowTotals = confusionMatrix.RowTotals()
FOR i=0, (SVMTask.NCLASSES)-1 DO $
Print, 'Predicted total for ', $
SVMTask.CLASS_NAMES[i],': ', $
rowTotals[i]
accuracy = confusionMatrix.Accuracy()
Print, 'Overall accuracy: ', accuracy
kappa = confusionMatrix.KappaCoefficient()
Print, 'Kappa coefficient: ', kappa
commissionError = confusionMatrix.CommissionError()
Print, 'Error of commission: ', commissionError
omissionError = confusionMatrix.OmissionError()
Print, 'Error of omission: ', omissionError
F1 = confusionMatrix.F1()
Print, 'F1 value: ', F1
precision = confusionMatrix.Precision()
Print, 'Precision: ', precision
producerAccuracy = confusionMatrix.ProducerAccuracy()
Print, 'Producer accuracy: ', producerAccuracy
recall = confusionMatrix.Recall()
Print, 'Recall: ', recall
userAccuracy = confusionMatrix.UserAccuracy()
Print, 'User accuracy: ', userAccuracy
applyGainOffsetTask = ENVITask('ApplyGainOffset')
applyGainOffsetTask.GAIN = gain
applyGainOffsetTask.OFFSET = offset
applyGainOffsetTask.INPUT_RASTER = raster
applyGainOffsetTask.Execute
normalizedRaster = applyGainOffsetTask.OUTPUT_RASTER
classifyTask = ENVITask('ClassifyRaster')
classifyTask.CLASSIFIER = classifier
classifyTask.INPUT_RASTER = normalizedRaster
classifyTask.Execute
classRaster = classifyTask.OUTPUT_RASTER
view = e.GetView()
layer = view.CreateLayer(raster)
layer2 = view.CreateLayer(classRaster)
view.Zoom, /FULL_EXTENT
END
This code saves the trained classifier to a binary file named TrainedSVMClassifierTasks.epo. You can apply this classifier to other similar datasets that have the same attributes and data representation. The following example shows how to do this.
- Get the sample data file (AttributeImage2.dat) from our website or from the ENVI Resource DVD in the classification directory. Copy this file to your local drive.
- Copy and paste the code into the IDL Editor.
- Update the following line to include the full path where you saved the sample data:
- file = 'AttributeImage2.dat'
- Update the following line to include the full path where you saved the trained classifier:
- trainedClassifierURI = 'TrainedSVMClassifierTasks.epo'
- Save the file as ApplySVMTrainedClassifierTasks.pro.
- Compile and run the code.
Tip: The classified image in this example overlaps with the image in the first example. As long as the ENVI application is still open from the first example, you can compare the results where they overlap. The classification results in the overlapping region will not be exactly the same because the attribute values are different in each image; however, the results should be similar.
PRO ApplySVMTrainedClassifierTasks
COMPILE_OPT IDL2
e = ENVI()
file = 'AttributeImage2.dat'
raster = e.OpenRaster(file)
gain = [0.68837909, 0.039032014, 1.3670539, $
1.2792631, 1.2774655, 1.0320982]
offset = [-0.14015123, -0.13057724, -0.12848703, $
-0.16770373, -0.18784684, -0.28932331]
normalizedRaster = ENVIGainOffsetRaster(raster, gain, offset)
trainedClassifierURI = 'TrainedSVMClassifierTasks.epo'
trainedClassifier = ENVIRestoreObject(trainedClassifierURI)
classifyTask = ENVITask('ClassifyRaster')
classifyTask.CLASSIFIER = trainedClassifier
classifyTask.INPUT_RASTER = normalizedRaster
classifyTask.Execute
classRaster = classifyTask.OUTPUT_RASTER
numClasses = classRaster.Metadata['Classes']
classNames = classRaster.Metadata['Class Names']
view = e.GetView()
layer = view.CreateLayer(raster)
layer2 = view.CreateLayer(classRaster)
view.Zoom, /FULL_EXTENT
END
You can optionally use ENVICalculateConfusionMatrixFromRasterTask to evaluate the classifier. This function takes in a classification raster and training ROIs, and it calculates a confusion matrix and accuracy metrics. Add the following lines of code to the previous code example, after classifying the attribute image and before displaying the results. Update the ROIfile variable to include the full path where you saved the sample data:
ROIfile = 'TrainingDataROIs.xml'
rois = e.OpenROI(ROIfile)
evaluateTask = ENVITask('CalculateConfusionMatrixFromRaster')
evaluateTask.INPUT_RASTER = classRaster
evaluateTask.INPUT_ROIS = rois
evaluateTask.Execute
confusionMatrix = evaluateTask.OUTPUT_CONFUSION_MATRIX
Print, confusionMatrix.Confusion_Matrix
columnTotals = confusionMatrix.ColumnTotals()
FOR i=0, (numClasses)-1 DO $
Print, 'Ground truth total for ', $
classNames[i],': ', $
columnTotals[i]
rowTotals = confusionMatrix.RowTotals()
FOR i=0, (numClasses)-1 DO $
Print, 'Predicted total for ', $
classNames[i],': ', $
rowTotals[i]
accuracy = confusionMatrix.Accuracy()
Print, 'Overall accuracy: ', accuracy
kappa = confusionMatrix.KappaCoefficient()
Print, 'Kappa coefficient: ', kappa
commissionError = confusionMatrix.CommissionError()
Print, 'Error of commission: ', commissionError
omissionError = confusionMatrix.OmissionError()
Print, 'Error of omission: ', omissionError
F1 = confusionMatrix.F1()
Print, 'F1 value: ', F1
precision = confusionMatrix.Precision()
Print, 'Precision: ', precision
producerAccuracy = confusionMatrix.ProducerAccuracy()
Print, 'Producer accuracy: ', producerAccuracy
recall = confusionMatrix.Recall()
Print, 'Recall: ', recall
userAccuracy = confusionMatrix.UserAccuracy()
Print, 'User accuracy: ', userAccuracy