0

I'm trying to create the Vegetation Condition Index with Landsat time series images in Earth Engine, but I get the error:

ImageCollection (Error) Error in map(ID=LC08_198032_20130813): Image.constant: Parameter 'value' is required.

Below is the script code, maybe something I was doing wrong at the section "//Create VCI index":

var l8collection = l8.filterDate('2013-04-01','2019-11-30').filterBounds(roi);
print(l8collection);

// Mask pixels with clouds and cloud shadows using the 'pixel_qa' band

var maskClouds = function(image){
// make a new single band image from the pixel qa band
  var pixel_qa = image.select('pixel_qa');
  // retain clear (0) and water (1) pixels
  return image.updateMask(pixel_qa.eq(322));   
};

// use "map" to apply the function to each image in the collection
var l8masked = l8collection.map(maskClouds);
print(l8masked);

// create function to add NDVI using NIR (B5) and the red band (B4)
var getNDVI = function(img1){
  return img1.addBands(img1.normalizedDifference(['B5','B4']).rename('NDVI'));
};

// map over image collection
var l8ndvi = l8masked.map(getNDVI);

// filter images not containing data in the study area
var filtered = l8ndvi.filter(ee.Filter.neq('count', 0));

print(filtered);

// Create VCI index
var vci = filtered.map(function(img){
 var id = img.id();
  var min =  img.reduceRegion({reducer: ee.Reducer.min(),geometry:roi, bestEffort:true, scale: 30}).get('NDVI');
 var max =  img.reduceRegion({reducer: ee.Reducer.max(),geometry:roi, bestEffort:true, scale: 30}).get('NDVI');
 var Index = img.expression("(NDVI-min)/(max-min)",
 {"NDVI" : img,"max" : ee.Number(max),"min" : ee.Number(min),})
 .rename('TCI')
 .copyProperties(img,['system:time_start','system:time_end']);
 return Index;
});
print(vci);
1

As Kevin Reid pointed out, the problem here is that the region reduction by min and/or max is resulting in null, which can occur when all the pixels in the region are masked. An alternative to reducing by count (as suggested) you can also pre-calculate min and max, add them as image properties and then filter on them to remove images from your collection that are null. This way you do not have to reduce the images an additional time for count. Here is an example script that illustrates the problem and provides a solution.

Code Editor script

/**
 * @license
 * Copyright 2019 Google LLC.
 * SPDX-License-Identifier: Apache-2.0
 */


// #############################################################################
// ### PROBLEM DEMO ###
// #############################################################################

// Define ROI.
var roi = ee.Geometry.Polygon(
  [[[-0.06057661456907226, 40.842476672518494],
    [-0.06057661456907226, 40.53424659065251],
    [0.36789018230592774, 40.53424659065251],
    [0.36789018230592774, 40.842476672518494]]], null, false);

// Import a sample image - set status.
var img = ee.Image('LANDSAT/LC08/C01/T1_SR/LC08_198032_20130813')
  .set('status', 'noMask');

// Make a copy that is all masked - set status.
var imgAllMasked = img.gt(1e7).selfMask().set('status', 'allMask');

// Put images together in an image collection.
var l8collection = ee.ImageCollection.fromImages([img, imgAllMasked]);

// Define a function to add NDVI using NIR (B5) and the red band (B4).
var getNDVI = function(img){
  return img.addBands(img.normalizedDifference(['B5','B4']).rename('NDVI'));
};

// Map NDVI function over the image collection.
var l8ndvi = l8collection.map(getNDVI);

// Subset just the 'allMask' image for testing with expression.
var allMasked = l8ndvi.filter('status == "allMask"').first();

// Define a combined reducer for min and max - one pass through the data.
var minMaxReducer = ee.Reducer.min().combine({
  reducer2: ee.Reducer.max(),
  sharedInputs: true
});

// Calculate regional min and max for the `allMasked` image.
var minMax =  allMasked.reduceRegion(
  {reducer: minMaxReducer, geometry:roi, bestEffort:true, scale: 30});

// Get the regional min and max NDVI values from the dictionary.
var min = minMax.get('NDVI_min');
var max = minMax.get('NDVI_max');
print('allMaskDemo min calc:', min); // null
print('allMaskDemo max calc:', max); // null

// Try using the expression function with null inputs; error occurs.
var allMaskDemo = allMasked.expression("(NDVI-min)/(max-min)", {
  "NDVI": allMasked,
  "max": ee.Number(max),
  "min": ee.Number(min),
});
print('allMaskDemo index calc:', allMaskDemo);



// #############################################################################
// ### SOLUTION ###
// #############################################################################

// Need to filter out all of the images that have null min or max region
// reductions. Map a function over the image collection that adds the min and
// max region reductions as image properties and then filter out the ones that
// are null.

// Calculate regional min and max and add as image properties.
l8ndvi = l8ndvi.map(function(img) {
  var minMax =  img.reduceRegion(
    {reducer: minMaxReducer, geometry:roi, bestEffort:true, scale: 30});
  return img.set({
    roi_min: minMax.get('NDVI_min'),
    roi_max: minMax.get('NDVI_max')
  });
});

// Filter out min and max region reductions that are null.
var filtered = l8ndvi
  .filterMetadata('roi_min', 'not_equals', null)
  .filterMetadata('roi_max', 'not_equals', null);

// Create VCI index.
var vci = filtered.map(function(img){
 var id = img.id();
 var max = img.getNumber('roi_max');
 var Index = img.expression("(NDVI-min)/(max-min)", {
    "NDVI": img.select('NDVI'),
    "min" : img.getNumber('roi_min'),
    "max" : img.getNumber('roi_max'),
 })
 .rename('VCI')
 .copyProperties(img,['system:time_start','system:time_end']);
 return Index;
});
print('After filtering null min and max:', vci);
| improve this answer | |
0

Here's how to understand the error message:

  • In Earth Engine, an argument being null is usually the same as it being omitted. Hence, a call to Image.constant with the value null will produce the error Image.constant: Parameter 'value' is required. This probably explains why you are getting this error despite not having written a misformed call to Image.constant.

  • But you don't have any Image.constant in your script, it seems. What you do have is img.expression("(NDVI-min)/(max-min)", ...) and you are passing in numbers. This implicitly creates a call to Image.constant to convert those numbers to constant images.

  • Therefore, we can conclude that either min or max were null. This could happen if for whatever reason there were no pixels intersecting the region of interest, so the minimum/maximum is undefined.

I confirmed this theory by using your reduceRegion parameters with ee.Reducer.count(): img.reduceRegion({reducer: ee.Reducer.count(),geometry:roi, bestEffort:true, scale: 30}) and replacing the image computation with returning a feature holding these counts in the properties. This showed that some of the selected images (may not be the same as yours, since I didn't use the same roi which you did not include in your question) had NDVI bands that had zero pixels counted.

In order to avoid this error, you can map to add the results of the reductions as properties to the features, filter out features with null values with ee.Filter.notNull, then map to compute the result you want (see Justin Braaten's answer for code).

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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