|
|
@ -26,6 +26,7 @@ import skimage.transform as transform
|
|
|
|
import sklearn.decomposition as decomposition
|
|
|
|
import sklearn.decomposition as decomposition
|
|
|
|
import skimage.measure as measure
|
|
|
|
import skimage.measure as measure
|
|
|
|
import skimage.morphology as morphology
|
|
|
|
import skimage.morphology as morphology
|
|
|
|
|
|
|
|
from sklearn.cluster import KMeans
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# import own modules
|
|
|
|
# import own modules
|
|
|
@ -605,3 +606,75 @@ def convert_epsg(points, epsg_in, epsg_out):
|
|
|
|
raise
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
return points_converted
|
|
|
|
return points_converted
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def classify_sand_unsupervised(im_ms_ps, im_pan, cloud_mask, wl_pix, buffer_size, min_beach_size, plot_bool):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Classifies sand pixels using an unsupervised algorithm (Kmeans)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KV WRL 2018
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
-----------
|
|
|
|
|
|
|
|
im_ms_ps: np.ndarray
|
|
|
|
|
|
|
|
Pansharpened RGB + downsampled NIR and SWIR
|
|
|
|
|
|
|
|
im_pan:
|
|
|
|
|
|
|
|
Panchromatic band
|
|
|
|
|
|
|
|
cloud_mask: np.ndarray
|
|
|
|
|
|
|
|
2D cloud mask with True where cloud pixels are
|
|
|
|
|
|
|
|
wl_pix: list of np.ndarray
|
|
|
|
|
|
|
|
list of arrays containig the pixel coordinates of the water line
|
|
|
|
|
|
|
|
buffer_size: int
|
|
|
|
|
|
|
|
radius of the disk used to create a buffer around the water line
|
|
|
|
|
|
|
|
min_beach_size: int
|
|
|
|
|
|
|
|
minimum number of connected pixels belonging to a single beach
|
|
|
|
|
|
|
|
plot_bool: boolean
|
|
|
|
|
|
|
|
True if plot is wanted
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Returns: -----------
|
|
|
|
|
|
|
|
im_sand: np.ndarray
|
|
|
|
|
|
|
|
2D binary image containing True where sand pixels are located
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
# reshape the 2D images into vectors
|
|
|
|
|
|
|
|
vec_ms_ps = im_ms_ps.reshape(im_ms_ps.shape[0] * im_ms_ps.shape[1], im_ms_ps.shape[2])
|
|
|
|
|
|
|
|
vec_pan = im_pan.reshape(im_pan.shape[0]*im_pan.shape[1])
|
|
|
|
|
|
|
|
vec_mask = cloud_mask.reshape(im_ms_ps.shape[0] * im_ms_ps.shape[1])
|
|
|
|
|
|
|
|
# add B,G,R,NIR and pan bands to the vector of features
|
|
|
|
|
|
|
|
vec_features = np.zeros((vec_ms_ps.shape[0], 5))
|
|
|
|
|
|
|
|
vec_features[:,[0,1,2,3]] = vec_ms_ps[:,[0,1,2,3]]
|
|
|
|
|
|
|
|
vec_features[:,4] = vec_pan
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# create binary image with ones where the detected water lines is
|
|
|
|
|
|
|
|
im_buffer = np.zeros((im_ms_ps.shape[0], im_ms_ps.shape[1]))
|
|
|
|
|
|
|
|
for i, contour in enumerate(wl_pix):
|
|
|
|
|
|
|
|
indices = [(int(_[0]), int(_[1])) for _ in list(np.round(contour))]
|
|
|
|
|
|
|
|
for j, idx in enumerate(indices):
|
|
|
|
|
|
|
|
im_buffer[idx] = 1
|
|
|
|
|
|
|
|
# perform a dilation on the binary image
|
|
|
|
|
|
|
|
se = morphology.disk(buffer_size)
|
|
|
|
|
|
|
|
im_buffer = morphology.binary_dilation(im_buffer, se)
|
|
|
|
|
|
|
|
vec_buffer = (im_buffer == 1).reshape(im_ms_ps.shape[0] * im_ms_ps.shape[1])
|
|
|
|
|
|
|
|
# add cloud mask to buffer
|
|
|
|
|
|
|
|
vec_buffer= np.logical_and(vec_buffer, ~vec_mask)
|
|
|
|
|
|
|
|
# perform kmeans (6 clusters)
|
|
|
|
|
|
|
|
kmeans = KMeans(n_clusters=6, random_state=0).fit(vec_features[vec_buffer,:])
|
|
|
|
|
|
|
|
labels = np.ones((len(vec_mask))) * np.nan
|
|
|
|
|
|
|
|
labels[vec_buffer] = kmeans.labels_
|
|
|
|
|
|
|
|
im_labels = labels.reshape(im_ms_ps.shape[0], im_ms_ps.shape[1])
|
|
|
|
|
|
|
|
# find the class with maximum reflection in the B,G,R,Pan
|
|
|
|
|
|
|
|
im_sand = im_labels == np.argmax(np.mean(kmeans.cluster_centers_[:,[0,1,2,4]], axis=1))
|
|
|
|
|
|
|
|
im_sand = morphology.remove_small_objects(im_sand, min_size=min_beach_size, connectivity=2)
|
|
|
|
|
|
|
|
# im_sand = morphology.binary_dilation(im_sand, morphology.disk(1))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if plot_bool:
|
|
|
|
|
|
|
|
im = np.copy(im_ms_ps)
|
|
|
|
|
|
|
|
im[im_sand,0] = 0
|
|
|
|
|
|
|
|
im[im_sand,1] = 0
|
|
|
|
|
|
|
|
im[im_sand,2] = 1
|
|
|
|
|
|
|
|
plt.figure()
|
|
|
|
|
|
|
|
plt.imshow(im[:,:,[2,1,0]])
|
|
|
|
|
|
|
|
plt.axis('image')
|
|
|
|
|
|
|
|
plt.title('Sand classification')
|
|
|
|
|
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return im_sand
|
|
|
|