-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optional gamma correction parameter #350
base: main
Are you sure you want to change the base?
Changes from 10 commits
eb5fe99
501b742
4bcf79c
5bb6ccc
2105538
873844a
f80789d
ec58a7d
6efe415
993ed66
21f2db2
4577289
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,13 +3,17 @@ | |
Utilities to create and manipulate images. | ||
""" | ||
|
||
from typing import List, Sequence, Tuple, TypeVar, Union | ||
from typing import List, Sequence, Tuple, TypeVar, Union, Optional | ||
from typing.io import BinaryIO | ||
|
||
from io import BytesIO | ||
import numbers | ||
|
||
import numpy as np | ||
from PIL import Image | ||
from color_operations import parse_operations | ||
from color_operations.operations import gamma | ||
from color_operations.utils import to_math_type, scale_dtype | ||
|
||
from terracotta.profile import trace | ||
from terracotta import exceptions, get_settings | ||
|
@@ -162,6 +166,43 @@ def to_uint8(data: Array, lower_bound: Number, upper_bound: Number) -> Array: | |
return rescaled.astype(np.uint8) | ||
|
||
|
||
def gamma_correction( | ||
masked_data: Array, | ||
gamma_factor: float, | ||
band_range: list, | ||
out_dtype: type = np.uint16, | ||
) -> Array: | ||
"""Apply gamma correction to the input array and scale it to the output dtype.""" | ||
if not isinstance(gamma_factor, numbers.Number) or gamma_factor <= 0: | ||
raise exceptions.InvalidArgumentsError("Invalid gamma factor") | ||
|
||
if band_range: | ||
arr = contrast_stretch(masked_data, band_range, (0, 1)) | ||
elif np.issubdtype(masked_data.dtype, np.integer): | ||
arr = to_math_type(masked_data) | ||
else: | ||
raise exceptions.InvalidArgumentsError("No band range given and array is not of integer type") | ||
|
||
arr = gamma(arr, gamma_factor) | ||
arr = scale_dtype(arr, out_dtype) | ||
return arr | ||
|
||
|
||
def apply_color_transform( | ||
masked_data: Array, | ||
color_transform: str, | ||
out_dtype: type = np.uint16, | ||
) -> Array: | ||
"""Apply gamma correction to the input array and scale it to the output dtype.""" | ||
arr = to_math_type(masked_data) | ||
|
||
for func in parse_operations(color_transform): | ||
arr = func(arr) | ||
Comment on lines
+182
to
+183
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this assume a particular scaling already? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, inputs have to be in the [0,1] range: https://github.com/vincentsarago/color-operations/?tab=readme-ov-file#color_operationsoperations There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. It may be easier to apply stretching before color transform then. I.e., normalize to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it may not be a good idea since it would change the result. The color stretch fills the [0, 1] range whereas the normalization This is what chatgpt said in the case of gamma correction:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, but who says that the dtype range is appropriate? The user-provided stretch range is telling us how to map the values in the raster to a linear scale. Summoning @vincentsarago in case you want to weigh in on the appropriate order of linear scaling (and clamping out of range values) vs. color correction :) |
||
|
||
arr = scale_dtype(arr, out_dtype) | ||
biserhong marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return arr | ||
|
||
|
||
def label(data: Array, labels: Sequence[Number]) -> Array: | ||
"""Create a labelled uint8 version of data, with output values starting at 1. | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why introduce this variable? Looks unused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh now I see, you're using this further below. But beware, since you're setting this in a loop only the value for the last band will be used in the color transform!