Skip to content

Commit

Permalink
Ensure that colour.utilities.as_float definition do not reduce dime…
Browse files Browse the repository at this point in the history
…nsionality.

Closes #1188.
  • Loading branch information
KelSolaar committed Jul 29, 2023
1 parent 708ded0 commit 24e0321
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 55 deletions.
6 changes: 2 additions & 4 deletions colour/algebra/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,14 +482,12 @@ def spow(a: ArrayLike, p: ArrayLike) -> NDArrayFloat:
if not _SPOW_ENABLED:
return np.power(a, p)

a = np.atleast_1d(a)
a = as_float_array(a)
p = as_float_array(p)

a_p = np.sign(a) * np.abs(a) ** p

a_p[np.isnan(a_p)] = 0

return as_float(a_p)
return as_float(0 if a_p.ndim == 0 and np.isnan(a_p) else a_p)


def normalise_vector(a: ArrayLike) -> NDArrayFloat:
Expand Down
4 changes: 2 additions & 2 deletions colour/algebra/extrapolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
ProtocolInterpolator,
Real,
Type,
cast,
)
from colour.utilities import (
as_float_array,
as_float,
attest,
is_numeric,
Expand Down Expand Up @@ -301,7 +301,7 @@ def __call__(self, x: ArrayLike) -> NDArrayFloat:
Extrapolated points value(s).
"""

x = cast(NDArrayFloat, np.atleast_1d(x).astype(self._dtype))
x = as_float_array(x)

xe = self._evaluate(x)

Expand Down
16 changes: 9 additions & 7 deletions colour/algebra/interpolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ def __call__(self, x: ArrayLike) -> NDArrayFloat:
Interpolated value(s).
"""

x = cast(NDArrayFloat, np.atleast_1d(x).astype(self._dtype))
x = as_float_array(x)

xi = self._evaluate(x)

Expand All @@ -685,7 +685,9 @@ def _evaluate(self, x: NDArrayFloat) -> NDArrayFloat:
x_interval = interval(self._x)[0]
x_f = np.floor(x / x_interval)

windows = x_f[:, None] + np.arange(-self._window + 1, self._window + 1)
windows = x_f[..., None] + np.arange(
-self._window + 1, self._window + 1
)
clip_l = min(self._x_p) / x_interval
clip_h = max(self._x_p) / x_interval
windows = np.clip(windows, clip_l, clip_h) - clip_l
Expand All @@ -694,7 +696,7 @@ def _evaluate(self, x: NDArrayFloat) -> NDArrayFloat:
return np.sum(
self._y_p[windows]
* self._kernel(
x[:, None] / x_interval
x[..., None] / x_interval
- windows
- min(self._x_p) / x_interval,
**self._kernel_kwargs,
Expand Down Expand Up @@ -903,7 +905,7 @@ def __call__(self, x: ArrayLike) -> NDArrayFloat:
Interpolated value(s).
"""

x = cast(NDArrayFloat, np.atleast_1d(x).astype(self._dtype))
x = as_float_array(x)

xi = self._evaluate(x)

Expand Down Expand Up @@ -1193,7 +1195,7 @@ def __call__(self, x: ArrayLike) -> NDArrayFloat:
Interpolated value(s).
"""

x = cast(NDArrayFloat, np.atleast_1d(x).astype(self._dtype))
x = as_float_array(x)

xi = self._evaluate(x)

Expand Down Expand Up @@ -1604,7 +1606,7 @@ def __call__(self, x: ArrayLike) -> NDArrayFloat:
Interpolated value(s).
"""

x = cast(NDArrayFloat, np.atleast_1d(x).astype(self._dtype))
x = as_float_array(x)

xi = self._evaluate(x)

Expand Down Expand Up @@ -1639,7 +1641,7 @@ def _evaluate(self, x: NDArrayFloat) -> NDArrayFloat:
)
] = self._default

return values
return np.squeeze(values)

def _validate_dimensions(self):
"""Validate that the variables dimensions are the same."""
Expand Down
31 changes: 18 additions & 13 deletions colour/appearance/ciecam16.py
Original file line number Diff line number Diff line change
Expand Up @@ -583,16 +583,21 @@ def f_e_forward(RGB_c: ArrayLike, F_L: ArrayLike) -> NDArrayFloat:
F_L = as_float_array(F_L)
q_L, q_U = 0.26, 150

f_q_F_L_q_U = f_q(F_L, q_U)[..., None]
f_q_F_L_q_L = f_q(F_L, q_L)[..., None]
f_q_F_L_RGB_c = f_q(F_L[..., None], RGB_c)
d_f_q_F_L_q_U = d_f_q(F_L, q_U)[..., None]

return np.select(
[
RGB_c > q_U,
np.logical_and(q_L <= RGB_c, RGB_c <= q_U),
RGB_c < q_L,
],
[
f_q(F_L, q_U) + d_f_q(F_L, q_U) * (RGB_c - q_U),
f_q(F_L, RGB_c),
f_q(F_L, q_L) * RGB_c / q_L,
f_q_F_L_q_U + d_f_q_F_L_q_U * (RGB_c - q_U),
f_q_F_L_RGB_c,
f_q_F_L_q_L * RGB_c / q_L,
],
)

Expand Down Expand Up @@ -632,18 +637,22 @@ def f_e_inverse(RGB_a: ArrayLike, F_L: ArrayLike) -> NDArrayFloat:
F_L = as_float_array(F_L)
q_L, q_U = 0.26, 150

f_q_F_L_q_U = f_q(F_L, q_U)[..., None]
f_q_F_L_q_L = f_q(F_L, q_L)[..., None]
d_f_q_F_L_q_U = d_f_q(F_L, q_U)[..., None]

return np.select(
[
RGB_a > f_q(F_L, q_U),
np.logical_and(f_q(F_L, q_L) <= RGB_a, RGB_a <= f_q(F_L, q_U)),
RGB_a < f_q(F_L, q_L),
RGB_a > f_q_F_L_q_U,
np.logical_and(f_q_F_L_q_L <= RGB_a, RGB_a <= f_q_F_L_q_U),
RGB_a < f_q_F_L_q_L,
],
[
q_U + (RGB_a - f_q(F_L, q_U)) / d_f_q(F_L, q_U),
q_U + (RGB_a - f_q_F_L_q_U) / d_f_q_F_L_q_U,
100
/ F_L[..., None]
* spow((27.13 * RGB_a) / (400 - RGB_a), 1 / 0.42),
q_L * RGB_a / f_q(F_L, q_L),
q_L * RGB_a / f_q_F_L_q_L,
],
)

Expand Down Expand Up @@ -673,8 +682,6 @@ def f_q(F_L: ArrayLike, q: ArrayLike) -> NDArrayFloat:
F_L = as_float_array(F_L)
q = as_float_array(q)

F_L = F_L[..., None]

F_L_q_100 = spow((F_L * q) / 100, 0.42)

return (400 * F_L_q_100) / (27.13 + F_L_q_100)
Expand All @@ -699,14 +706,12 @@ def d_f_q(F_L: ArrayLike, q: ArrayLike) -> NDArrayFloat:
Examples
--------
>>> d_f_q(1.17, 0.26) # doctest: +ELLIPSIS
array([ 2.0749623...])
2.0749623...
"""

F_L = as_float_array(F_L)
q = as_float_array(q)

F_L = F_L[..., None]

F_L_q_100 = (F_L * q) / 100

return (1.68 * 27.13 * F_L * spow(F_L_q_100, -0.58)) / (
Expand Down
32 changes: 20 additions & 12 deletions colour/models/rgb/transfer_functions/itur_bt_2100.py
Original file line number Diff line number Diff line change
Expand Up @@ -1126,9 +1126,11 @@ def ootf_BT2100_HLG_1(
63.1051034...
"""

E = as_float_array(np.atleast_1d(to_domain_1(E)))
E = to_domain_1(E)

if E.shape[-1] != 3:
is_single_channel = np.atleast_1d(E).shape[-1] != 3

if is_single_channel:
usage_warning(
'"Recommendation ITU-R BT.2100" "Reference HLG OOTF" uses '
"RGB Luminance in computations and expects a vector input, thus "
Expand All @@ -1150,7 +1152,7 @@ def ootf_BT2100_HLG_1(
G_D = alpha * G_S * np.abs(Y_S) ** (gamma - 1) + beta
B_D = alpha * B_S * np.abs(Y_S) ** (gamma - 1) + beta

if E.shape[-1] != 3:
if is_single_channel:
return as_float(from_range_1(R_D))
else:
RGB_D = tstack([R_D, G_D, B_D])
Expand Down Expand Up @@ -1212,9 +1214,11 @@ def ootf_BT2100_HLG_2(
63.0957344...
"""

E = as_float_array(np.atleast_1d(to_domain_1(E)))
E = to_domain_1(E)

is_single_channel = np.atleast_1d(E).shape[-1] != 3

if E.shape[-1] != 3:
if is_single_channel:
usage_warning(
'"Recommendation ITU-R BT.2100" "Reference HLG OOTF" uses '
"RGB Luminance in computations and expects a vector input, thus "
Expand All @@ -1235,7 +1239,7 @@ def ootf_BT2100_HLG_2(
G_D = alpha * G_S * np.abs(Y_S) ** (gamma - 1)
B_D = alpha * B_S * np.abs(Y_S) ** (gamma - 1)

if E.shape[-1] != 3:
if is_single_channel:
return as_float(from_range_1(R_D))
else:
RGB_D = tstack([R_D, G_D, B_D])
Expand Down Expand Up @@ -1392,9 +1396,11 @@ def ootf_inverse_BT2100_HLG_1(
0.0999999...
"""

F_D = as_float_array(np.atleast_1d(to_domain_1(F_D)))
F_D = to_domain_1(F_D)

if F_D.shape[-1] != 3:
is_single_channel = np.atleast_1d(F_D).shape[-1] != 3

if is_single_channel:
usage_warning(
'"Recommendation ITU-R BT.2100" "Reference HLG OOTF" uses '
"RGB Luminance in computations and expects a vector input, thus "
Expand Down Expand Up @@ -1430,7 +1436,7 @@ def ootf_inverse_BT2100_HLG_1(
Y_D_beta * (B_D - beta) / alpha,
)

if F_D.shape[-1] != 3:
if is_single_channel:
return as_float(from_range_1(R_S))
else:
RGB_S = tstack([R_S, G_S, B_S])
Expand Down Expand Up @@ -1490,9 +1496,11 @@ def ootf_inverse_BT2100_HLG_2(
0.1000000...
"""

F_D = as_float_array(np.atleast_1d(to_domain_1(F_D)))
F_D = to_domain_1(F_D)

is_single_channel = np.atleast_1d(F_D).shape[-1] != 3

if F_D.shape[-1] != 3:
if is_single_channel:
usage_warning(
'"Recommendation ITU-R BT.2100" "Reference HLG OOTF" uses '
"RGB Luminance in computations and expects a vector input, thus "
Expand Down Expand Up @@ -1527,7 +1535,7 @@ def ootf_inverse_BT2100_HLG_2(
Y_D_alpha * B_D / alpha,
)

if F_D.shape[-1] != 3:
if is_single_channel:
return as_float(from_range_1(R_S))
else:
RGB_S = tstack([R_S, G_S, B_S])
Expand Down
2 changes: 1 addition & 1 deletion colour/notation/munsell.py
Original file line number Diff line number Diff line change
Expand Up @@ -1557,7 +1557,7 @@ def is_grey_munsell_colour(specification: ArrayLike) -> bool:

specification = as_float_array(specification)

specification = specification[~np.isnan(specification)]
specification = np.squeeze(specification[~np.isnan(specification)])

return is_numeric(as_float(specification))

Expand Down
33 changes: 19 additions & 14 deletions colour/utilities/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,9 +601,11 @@ def as_int(a: ArrayLike, dtype: Type[DTypeInt] | None = None) -> NDArrayInt:
Examples
--------
>>> as_int(np.array([1]))
>>> as_int(np.array(1))
1
>>> as_int(np.arange(10)) # doctest: +ELLIPSIS
>>> as_int(np.array([1])) # doctest: +SKIP
array([1])
>>> as_int(np.arange(10)) # doctest: +SKIP
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]...)
"""

Expand All @@ -614,12 +616,6 @@ def as_int(a: ArrayLike, dtype: Type[DTypeInt] | None = None) -> NDArrayInt:
_ASSERTION_MESSAGE_DTYPE_INT,
)

try:
if len(a) == 1: # pyright: ignore
a = np.squeeze(a)
except TypeError:
pass

return dtype(a) # pyright: ignore


Expand Down Expand Up @@ -647,8 +643,10 @@ def as_float(
Examples
--------
>>> as_float(np.array([1]))
>>> as_float(np.array(1))
1.0
>>> as_float(np.array([1]))
array([ 1.])
>>> as_float(np.arange(10))
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
"""
Expand All @@ -660,11 +658,18 @@ def as_float(
_ASSERTION_MESSAGE_DTYPE_FLOAT,
)

try:
if len(a) == 1: # pyright: ignore
a = np.squeeze(a)
except TypeError:
pass
# NOTE: "np.float64" reduces dimensionality:
# >>> np.int64(np.array([[1]]))
# array([[1]])
# >>> np.float64(np.array([[1]]))
# 1.0
# See for more information https://github.com/numpy/numpy/issues/24283
if (
all([hasattr(a, "size"), hasattr(a, "ndim")])
and a.size == 1
and a.ndim != 0
):
return as_float_array(a, dtype)

return dtype(a) # pyright: ignore

Expand Down
8 changes: 6 additions & 2 deletions colour/utilities/tests/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,9 @@ def test_as_int(self):

self.assertEqual(as_int(1), 1)

self.assertEqual(as_int(np.array([1])), 1)
self.assertEqual(as_int(np.array([1])).ndim, 1)

self.assertEqual(as_int(np.array([[1]])).ndim, 2)

np.testing.assert_array_almost_equal(
as_int(np.array([1.0, 2.0, 3.0])), np.array([1, 2, 3])
Expand All @@ -526,7 +528,9 @@ def test_as_float(self):

self.assertEqual(as_float(1), 1.0)

self.assertEqual(as_float(np.array([1])), 1.0)
self.assertEqual(as_float(np.array([1])).ndim, 1)

self.assertEqual(as_float(np.array([[1]])).ndim, 2)

np.testing.assert_array_almost_equal(
as_float(np.array([1, 2, 3])), np.array([1.0, 2.0, 3.0])
Expand Down

0 comments on commit 24e0321

Please sign in to comment.