This is the GEE script I used to show a cassification product. https://code.earthengine.google.com/21603a6e19f76d8c121a4dd9000ebee4
The resulting map in GEE is clipped correctly to the border that I imported as an asset:
var table = ee.FeatureCollection("users/parivash89/Canopy_Height_Product/pnp_perimeter_Basilicata");
//Import the boundaries of the Park
var Park_Border = ee.FeatureCollection(table);
var Park_Border_Vis = Park_Border.style({
color: 'ff2525',
width: 3,
lineType: 'solid',
fillColor: '00000000',
});
Map.addLayer(Park_Border_Vis, null, 'Park Area');
Map.centerObject(Park_Border, 11);
////Earth Engine Snippet
//var canopy_ht = ee.ImageCollection("projects/meta-forest-monitoring-okw37/assets/CanopyHeight");
////How many frames are available in the canopy worldwide
//print(canopy_ht);
//If we want a single mosaic for all worldwide connecting all frames together into a single image
var canopy_ht_mosaic = ee.ImageCollection("projects/meta-forest-monitoring-okw37/assets/CanopyHeight").mosaic();
//print(canopy_ht_mosaic);
Map.addLayer(canopy_ht_mosaic.clip(Park_Border),[], 'canopy_ht_mosaic');
//Histogram of Canopy height frequency
print(
ui.Chart.image.histogram(canopy_ht_mosaic,Park_Border,11)
);
//Non-forest pixels Removal (pixels with value=0)
var canopy_threshold = canopy_ht_mosaic.gt(0);
var forest = canopy_ht_mosaic.updateMask(canopy_threshold);
Map.addLayer(forest.clip(Park_Border),[],'Forest');
print(
ui.Chart.image.histogram(forest,Park_Border,20)
);
//Avg, Max, Min Value of canopy height
var canopy_mean = forest.reduceRegion({
reducer: ee.Reducer.mean(), geometry:Park_Border, scale: 11
}).values().get(0);
print(canopy_mean, 'Canopy_MEAN');
var canopy_max = forest.reduceRegion({
reducer: ee.Reducer.max(), geometry:Park_Border, scale: 11
}).values().get(0);
print(canopy_max, 'Canopy_MAX');
var canopy_min = forest.reduceRegion({
reducer: ee.Reducer.min(), geometry:Park_Border, scale: 11
}).values().get(0);
print(canopy_min, 'Canopy_MIN');
//By downloading the CSV of the 'Canopy_MAX' histogram, we see that there are only two pixels related to the maximum values of 31 meteres. For a more realistic solution to get the max value according to the frequency:
var canopy_percentile99 = forest.reduceRegion({
reducer: ee.Reducer.percentile([99]), geometry:Park_Border, scale: 11
}).values().get(0);
print(canopy_percentile99, 'Canopy_Percentile99');
//99% of the Max canopy height according to the frequency is 20 meters.
//Classification by the thresholding technqiue
var cons = ee.Image.constant(0);
var class1 = cons.where(forest.lt(5), 1);
var class2 = class1.where(forest.gte(5).and(forest.lt(10)), 2);
var class3 = class2.where(forest.gte(10).and(forest.lt(15)), 3);
var class4 = class3.where(forest.gte(15).and(forest.lt(20)), 4);
var class5 = class4.where(forest.gte(20).and(forest.lt(25)), 5);
var class6 = class5.where(forest.gte(25).and(forest.lt(30)), 6);
var class7 = class6.where(forest.gte(30), 7);
Map.addLayer(class7.clip(Park_Border),{min:0, max:7, palette:['#64481a','#e8a73c','#c1ffb8','#87ff93','#00fb30','#00b92c','#009323','#006e1a']},'Class7'); //All the pixel where canopy height is 0 < x < 5 are shown in white
//Add a legend
// set position of panel
var legend = ui.Panel({
style: {
position: 'bottom-left',
padding: '8px 15px'
}
});
// Create legend title
var legendTitle = ui.Label({
value: 'Canopy Height Classified',
style: {
fontWeight: 'bold',
fontSize: '18px',
margin: '0 0 4px 0',
padding: '0'
}
});
// Add the title to the panel
legend.add(legendTitle);
// Creates and styles 1 row of the legend.
var makeRow = function(color, name) {
// Create the label that is actually the colored box.
var colorBox = ui.Label({
style: {
backgroundColor: '#' + color,
// Use padding to give the box height and width.
padding: '10px',
margin: '0 0 4px 0'
}
});
// Create the label filled with the description text.
var description = ui.Label({
value: name,
style: {margin: '0 0 4px 6px'}
});
// return the panel
return ui.Panel({
widgets: [colorBox, description],
layout: ui.Panel.Layout.Flow('horizontal')
});
};
// Identify Palette with the legend colors
var palette =[
'64481a',
'e8a73c',
'c1ffb8',
'87ff93',
'00fb30',
'00b92c',
'009323',
'006e1a'
];
// Identify names with the legend
var names = ['H<5','5<H<10','10<H<15','15<H<20','20<H<25','25<H<30','H>30'];
// Add color and and names
for (var i = 0; i < 7; i++) {
legend.add(makeRow(palette[i], names[i]));
}
// add legend to map (alternatively you can also print the legend to the console)
Map.add(legend);
Export.image.toDrive({
image: forest,
description: 'Canopy_Height_PollinoPark_Basilicata',
scale: 1,
maxPixels: 1e13,
region: Park_Border.geometry(),
crs: 'EPSG:32633',
folder: 'Pollino_Park'
});
/*
var visualization = class7.visualize({
min:0,
max:7,
palette:['#64481a','#e8a73c','#c1ffb8','#87ff93','#00fb30','#00b92c','#009323','#006e1a']
});*/
Export.image.toDrive({
image: class7,
description: 'Canopy_Height_Classified_PollinoPark_Basilicata',
scale: 1,
maxPixels: 1e13,
region: Park_Border,
crs: 'EPSG:32633',
folder: 'Pollino_Park'
});
When I export this map to QGIS 3.26.1, it is not clipped to the area (shown in red):
In the Symbology tab, if I remove class 0, the area outside of the border gets deleted, but also some values inside the map.
I tried adding .clip()
to the image: class7
and also adding .geometry()
to the region: Park_Border
part of the script because I found these solutions in another post but it did not work.