-
Notifications
You must be signed in to change notification settings - Fork 3
/
cloudMasking.js
95 lines (77 loc) · 2.66 KB
/
cloudMasking.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Generate a binary cloud mask from a cloud probability image
exports.generateCloudMask = function (probability, probabilityThreshold) {
return probability.gt(probabilityThreshold);
};
// Generate a binary shadow mask from a cloud mask of an image by looking for dark pixels near clouds.
exports.generateShadowMask = function (
img,
cloudMask,
shadowNIR,
shadowDist,
solarAzimuth,
scale
) {
// Identify potential shadows
var darkMask = img.select("B8").lt(shadowNIR);
// If no azimuth is provided, try to pull it from the image properties
solarAzimuth = solarAzimuth
? solarAzimuth
: ee.Number(img.get("MEAN_SOLAR_AZIMUTH_ANGLE"));
var shadowAz = ee.Number(90).subtract(solarAzimuth);
// Get the potential location of shadows based on cloud location
var shadowProj = cloudMask
.directionalDistanceTransform(shadowAz, shadowDist * 10)
.reproject({ crs: img.select(0).projection(), scale: scale })
.select("distance")
.mask();
return shadowProj.multiply(darkMask);
};
// Apply morphological closing to remove small groups of pixels in a binary mask
exports.cleanMask = function (mask, bufferDist, scale) {
var cleaned = mask.focal_max((2 * bufferDist) / scale).focal_min(2);
return cleaned;
};
// Mask clouds and shadows in Sentinel-2 imagery using a cloud probability image.
exports.probabilityCloudMask = function (
img,
probability,
probabilityThreshold,
bufferDist,
scale,
maskShadow,
shadowNIR,
shadowDist
) {
probabilityThreshold = probabilityThreshold ? probabilityThreshold : 30;
bufferDist = bufferDist ? bufferDist : 15;
scale = scale ? scale : img.select(0).projection().nominalScale();
maskShadow = maskShadow ? maskShadow : false;
shadowNIR = shadowNIR ? shadowNIR : 1000;
shadowDist = shadowDist ? shadowDist : 10;
var cloudMask = exports.generateCloudMask(probability, probabilityThreshold);
var shadowMask = exports.generateShadowMask(
img,
cloudMask,
shadowNIR,
shadowDist,
scale
);
var cloudAndShadowMask = cloudMask.add(shadowMask).gt(0);
if (maskShadow) {
var mask = cloudAndShadowMask.eq(0);
} else {
mask = cloudMask.eq(0);
}
mask = exports.cleanMask(mask, bufferDist, scale);
return img.mask(mask);
};
// A fast implementation of cloud masking that uses a simple binary cloud mask, such as the
// QA60 band in Sentinel-2 imagery to mask clouds.
exports.simpleCloudMask = function (img, maskBand) {
maskBand = maskBand ? maskBand : "QA60";
if (!img.bandNames().contains(maskBand).getInfo()) {
throw 'Image does not contain a band called "' + maskBand + '".';
}
var cloudMask = img.select(maskBand).eq(0);
return img.mask(cloudMask);
};