-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
update RCA algo and set RELOAD in docker-compose to --reload (#78)
Co-authored-by: janf <[email protected]>
- Loading branch information
Showing
2 changed files
with
71 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,79 +1,101 @@ | ||
from typing import Sequence | ||
|
||
import numpy | ||
from typing import List | ||
from pydantic import Field | ||
from rio_tiler.models import ImageData | ||
|
||
from titiler.core.algorithm.base import BaseAlgorithm | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
class RapidChangeAssessment(BaseAlgorithm): | ||
|
||
title: str = "Rapid Change Assessment Tool" | ||
description: str = "Quick assessment to detect changes by comparing two bands" | ||
description: str = "Detect changes by subtracting relative radiances between two images taken between and after an event" | ||
|
||
"""Rapid change assessment.""" | ||
# parameters | ||
threshold: float = Field( | ||
0.8, ge=0.0, le=1.0, | ||
title="Threshold(%)", | ||
description="Threshold (%) to mask changes which is ranged between 0 and 1" | ||
) | ||
# threshold: float = Field( | ||
# default=0, ge=0.0, le=1.0, | ||
# title="Threshold(%)", | ||
# description="Only pixels with change/decrease above this threshold will be supplied" | ||
# ) | ||
|
||
only_negative: bool = Field( | ||
default=True, | ||
title='Only negative', | ||
description='Compute only pixels whose values have decreased between the two dates' | ||
|
||
cloud_mask: bool = Field( | ||
False, | ||
title="Cloud mask", | ||
description="If enabled, cloud will be removed masked by band 3 and band 4." | ||
) | ||
|
||
cloud_mask_threshold: int = Field( | ||
1, | ||
# cloud_mask: bool = Field( | ||
# False, | ||
# title="Cloud mask", | ||
# description="If enabled, cloud will be removed masked by band 3 and band 4." | ||
# ) | ||
|
||
cloud_mask_value: int = Field( | ||
default=1, | ||
ge=0, | ||
le=5, | ||
title="Cloud mask threshold", | ||
description="Remove cloud if band value is greater than this threshold" | ||
description="Inclusive cloud threshold. Specifying a value results in considering all lower values", | ||
options_descriptions = ['No clouds', 'Almost no clouds', 'Very few clouds', 'Partially cloudy', 'Cloudy', 'Very cloudy' ] | ||
) | ||
|
||
|
||
|
||
# metadata | ||
input_nbands: int = 2 | ||
input_description: str = "the first two bands will be used to compute change detection. " \ | ||
"the last two bands will be used to mask the result. " \ | ||
"The first two bands are required. " | ||
input_description: str = "The bands that will be used to detect changes" | ||
input_bands: List = [ | ||
{'title': 'Start date image', 'description': 'The image before the event', 'required':True}, | ||
{'title': 'End date image', 'description': 'The image after the event', 'required':True}, | ||
{'title': 'Start date cloud mask', 'description': 'The cloud mask of the image before the event', | ||
'required': True}, | ||
{'title': 'End date cloud mask', 'description': 'The cloud mask of the image after the event', | ||
'required': True}, | ||
] | ||
|
||
# input_second_image_title: str = 'Second image' | ||
# input_second_image_description: str = 'The image after the event' | ||
|
||
output_nbands: int = 1 | ||
output_dtype: int = "uint8" | ||
output_min: Sequence[int] = [0] | ||
output_max: Sequence[int] = [1] | ||
output_description: str = "Masked result which has changed greater than threshold" | ||
output_dtype: int = "int8" | ||
output_min: Sequence[int] = [-100] | ||
output_max: Sequence[int] = [100] | ||
output_description: str = "Pixels/locations whose values have decreased/changed" | ||
|
||
def __call__(self, img: ImageData) -> ImageData: | ||
"""Rapid change assessment.""" | ||
b1 = img.array[0].astype("float16") | ||
b2 = img.array[1].astype("float16") | ||
|
||
diff = numpy.abs(b1 - b2) | ||
total = numpy.abs(b1) + numpy.abs(b2) | ||
|
||
# If the difference is more than threshold, return 1. Otherwise return 0 | ||
data = (diff / total > self.threshold) | ||
|
||
# add additional mask condition to remove cloud | ||
if self.cloud_mask and len(img.array) > 2: | ||
# add the third band to mask | ||
b3 = img.array[2].astype("uint8") | ||
valid_mask = (b3 > self.cloud_mask_threshold) | ||
|
||
if len(img.array) > 3: | ||
# add the fourth band to mask if available | ||
b4 = img.array[3].astype("uint8") | ||
valid_mask = valid_mask | (b4 > self.cloud_mask_threshold) | ||
arr = numpy.ma.masked_array(data, dtype=self.output_dtype, mask=valid_mask) | ||
else: | ||
arr = numpy.ma.masked_array(data, dtype=self.output_dtype) | ||
|
||
bnames = img.band_names | ||
b1 = img.array[0] | ||
b2 = img.array[1] | ||
b2 = b2 / b2.max() | ||
b1 = b1 / b1.max() | ||
valid_mask = (img.array[2].astype('uint8') > self.cloud_mask_value) | (img.array[3].astype('uint8') > self.cloud_mask_value) | ||
diff = b2-b1 | ||
data = diff | ||
v = .1 | ||
#v = data.ptp()*.1 | ||
|
||
datam = (data > -v) & (data < v) | ||
|
||
if self.only_negative: | ||
datam |= data>0 | ||
|
||
|
||
arr = numpy.ma.masked_array(data*100, dtype=self.output_dtype, mask=valid_mask | datam ) | ||
|
||
word = 'changes' if not self.only_negative else 'decrease' | ||
|
||
return ImageData( | ||
arr, | ||
assets=img.assets, | ||
crs=img.crs, | ||
bounds=img.bounds, | ||
band_names=[f"(abs({bnames[1]} - {bnames[0]}) / ({bnames[1]} + {bnames[0]})) > {self.threshold}"], | ||
band_names=[f"Relative {word} in pixels value"], | ||
) | ||
|