1
1
import numpy as np
2
2
import os .path
3
+ import copy
3
4
from .PixelClassifier import PixelClassifier
4
5
from skimage .morphology import disk , dilation
5
6
from scipy .ndimage .filters import convolve
6
7
8
+ from sentinelhub import CustomUrlParam
9
+
7
10
from sklearn .externals import joblib
8
11
9
12
@@ -130,7 +133,9 @@ class CloudMaskRequest:
130
133
131
134
The user can then efficiently derive binary clouds masks based on a threshold.
132
135
133
- :param ogc_request: An instance of WmsRequest or WcsRequest (defined in sentinelhub-py package).
136
+ :param ogc_request: An instance of WmsRequest or WcsRequest (defined in sentinelhub-py package). The cloud mask
137
+ request creates a copy of this request and sets two custom url parameters: turns of the logo and
138
+ adds a request for transparency layer, which is used to determine the (non) valid data pixels.
134
139
:type ogc_request: data_request.WmsRequest or data_request.WcsRequest
135
140
:param threshold: Defines cloud and non-cloud in the binary cloud mask.
136
141
:type threshold: float
@@ -156,10 +161,21 @@ def __init__(self, ogc_request, *, threshold=0.4, average_over=4,
156
161
157
162
self .cloud_detector = S2PixelCloudDetector (threshold = threshold , average_over = average_over , all_bands = all_bands ,
158
163
dilation_size = dilation_size , model_filename = model_filename )
159
- self .ogc_bands_request = ogc_request
160
164
165
+ self .ogc_bands_request = copy .deepcopy (ogc_request )
166
+ # Add the transparency layer to the request
167
+ # Transparency layer is used to determine valid data points
168
+ if self .ogc_bands_request .custom_url_params is None :
169
+ self .ogc_bands_request .custom_url_params = {CustomUrlParam .SHOWLOGO : False ,
170
+ CustomUrlParam .TRANSPARENT : True }
171
+ else :
172
+ self .ogc_bands_request .custom_url_params .update ({CustomUrlParam .SHOWLOGO : False ,
173
+ CustomUrlParam .TRANSPARENT : True })
174
+
175
+ self .ogc_bands_request .create_request ()
161
176
self .bands = None
162
177
self .probability_masks = None
178
+ self .valid_data = None
163
179
164
180
def __len__ (self ):
165
181
return len (self .bands )
@@ -178,14 +194,19 @@ def get_dates(self):
178
194
"""
179
195
return self .ogc_bands_request .get_dates ()
180
196
181
- def get_probability_masks (self ):
197
+ def get_probability_masks (self , non_valid_value = 0 ):
182
198
"""
183
- Get probability maps of areas for each available date.
199
+ Get probability maps of areas for each available date. The pixels without valid data are assigned
200
+ non_valid_value.
201
+
202
+ :param non_valid_value: Value to be assigned to non valid data pixels
203
+
184
204
:return: np.ndarray
185
205
"""
186
206
if self .probability_masks is None :
187
207
self .get_data ()
188
- self .probability_masks = self .cloud_detector .get_cloud_probability_maps (np .array (self .bands ))
208
+ self .probability_masks = self .cloud_detector .get_cloud_probability_maps (self .bands )
209
+ self .probability_masks [self .valid_data == False ] = non_valid_value
189
210
return self .probability_masks
190
211
191
212
def get_data (self ):
@@ -194,11 +215,22 @@ def get_data(self):
194
215
:return: np.ndarray
195
216
"""
196
217
if self .bands is None :
197
- self .bands = self .ogc_bands_request .get_data ()
218
+ # last 'band' is the transperency layer
219
+ data = np .asarray (self .ogc_bands_request .get_data ())
220
+ self .bands = data [..., :- 1 ]
221
+ self .valid_data = (data [..., - 1 ] > 0.5 ).astype (np .bool )
198
222
return self .bands
223
+
224
+ def get_valid_data (self ):
225
+ """
226
+ Returns valid data mask.
227
+
228
+ :return: np.ndarray
229
+ """
199
230
200
- def get_cloud_masks (self , threshold = None ):
201
- """ The binary cloud mask is computed on the fly. Be cautious.
231
+ def get_cloud_masks (self , threshold = None , non_valid_value = False ):
232
+ """ The binary cloud mask is computed on the fly. Be cautious. The pixels without valid data are assigned
233
+ non_valid_value.
202
234
203
235
:param threshold: A float from [0,1] specifying threshold
204
236
:return: Binary cloud masks
@@ -218,4 +250,6 @@ def get_cloud_masks(self, threshold=None):
218
250
[dilation (cloud_mask , self .cloud_detector .dilation_filter ) for cloud_mask in cloud_masks ],
219
251
dtype = np .int8 )
220
252
253
+ cloud_masks [self .valid_data == False ] = non_valid_value
254
+
221
255
return cloud_masks
0 commit comments