def execute(mp): """Enhance RGB colors from a Sentinel-2 SAFE archive.""" # read input SAFE file with mp.open( "input_file", resampling=mp.params["resampling"] ) as safe_file: try: # read red, green and blue bands & scale to 8 bit rgb = np.clip( safe_file.read( [4, 3, 2], mask_clouds=mp.params["mask_clouds"], mask_white_areas=mp.params["mask_white_areas"] ) / 16, 0, 255 ).astype("uint8") except MapcheteEmptyInputTile: return "empty" # scale to 0 to 1 for filters red, green, blue = rgb.astype("float") / 255 # save nodata mask for later & remove rgb to free memory mask = rgb.mask del rgb # using rio-color: # (1) apply gamma correction to each band individually # (2) add sigmoidal contrast & bias # (3) add saturation enhanced = np.clip( saturation( sigmoidal( np.stack([ # apply gamma correction for each band gamma(red, mp.params["red_gamma"]), gamma(green, mp.params["green_gamma"]), gamma(blue, mp.params["blue_gamma"]), ]), mp.params["sigmoidal_contrast"], mp.params["sigmoidal_bias"] ), mp.params["saturation"] ) * 255, # scale back to 8bit 1, 255 # clip valid values from 1 to 255 ) # use original nodata mask and return return np.where(mask, 0, enhanced).astype("uint8")
def test_sat_rgba_direct(arr_rgba): # Anything but 3-band RGB will fail with pytest.raises(ValueError): saturation(arr_rgba, 50) with pytest.raises(ValueError): saturation(arr_rgba[0:2], 50)
def test_sat(arr): x = saturation(arr, 50) assert x[0][0][0] - 0.15860622 < 1e-4
def test_parse_multi_saturation_first(arr): f1, f2 = parse_operations("saturation 1.25 gamma rgb 0.95") assert np.array_equal(f2(f1(arr)), gamma(saturation(arr, 1.25), g=0.95))
def test_parse_saturation_rgb(arr): f = parse_operations("saturation 1.25")[0] assert np.allclose(f(arr), saturation(arr, 1.25))