2

I am trying to do an unsupervised classification in GEE using Sentinel-2 drone imagery for training and classification and high-resolution drone data as a visual reference. When I define my training dataset, I get the following error message:

K-means Unsupervised classifier: Layer error: No data was found in training input.

All the code below, which contains a successful supervised classification (the unsupervised classification is at the very bottom). My GEE script is here: https://code.earthengine.google.com/e6ff079a2b440208c4309d87e0d3f501

//Here I try land classification using sentinel 2 imagery to train
//and drone imagery as a visual reference

//Load s2 data
var s2 = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED")

var pointKT = ee.Geometry.Point([92.1635,21.2127]); 
Map.centerObject(pointKT); 
Map.addLayer(campBoundaries, {}, "Camp Boundaries"); 

// Mask out the black background from Camp 4
var mask = Camp4.select('b1').neq(1).and(Camp4.select('b2').neq(1)).and(Camp4.select('b3').neq(1));
var Camp4Masked = Camp4.updateMask(mask);


// Function to remove the b4 band if it exists
var removeExtraBand = function(image) {
  var bands = image.bandNames();
  return bands.contains('b4') ? image.select(['b1', 'b2', 'b3']) : image;
};

//Apply the function to drone2019
var drone2019Uniform = drone2019.map(removeExtraBand);

//Load the 2019 imagery as a mosiac.
var mosiacDrone2019 = drone2019Uniform.mosaic();


// Combine the rest of the camps and the masked Camp 4 as a mosiac. Then map it.
var combinedMosaic = ee.ImageCollection([mosiacDrone2019, Camp4Masked]).mosaic();
Map.addLayer(combinedMosaic, {}, 'NPM Drone Imagery 2019 (Released July 2019)');

//Date range.
var startDate= '2018-10-01'; // Start date for the drone period
var endDate = '2019-05-01'; // End date for the drone period
//Note I added more months of data to improve quality due to cloud cover

//Cloud cover mask
function cloudMask(KTimage){
    var scl = KTimage.select('SCL'); //Scene classification layer.
    var mask = scl.eq(3).or(scl.gte(7).and(scl.lte(10)));
    return KTimage.updateMask(mask.eq(0));
}

var KTimage = s2
              .filterBounds(pointKT)
              .filterDate(startDate,endDate)
              .map(cloudMask)
              .median();

//Get a preliminary map
Map.addLayer(KTimage, {
  bands:['B4','B3','B2'], 
  min:0, 
  max: [3000]
},'True Colour April-May');

//NDVI
var ndvi = KTimage.normalizedDifference(['B8','B4']);

var vegPalette = ['red', 'white', 'green'];

//Masked NDVI layer
Map.addLayer(ndvi, {
  min: -1,
  max: 1,
  palette: vegPalette
}, 'NDVI April-May');
  


///////////////////////////////////////////////////////////////////////////
//Classification process begins:

// Combine training feature collections.
var trainingFeatures = ee.FeatureCollection([
    vegetation, bare, settlement, water
]).flatten();

// Define prediction bands.
// Left some bands out (aerosols, clouds, etc. See documentation)
var predictionBands = [
    'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8',
    'B8A', 'B11', 'B12'
];

// 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8',
//    'B8A', 'B9', 'B11', 'B12'

// Sample training points.
var classifierTraining =  KTimage.select(predictionBands)
    .sampleRegions({
        collection: trainingFeatures,
        properties: ['class'],
        scale: 10
    });
    
    
print(classifierTraining);

//////////////// CART Classifier ///////////////////

// Train a CART Classifier.
var classifier = ee.Classifier.smileCart().train({
    features: classifierTraining,
    classProperty: 'class',
    inputProperties: predictionBands
});

// Classify the Landsat image.
var classified = KTimage.select(predictionBands).classify(classifier);

// Define classification image visualization parameters.
var classificationVis = {
    min: 0,
    max: 3,
    palette: ['38761d', 'ffff52', 'ff0004', '0000ff']
};
// vegatation, bare soil, built-up, water.

// Add the classified image to the map.
Map.addLayer(classified, classificationVis, 'CART classified');

/////////////// Random Forest Classifier /////////////////////

// Train RF classifier.
var RFclassifier = ee.Classifier.smileRandomForest(50).train({
    features: classifierTraining,
    classProperty: 'class',
    inputProperties: predictionBands
});

// Classify Landsat image.
var RFclassified = KTimage.select(predictionBands).classify(
    RFclassifier);

// Add classified image to the map.
Map.addLayer(RFclassified, classificationVis, 'RF classified');

/////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////
///////////////////////////////////////////////////////
/////Unsupervised Classification
///////////////////////////////////////////////////////

//Instead of selecting training points, this approach lets the algrithm find clusters in the data

//K means clusterer

var region = campBoundaries.geometry();


//Define the training dataset
var training = KTimage.sample({
  region: region,
  scale: 10,
  numPixels: 1000,
  tileScale: 4,
  dropNulls: true
});

//Set up the clusterer and train it
var clusterer = ee.Clusterer.wekaKMeans(4).train(training);

//Cluster the input using the trained clusterer
var Kclassified = KTimage.cluster(clusterer)

//Display the clusters with random colours
Map.addLayer(Kclassified.randomVisualizer(),{},'K-means Unsupervised classifier')

//After classifying, mask settlements and farmland. Then export individual layers by class


1 Answer 1

4

When using .sample() it drops all features that intersect masked pixels. This happened in your case as your image contains non relevant bands and some masked bands: MSK_CLASSI_OPAQUE, MSK_CLASSI_CIRRUS, and MSK_CLASSI_SNOW_ICE. See the documentation here

Samples the pixels of an image, returning them as a FeatureCollection. Each feature will have 1 property per band in the input image. Note that the default behavior is to drop features that intersect masked pixels, which result in null-valued properties (see dropNulls argument).

You need to select the bands in your image to include only unmasked and meaningful variables to your classification. That applies to all your classifiers

var bands = ['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9','B11','B12']

//Define the training dataset
var training = KTimage.select(bands).sample({
  region: region,
  scale: 10,
  numPixels: 1000,
 tileScale: 4,
 dropNulls: true
});
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.