def test_as_numeric(self): """ Tests :func:`colour.utilities.array.as_numeric` definition. """ self.assertEqual(as_numeric(1), 1) self.assertEqual(as_numeric(np.array([1])), 1) np.testing.assert_almost_equal(as_numeric(np.array([1, 2, 3])), np.array([1, 2, 3]))
def test_as_numeric(self): """ Tests :func:`colour.utilities.array.as_numeric` definition. """ self.assertEqual(as_numeric(1), 1.0) self.assertEqual(as_numeric(np.array([1])), 1.0) np.testing.assert_almost_equal( as_numeric(np.array([1, 2, 3])), np.array([1.0, 2.0, 3.0])) self.assertIsInstance(as_numeric(1), DEFAULT_FLOAT_DTYPE) self.assertIsInstance(as_numeric(1, int), int)
def log_decoding_ACEScc(ACEScc): """ Defines the *ACEScc* colourspace log decoding / electro-optical transfer function. Parameters ---------- ACEScc : numeric or array_like *ACEScc* non-linear value. Returns ------- numeric or ndarray *ACESccLin* linear value. Examples -------- >>> log_decoding_ACEScc(0.413588402492442) # doctest: +ELLIPSIS 0.1799999... """ ACEScc = np.asarray(ACEScc) output = np.where(ACEScc < (9.72 - 15) / 17.52, (2 ** (ACEScc * 17.52 - 9.72) - 2 ** -16) * 2, 2 ** (ACEScc * 17.52 - 9.72)) output = np.where(ACEScc >= (np.log2(65504) + 9.72) / 17.52, 65504, output) return as_numeric(output)
def daylight_locus_function(x_D): """ Returns the daylight locus as *xy* chromaticity coordinates. Parameters ---------- x_D : numeric or array_like *x* chromaticity coordinates Returns ------- numeric or array_like Daylight locus as *xy* chromaticity coordinates. References ---------- :cite:`Wyszecki2000a` Examples -------- >>> daylight_locus_function(0.31270) # doctest: +ELLIPSIS 0.3291051... """ x_D = as_float_array(x_D) y_D = -3.000 * x_D ** 2 + 2.870 * x_D - 0.275 return as_numeric(y_D)
def log_decoding_VLog(V_out): """ Defines the *Panasonic V-Log* log decoding curve / electro-optical transfer function. Parameters ---------- V_out : numeric or array_like Non-linear data :math:`V_{out}`. Returns ------- numeric or ndarray Linear reflection data :math`L_{in}`. Examples -------- >>> log_decoding_VLog(0.423311448760136) # doctest: +ELLIPSIS 0.1799999... """ V_out = np.asarray(V_out) cut2 = VLOG_CONSTANTS.cut2 b = VLOG_CONSTANTS.b c = VLOG_CONSTANTS.c d = VLOG_CONSTANTS.d V_out = np.where(V_out < cut2, (V_out - 0.125) / 5.6, np.power(10, ((V_out - d) / c)) - b) return as_numeric(V_out)
def oetf_ROMMRGB(X): """ Defines the *ROMM RGB* encoding opto-electronic transfer function (OETF / OECF). Parameters ---------- X : numeric or array_like Linear data :math:`X_{ROMM}`. Returns ------- numeric or ndarray Non-linear data :math:`X'_{ROMM}`. Examples -------- >>> oetf_ROMMRGB(0.18) # doctest: +ELLIPSIS 0.3857114... """ X = np.asarray(X) E_t = 16 ** (1.8 / (1 - 1.8)) return as_numeric(np.where(X < E_t, X * 16, X ** (1 / 1.8)))
def log_encoding_VLog(L_in): """ Defines the *Panasonic V-Log* log encoding curve / opto-electronic transfer function. Parameters ---------- L_in : numeric or array_like Linear reflection data :math`L_{in}`. Returns ------- numeric or ndarray Non-linear data :math:`V_{out}`. Examples -------- >>> log_encoding_VLog(0.18) # doctest: +ELLIPSIS 0.4233114... """ L_in = np.asarray(L_in) cut1 = VLOG_CONSTANTS.cut1 b = VLOG_CONSTANTS.b c = VLOG_CONSTANTS.c d = VLOG_CONSTANTS.d L_in = np.where(L_in < cut1, 5.6 * L_in + 0.125, c * np.log10(L_in + b) + d) return as_numeric(L_in)
def eotf_BT2020(E_p, is_12_bits_system=False): """ Defines *Recommendation ITU-R BT.2020* electro-optical transfer function (EOTF / EOCF). Parameters ---------- E_p : numeric or array_like Non-linear signal :math:`E'`. is_12_bits_system : bool *BT.709* *alpha* and *beta* constants are used if system is not 12-bit. Returns ------- numeric or ndarray Resulting voltage :math:`E`. Examples -------- >>> eotf_BT2020(0.705515089922121) # doctest: +ELLIPSIS 0.4999999... """ E_p = np.asarray(E_p) a = BT2020_CONSTANTS.alpha(is_12_bits_system) b = BT2020_CONSTANTS.beta(is_12_bits_system) return as_numeric(np.where(E_p < oetf_BT2020(b), E_p / 4.5, ((E_p + (a - 1)) / a) ** (1 / 0.45)))
def log_encoding_SLog3(t): """ Defines the *Sony S-Log3* log encoding curve / opto-electronic transfer function. Parameters ---------- t : numeric or array_like Input light level :math:`t` to a camera. Returns ------- numeric or ndarray Camera output code :math:`y`. Examples -------- >>> log_encoding_SLog3(0.18) # doctest: +ELLIPSIS 0.4105571... """ t = np.asarray(t) return as_numeric( np.where(t >= 0.01125000, (420 + np.log10((t + 0.01) / (0.18 + 0.01)) * 261.5) / 1023, (t * (171.2102946929 - 95) / 0.01125000 + 95) / 1023))
def oetf_BT709(L): """ Defines *Recommendation ITU-R BT.709-6* opto-electronic transfer function (OETF / OECF). Parameters ---------- L : numeric or array_like *Luminance* :math:`L` of the image. Returns ------- numeric or ndarray Corresponding electrical signal :math:`V`. Examples -------- >>> oetf_BT709(0.18) # doctest: +ELLIPSIS 0.4090077... """ L = np.asarray(L) return as_numeric(np.where(L < 0.018, L * 4.5, 1.099 * (L ** 0.45) - 0.099))
def log_decoding_SLog3(y): """ Defines the *Sony S-Log3* log decoding curve / electro-optical transfer function. Parameters ---------- y : numeric or array_like Camera output code :math:`y`. Returns ------- numeric or ndarray Input light level :math:`t` to a camera. Examples -------- >>> log_decoding_SLog3(0.410557184750733) # doctest: +ELLIPSIS 0.1... """ y = np.asarray(y) return as_numeric( np.where(y >= 171.2102946929 / 1023, ((10 ** ((y * 1023 - 420) / 261.5)) * (0.18 + 0.01) - 0.01), (y * 1023 - 95) * 0.01125000 / (171.2102946929 - 95)))
def eotf_ROMMRGB(X_p): """ Defines the *ROMM RGB* encoding electro-optical transfer function (EOTF / EOCF). Parameters ---------- X_p : numeric or array_like Non-linear data :math:`X'_{ROMM}`. Returns ------- numeric or ndarray Linear data :math:`X_{ROMM}`. Examples -------- >>> eotf_ROMMRGB(0.3857114247511376) # doctest: +ELLIPSIS 0.1... """ X_p = np.asarray(X_p) E_t = 16 ** (1.8 / (1 - 1.8)) return as_numeric(np.where( X_p < oetf_ROMMRGB(E_t), X_p / 16, X_p ** 1.8))
def log_encoding_ACEScc(ACEScc_l): """ Defines the *ACEScc* colourspace log encoding / opto-electronic transfer function. Parameters ---------- ACEScc_l : numeric or array_like *ACESccLin* linear value. Returns ------- numeric or ndarray *ACEScc* non-linear value. Examples -------- >>> log_encoding_ACEScc(0.18) # doctest: +ELLIPSIS 0.4135884... """ ACEScc_l = np.asarray(ACEScc_l) output = np.where(ACEScc_l < 0, (np.log2(2 ** -15 * 0.5) + 9.72) / 17.52, (np.log2(2 ** -16 + ACEScc_l * 0.5) + 9.72) / 17.52) output = np.where(ACEScc_l >= 2 ** -15, (np.log2(ACEScc_l) + 9.72) / 17.52, output) return as_numeric(output)
def oetf_BT2020(E, is_12_bits_system=False): """ Defines *Recommendation ITU-R BT.2020* opto-electrical transfer function (OETF / OECF). Parameters ---------- E : numeric or array_like Voltage :math:`E` normalized by the reference white level and proportional to the implicit light intensity that would be detected with a reference camera colour channel R, G, B. is_12_bits_system : bool *BT.709* *alpha* and *beta* constants are used if system is not 12-bit. Returns ------- numeric or ndarray Resulting non-linear signal :math:`E'`. Examples -------- >>> oetf_BT2020(0.18) # doctest: +ELLIPSIS 0.4090077... """ E = np.asarray(E) a = BT2020_CONSTANTS.alpha(is_12_bits_system) b = BT2020_CONSTANTS.beta(is_12_bits_system) return as_numeric(np.where(E < b, E * 4.5, a * (E ** 0.45) - (a - 1)))
def xy_to_CCT_Hernandez1999(xy): """ Returns the correlated colour temperature :math:`T_{cp}` from given *CIE XYZ* tristimulus values *xy* chromaticity coordinates using Hernandez-Andres, Lee and Romero (1999) method. Parameters ---------- xy : array_like *xy* chromaticity coordinates. Returns ------- numeric Correlated colour temperature :math:`T_{cp}`. References ---------- .. [10] Hernández-Andrés, J., Lee, R. L., & Romero, J. (1999). Calculating correlated color temperatures across the entire gamut of daylight and skylight chromaticities. Applied Optics, 38(27), 5703–5709. doi:10.1364/AO.38.005703 Examples -------- >>> xy = np.array([0.31270, 0.32900]) >>> xy_to_CCT_Hernandez1999(xy) # doctest: +ELLIPSIS 6500.7420431... """ x, y = tsplit(xy) n = (x - 0.3366) / (y - 0.1735) CCT = (-949.86315 + 6253.80338 * np.exp(-n / 0.92159) + 28.70599 * np.exp(-n / 0.20039) + 0.00004 * np.exp(-n / 0.07125)) n = np.where(CCT > 50000, (x - 0.3356) / (y - 0.1691), n) CCT = np.where(CCT > 50000, 36284.48953 + 0.00228 * np.exp(-n / 0.07861) + 5.4535e-36 * np.exp(-n / 0.01543), CCT) return as_numeric(CCT)
def log_encoding_ERIMMRGB(X, I_max=255, E_min=0.001, E_clip=316.2): """ Defines the *ERIMM RGB* log encoding curve / opto-electronic transfer function (OETF / OECF). Parameters ---------- X : numeric or array_like Linear data :math:`X_{ERIMM}`. I_max : numeric, optional Maximum code value: 255, 4095, and 650535 for respectively 8-bit, 12-bit and 16-bit per channel. E_min : numeric, optional Minimum exposure limit. E_clip : numeric, optional Maximum exposure limit. Returns ------- numeric or ndarray Non-linear data :math:`X'_{ERIMM}`. Examples -------- >>> log_encoding_ERIMMRGB(0.18) # doctest: +ELLIPSIS 104.5633593... """ X = np.asarray(X) E_t = np.exp(1) * E_min X_p = np.select( [X < 0.0, X <= E_t, X > E_t, X > E_clip], [0, I_max * ((np.log(E_t) - np.log(E_min)) / (np.log(E_clip) - np.log(E_min))) * (X / E_t), I_max * ((np.log(X) - np.log(E_min)) / (np.log(E_clip) - np.log(E_min))), I_max]) return as_numeric(X_p)
def log_encoding_ACESproxy(ACESproxy_l, bit_depth='10 Bit'): """ Defines the *ACESproxy* colourspace log encoding curve / opto-electronic transfer function. Parameters ---------- ACESproxy_l : numeric or array_like *ACESproxyLin* linear value. bit_depth : unicode, optional **{'10 Bit', '12 Bit'}**, *ACESproxy* bit depth. Returns ------- numeric or ndarray *ACESproxy* non-linear value. Examples -------- >>> log_encoding_ACESproxy(0.18) 426 """ ACESproxy_l = np.asarray(ACESproxy_l) constants = ACES_PROXY_CONSTANTS.get(bit_depth) CV_min = np.resize(constants.CV_min, ACESproxy_l.shape) CV_max = np.resize(constants.CV_max, ACESproxy_l.shape) def float_2_cv(x): """ Converts given numeric to code value. """ return np.maximum(CV_min, np.minimum(CV_max, np.round(x))) output = np.where(ACESproxy_l > 2 ** -9.72, float_2_cv((np.log2(ACESproxy_l) + constants.mid_log_offset) * constants.steps_per_stop + constants.mid_CV_offset), np.resize(CV_min, ACESproxy_l.shape)) return as_numeric(output, int)
def log_encoding_CanonLog(x, bit_depth=10, out_legal=True, in_reflection=True): """ Defines the *Canon Log* log encoding curve / opto-electronic transfer function. Parameters ---------- x : numeric or array_like Linear data :math:`x`. bit_depth : int, optional Bit depth used for conversion. out_legal : bool, optional Whether the *Canon Log* non-linear data is encoded in legal range. in_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Returns ------- numeric or ndarray *Canon Log* non-linear data. References ---------- - :cite:`Thorpe2012a` Examples -------- >>> log_encoding_CanonLog(0.18) * 100 # doctest: +ELLIPSIS 34.3389651... """ x = np.asarray(x) if in_reflection: x = x / 0.9 clog = np.where(x < log_decoding_CanonLog(0.0730597, bit_depth, False), -(0.529136 * (np.log10(-x * 10.1596 + 1)) - 0.0730597), 0.529136 * np.log10(10.1596 * x + 1) + 0.0730597) clog = full_to_legal(clog, bit_depth) if out_legal else clog return as_numeric(clog)
def log_decoding_ALEXALogC(t, firmware='SUP 3.x', method='Linear Scene Exposure Factor', EI=800): """ Defines the *ALEXA Log C* log decoding curve / electro-optical transfer function. Parameters ---------- t : numeric or array_like *ALEXA Log C* encoded data :math:`t`. firmware : unicode, optional **{'SUP 3.x', 'SUP 2.x'}**, Alexa firmware version. method : unicode, optional **{'Linear Scene Exposure Factor', 'Normalised Sensor Signal'}**, Conversion method. EI : int, optional Ei. Returns ------- numeric or ndarray Linear data :math:`x`. References ---------- - :cite:`ARRI2012a` Examples -------- >>> log_decoding_ALEXALogC(0.391006832034084) # doctest: +ELLIPSIS 0.18... """ t = np.asarray(t) cut, a, b, c, d, e, f, _e_cut_f = ( ALEXA_LOG_C_CURVE_CONVERSION_DATA[firmware][method][EI]) return as_numeric( np.where(t > e * cut + f, (np.power(10, (t - d) / c) - b) / a, (t - f) / e))
def luminance_CIE1976(Lstar, Y_n=100): """ Returns the *luminance* :math:`Y` of given *Lightness* :math:`L^*` with given reference white *luminance* :math:`Y_n`. Parameters ---------- Lstar : numeric or array_like *Lightness* :math:`L^*` Y_n : numeric or array_like White reference *luminance* :math:`Y_n`. Returns ------- numeric or array_like *luminance* :math:`Y`. Notes ----- - Input *Lightness* :math:`L^*` and reference white *luminance* :math:`Y_n` are in domain [0, 100]. - Output *luminance* :math:`Y` is in range [0, 100]. References ---------- - :cite:`Lindbloom2003d` - :cite:`Wyszecki2000bd` Examples -------- >>> luminance_CIE1976(37.98562910) # doctest: +ELLIPSIS 10.0800000... >>> luminance_CIE1976(37.98562910, 95) # doctest: +ELLIPSIS 9.5760000... """ Lstar = np.asarray(Lstar) Y_n = np.asarray(Y_n) Y = as_numeric( np.where(Lstar > CIE_K * CIE_E, Y_n * ((Lstar + 16) / 116)**3, Y_n * (Lstar / CIE_K))) return Y
def log_decoding_ERIMMRGB(X_p, I_max=255, E_min=0.001, E_clip=316.2): """ Defines the *ERIMM RGB* log decoding curve / electro-optical transfer function (EOTF / EOCF). Parameters ---------- X_p : numeric or array_like Non-linear data :math:`X'_{ERIMM}`. I_max : numeric, optional Maximum code value: 255, 4095, and 650535 for respectively 8-bit, 12-bit and 16-bit per channel. E_min : numeric, optional Minimum exposure limit. E_clip : numeric, optional Maximum exposure limit. Returns ------- numeric or ndarray Linear data :math:`X_{ERIMM}`. Examples -------- >>> log_decoding_ERIMMRGB(104.56335932049294) # doctest: +ELLIPSIS 0.1... """ X_p = np.asarray(X_p) E_t = np.exp(1) * E_min X = np.where( X_p <= I_max * ((np.log(E_t) - np.log(E_min)) / (np.log(E_clip) - np.log(E_min))), (((np.log(E_clip) - np.log(E_min)) / (np.log(E_t) - np.log(E_min))) * ((X_p * E_t) / I_max)), np.exp((X_p / I_max) * (np.log(E_clip) - np.log(E_min)) + np.log(E_min))) return as_numeric(X)
def log_decoding_ERIMMRGB(X_p, I_max=255, E_min=0.001, E_clip=316.2): """ Defines the *ERIMM RGB* log decoding curve / electro-optical transfer function (EOTF / EOCF). Parameters ---------- X_p : numeric or array_like Non-linear data :math:`X'_{ERIMM}`. I_max : numeric, optional Maximum code value: 255, 4095 and 650535 for respectively 8-bit, 12-bit and 16-bit per channel. E_min : numeric, optional Minimum exposure limit. E_clip : numeric, optional Maximum exposure limit. Returns ------- numeric or ndarray Linear data :math:`X_{ERIMM}`. Examples -------- >>> log_decoding_ERIMMRGB(104.56335932049294) # doctest: +ELLIPSIS 0.1... """ X_p = np.asarray(X_p) E_t = np.exp(1) * E_min X = np.where( X_p <= I_max * ((np.log(E_t) - np.log(E_min)) / (np.log(E_clip) - np.log(E_min))), (((np.log(E_clip) - np.log(E_min)) / (np.log(E_t) - np.log(E_min))) * ((X_p * E_t) / I_max)), np.exp((X_p / I_max) * (np.log(E_clip) - np.log(E_min)) + np.log(E_min))) return as_numeric(X)
def xy_to_CCT_Hernandez1999(xy): """ Returns the correlated colour temperature :math:`T_{cp}` from given *CIE XYZ* tristimulus values *xy* chromaticity coordinates using Hernandez-Andres et al. (1999) method. Parameters ---------- xy : array_like *xy* chromaticity coordinates. Returns ------- numeric Correlated colour temperature :math:`T_{cp}`. References ---------- .. [11] Hernández-Andrés, J., Lee, R. L., & Romero, J. (1999). Calculating correlated color temperatures across the entire gamut of daylight and skylight chromaticities. Applied Optics, 38(27), 5703–5709. doi:10.1364/AO.38.005703 Examples -------- >>> xy = np.array([0.31270, 0.32900]) >>> xy_to_CCT_Hernandez1999(xy) # doctest: +ELLIPSIS 6500.7420431... """ x, y = tsplit(xy) n = (x - 0.3366) / (y - 0.1735) CCT = (-949.86315 + 6253.80338 * np.exp(-n / 0.92159) + 28.70599 * np.exp(-n / 0.20039) + 0.00004 * np.exp(-n / 0.07125)) n = np.where(CCT > 50000, (x - 0.3356) / (y - 0.1691), n) CCT = np.where( CCT > 50000, 36284.48953 + 0.00228 * np.exp(-n / 0.07861) + 5.4535e-36 * np.exp(-n / 0.01543), CCT) return as_numeric(CCT)
def xy_to_CCT_Hernandez1999(xy): """ Returns the correlated colour temperature :math:`T_{cp}` from given *CIE xy* chromaticity coordinates using *Hernandez-Andres et al. (1999)* method. Parameters ---------- xy : array_like *CIE xy* chromaticity coordinates. Returns ------- numeric Correlated colour temperature :math:`T_{cp}`. References ---------- :cite:`Hernandez-Andres1999a` Examples -------- >>> xy = np.array([0.31270, 0.32900]) >>> xy_to_CCT_Hernandez1999(xy) # doctest: +ELLIPSIS 6500.7420431... """ x, y = tsplit(xy) n = (x - 0.3366) / (y - 0.1735) CCT = (-949.86315 + 6253.80338 * np.exp(-n / 0.92159) + 28.70599 * np.exp(-n / 0.20039) + 0.00004 * np.exp(-n / 0.07125)) n = np.where(CCT > 50000, (x - 0.3356) / (y - 0.1691), n) CCT = np.where( CCT > 50000, 36284.48953 + 0.00228 * np.exp(-n / 0.07861) + 5.4535e-36 * np.exp(-n / 0.01543), CCT, ) return as_numeric(CCT)
def log_encoding_ERIMMRGB(X, I_max=255, E_min=0.001, E_clip=316.2): """ Defines the *ERIMM RGB* log encoding curve / opto-electronic transfer function (OETF / OECF). Parameters ---------- X : numeric or array_like Linear data :math:`X_{ERIMM}`. I_max : numeric, optional Maximum code value: 255, 4095 and 650535 for respectively 8-bit, 12-bit and 16-bit per channel. E_min : numeric, optional Minimum exposure limit. E_clip : numeric, optional Maximum exposure limit. Returns ------- numeric or ndarray Non-linear data :math:`X'_{ERIMM}`. References ---------- - :cite:`Spaulding2000b` Examples -------- >>> log_encoding_ERIMMRGB(0.18) # doctest: +ELLIPSIS 104.5633593... """ X = np.asarray(X) E_t = np.exp(1) * E_min X_p = np.select([X < 0.0, X <= E_t, X > E_t, X > E_clip], [ 0, I_max * ((np.log(E_t) - np.log(E_min)) / (np.log(E_clip) - np.log(E_min))) * (X / E_t), I_max * ((np.log(X) - np.log(E_min)) / (np.log(E_clip) - np.log(E_min))), I_max ]) return as_numeric(X_p)
def lightness_CIE1976(Y, Y_n=100): """ Returns the *Lightness* :math:`L^*` of given *luminance* :math:`Y` using given reference white *luminance* :math:`Y_n` as per *CIE 1976* recommendation. Parameters ---------- Y : numeric or array_like *luminance* :math:`Y`. Y_n : numeric or array_like, optional White reference *luminance* :math:`Y_n`. Returns ------- numeric or array_like *Lightness* :math:`L^*`. Notes ----- - Input *luminance* :math:`Y` and :math:`Y_n` are in domain [0, 100]. - Output *Lightness* :math:`L^*` is in range [0, 100]. References ---------- - :cite:`Lindbloom2003d` - :cite:`Wyszecki2000bd` Examples -------- >>> lightness_CIE1976(10.08) # doctest: +ELLIPSIS 37.9856290... """ Y = np.asarray(Y) Y_n = np.asarray(Y_n) Lstar = Y / Y_n Lstar = as_numeric( np.where(Lstar <= CIE_E, CIE_K * Lstar, 116 * Lstar**(1 / 3) - 16)) return Lstar
def log_encoding_ALEXALogC(x, firmware='SUP 3.x', method='Linear Scene Exposure Factor', EI=800): """ Defines the *ALEXA Log C* log encoding curve / opto-electronic transfer function. Parameters ---------- x : numeric or array_like Linear data :math:`x`. firmware : unicode, optional **{'SUP 3.x', 'SUP 2.x'}**, Alexa firmware version. method : unicode, optional **{'Linear Scene Exposure Factor', 'Normalised Sensor Signal'}**, Conversion method. EI : int, optional Ei. Returns ------- numeric or ndarray *ALEXA Log C* encoded data :math:`t`. References ---------- - :cite:`ARRI2012a` Examples -------- >>> log_encoding_ALEXALogC(0.18) # doctest: +ELLIPSIS 0.3910068... """ x = np.asarray(x) cut, a, b, c, d, e, f, _e_cut_f = ( ALEXA_LOG_C_CURVE_CONVERSION_DATA[firmware][method][EI]) return as_numeric(np.where(x > cut, c * np.log10(a * x + b) + d, e * x + f))
def oetf_DICOMGSDF(L): """ Defines the *DICOM - Grayscale Standard Display Function* opto-electronic transfer function (OETF / OECF). Parameters ---------- L : numeric or array_like *Luminance* :math:`L`. Returns ------- numeric or ndarray Just-Noticeable Difference (JND) Index, :math:`j` in domain 1 to 1023. References ---------- - :cite:`NationalElectricalManufacturersAssociation2004b` Examples -------- >>> oetf_DICOMGSDF(130.065284012159790) # doctest: +ELLIPSIS 511.9964806... """ L = np.asarray(L) L_lg = np.log10(L) A = DICOMGSDF_CONSTANTS.A B = DICOMGSDF_CONSTANTS.B C = DICOMGSDF_CONSTANTS.C D = DICOMGSDF_CONSTANTS.D E = DICOMGSDF_CONSTANTS.E F = DICOMGSDF_CONSTANTS.F G = DICOMGSDF_CONSTANTS.G H = DICOMGSDF_CONSTANTS.H I = DICOMGSDF_CONSTANTS.I # noqa L = (A + B * L_lg + C * L_lg ** 2 + D * L_lg ** 3 + E * L_lg ** 4 + F * L_lg ** 5 + G * L_lg ** 6 + H * L_lg ** 7 + I * L_lg ** 8) return as_numeric(L)
def oetf_RIMMRGB(X, I_max=255, E_clip=2.0): """ Defines the *RIMM RGB* encoding opto-electronic transfer function (OETF / OECF). *RIMM RGB* encoding non-linearity is based on that specified by *Recommendation ITU-R BT.709-6*. Parameters ---------- X : numeric or array_like Linear data :math:`X_{RIMM}`. I_max : numeric, optional Maximum code value: 255, 4095 and 650535 for respectively 8-bit, 12-bit and 16-bit per channel. E_clip : numeric, optional Maximum exposure level. Returns ------- numeric or ndarray Non-linear data :math:`X'_{RIMM}`. References ---------- - :cite:`Spaulding2000b` Examples -------- >>> oetf_RIMMRGB(0.18) # doctest: +ELLIPSIS 74.3768017... """ X = np.asarray(X) V_clip = 1.099 * E_clip**0.45 - 0.099 q = I_max / V_clip X_p_RIMM = np.select([X < 0.0, X < 0.018, X >= 0.018, X > E_clip], [0, 4.5 * X, 1.099 * (X**0.45) - 0.099, I_max]) return as_numeric(q * X_p_RIMM)
def __call__(self, x): """ Evaluates the Extrapolator at given point(s). Parameters ---------- x : numeric or array_like Point(s) to evaluate the Extrapolator at. Returns ------- float or ndarray Extrapolated points value(s). """ x = np.atleast_1d(x).astype(np.float_) xe = as_numeric(self.__evaluate(x)) return xe
def __call__(self, x): """ Evaluates the interpolator at given point(s). Parameters ---------- x : numeric or array_like Point(s) to evaluate the interpolant at. Returns ------- float or ndarray Interpolated value(s). """ x = np.atleast_1d(x).astype(self._dtype) xi = as_numeric(self._evaluate(x)) return xi
def __call__(self, x): """ Evaluates the Extrapolator at given point(s). Parameters ---------- x : numeric or array_like Point(s) to evaluate the Extrapolator at. Returns ------- float or ndarray Extrapolated points value(s). """ x = np.atleast_1d(x).astype(np.float_) xe = as_numeric(self._evaluate(x)) return xe
def oetf_RIMMRGB(X, I_max=255, E_clip=2.0): """ Defines the *RIMM RGB* encoding opto-electronic transfer function (OETF / OECF). *RIMM RGB* encoding non-linearity is based on that specified by *Recommendation ITU-R BT.709-6*. Parameters ---------- X : numeric or array_like Linear data :math:`X_{RIMM}`. I_max : numeric, optional Maximum code value: 255, 4095, and 650535 for respectively 8-bit, 12-bit and 16-bit per channel. E_clip : numeric, optional Maximum exposure level. Returns ------- numeric or ndarray Non-linear data :math:`X'_{RIMM}`. Examples -------- >>> oetf_RIMMRGB(0.18) # doctest: +ELLIPSIS 74.3768017... """ X = np.asarray(X) V_clip = 1.099 * E_clip ** 0.45 - 0.099 q = I_max / V_clip X_p_RIMM = np.select( [X < 0.0, X < 0.018, X >= 0.018, X > E_clip], [0, 4.5 * X, 1.099 * (X ** 0.45) - 0.099, I_max]) return as_numeric(q * X_p_RIMM)
def __call__(self, x): """ Evaluates the interpolating polynomial at given point(s). Parameters ---------- x : numeric or array_like Point(s) to evaluate the interpolant at. Returns ------- float or ndarray Interpolated value(s). """ x = np.atleast_1d(x).astype(np.float_) xi = as_numeric(self._evaluate(x)) return xi
def domain_distance(self, a): """ Returns the euclidean distance between given array and independent domain :math:`x` closest element. Parameters ---------- a : numeric or array_like :math:`a` variable to compute the euclidean distance with independent domain :math:`x` variable. Returns ------- numeric or array_like Euclidean distance between independent domain :math:`x` variable and given :math:`a` variable. """ n = closest(self.domain, a) return as_numeric(np.abs(a - n))
def test_as_numeric(self): """ Tests :func:`colour.utilities.array.as_numeric` definition. """ self.assertEqual(as_numeric(1), 1.0) self.assertEqual(as_numeric(np.array([1])), 1.0) np.testing.assert_almost_equal(as_numeric(np.array([1, 2, 3])), np.array([1.0, 2.0, 3.0])) self.assertIsInstance(as_numeric(1), DEFAULT_FLOAT_DTYPE) self.assertIsInstance(as_numeric(1, int), int) self.assertListEqual(as_numeric(['John', 'Doe']), ['John', 'Doe']) self.assertEqual(as_numeric('John Doe'), 'John Doe')
def eotf_RIMMRGB(X_p, I_max=255, E_clip=2.0): """ Defines the *RIMM RGB* encoding electro-optical transfer function (EOTF / EOCF). Parameters ---------- X_p : numeric or array_like Non-linear data :math:`X'_{RIMM}`. I_max : numeric, optional Maximum code value: 255, 4095 and 650535 for respectively 8-bit, 12-bit and 16-bit per channel. E_clip : numeric, optional Maximum exposure level. Returns ------- numeric or ndarray Linear data :math:`X_{RIMM}`. References ---------- - :cite:`Spaulding2000b` Examples -------- >>> eotf_RIMMRGB(74.37680178131521) # doctest: +ELLIPSIS 0.1... """ X_p = np.asarray(X_p) V_clip = 1.099 * E_clip**0.45 - 0.099 m = V_clip * X_p / I_max X_RIMM = np.where(X_p < oetf_RIMMRGB(0.018), m / 4.5, ((m + 0.099) / 1.099)**(1 / 0.45)) return as_numeric(X_RIMM)
def oetf_reverse_ARIBSTDB67(E_p, r=0.5): """ Defines *ARIB STD-B67 (Hybrid Log-Gamma)* reverse opto-electrical transfer function (OETF / OECF). Parameters ---------- E_p : numeric or array_like Non-linear signal :math:`E'`. r : numeric, optional Video level corresponding to reference white level. Returns ------- numeric or ndarray Voltage :math:`E` normalized by the reference white level and proportional to the implicit light intensity that would be detected with a reference camera color channel R, G, B. References ---------- - :cite:`AssociationofRadioIndustriesandBusinesses2015a` Examples -------- >>> oetf_reverse_ARIBSTDB67(0.212132034355964) # doctest: +ELLIPSIS 0.1799999... """ E_p = np.asarray(E_p) a = ARIBSTDB67_CONSTANTS.a b = ARIBSTDB67_CONSTANTS.b c = ARIBSTDB67_CONSTANTS.c E = np.where(E_p <= oetf_ARIBSTDB67(1), (E_p / r)**2, np.exp((E_p - c) / a) + b) return as_numeric(E)
def oetf_ARIBSTDB67(E, r=0.5): """ Defines *ARIB STD-B67 (Hybrid Log-Gamma)* opto-electrical transfer function (OETF / OECF). Parameters ---------- E : numeric or array_like Voltage normalized by the reference white level and proportional to the implicit light intensity that would be detected with a reference camera color channel R, G, B. r : numeric, optional Video level corresponding to reference white level. Returns ------- numeric or ndarray Resulting non-linear signal :math:`E'`. References ---------- - :cite:`AssociationofRadioIndustriesandBusinesses2015a` Examples -------- >>> oetf_ARIBSTDB67(0.18) # doctest: +ELLIPSIS 0.2121320... """ E = np.asarray(E) a = ARIBSTDB67_CONSTANTS.a b = ARIBSTDB67_CONSTANTS.b c = ARIBSTDB67_CONSTANTS.c E_p = np.where(E <= 1, r * np.sqrt(E), a * np.log(E - b) + c) return as_numeric(E_p)
def eotf_BT709(V): """ Defines *Recommendation ITU-R BT.709-6* electro-optical transfer function (EOTF / EOCF). Parameters ---------- V : numeric or array_like Electrical signal :math:`V`. Returns ------- numeric or ndarray Corresponding *luminance* :math:`L` of the image. Warning ------- *Recommendation ITU-R BT.709-6* doesn't specify an electro-optical transfer function. This definition is used for symmetry in unit tests and other computations but should not be used as an *EOTF*. Examples -------- >>> eotf_BT709(0.409007728864150) # doctest: +ELLIPSIS 0.1... """ warning(('*Recommendation ITU-R BT.709-6* doesn\'t specify an ' 'electro-optical transfer function. This definition is used ' 'for symmetry in unit tests and others computations but should ' 'not be used as an *EOTF*!')) V = np.asarray(V) return as_numeric(np.where(V < oetf_BT709(0.018), V / 4.5, ((V + 0.099) / 1.099) ** (1 / 0.45)))
def eotf_RIMMRGB(X_p, I_max=255, E_clip=2.0): """ Defines the *RIMM RGB* encoding electro-optical transfer function (EOTF / EOCF). Parameters ---------- X_p : numeric or array_like Non-linear data :math:`X'_{RIMM}`. I_max : numeric, optional Maximum code value: 255, 4095, and 650535 for respectively 8-bit, 12-bit and 16-bit per channel. E_clip : numeric, optional Maximum exposure level. Returns ------- numeric or ndarray Linear data :math:`X_{RIMM}`. Examples -------- >>> eotf_RIMMRGB(74.37680178131521) # doctest: +ELLIPSIS 0.1... """ X_p = np.asarray(X_p) V_clip = 1.099 * E_clip ** 0.45 - 0.099 m = V_clip * X_p / I_max X_RIMM = np.where( X_p < oetf_RIMMRGB(0.018), m / 4.5, ((m + 0.099) / 1.099) ** (1 / 0.45)) return as_numeric(X_RIMM)
def log_encoding_ACEScct(lin_AP1): """ Defines the *ACEScct* colourspace log encoding / opto-electronic transfer function. Parameters ---------- lin_AP1 : numeric or array_like *lin_AP1* value. Returns ------- numeric or ndarray *ACEScct* non-linear value. References ---------- - :cite:`TheAcademyofMotionPictureArtsandSciences2014q` - :cite:`TheAcademyofMotionPictureArtsandSciences2014r` - :cite:`TheAcademyofMotionPictureArtsandSciences2016c` - :cite:`TheAcademyofMotionPictureArtsandSciencese` Examples -------- >>> log_encoding_ACEScct(0.18) # doctest: +ELLIPSIS 0.4135884... """ constants = ACES_CCT_CONSTANTS lin_AP1 = np.asarray(lin_AP1) output = np.where(lin_AP1 <= constants.X_BRK, constants.A * lin_AP1 + constants.B, (np.log2(lin_AP1) + 9.72) / 17.52) return as_numeric(output)
def eotf_BT709(V): """ Defines *Recommendation ITU-R BT.709-6* electro-optical transfer function (EOTF / EOCF). Parameters ---------- V : numeric or array_like Electrical signal :math:`V`. Returns ------- numeric or ndarray Corresponding *luminance* :math:`L` of the image. Warning ------- *Recommendation ITU-R BT.709-6* doesn't specify an electro-optical transfer function. This definition is used for symmetry in unit tests and other computations but should not be used as an *EOTF*. Examples -------- >>> eotf_BT709(0.409007728864150) # doctest: +ELLIPSIS 0.1... """ warning(('*Recommendation ITU-R BT.709-6* doesn\'t specify an ' 'electro-optical transfer function. This definition is used ' 'for symmetry in unit tests and others computations but should ' 'not be used as an *EOTF*!')) V = np.asarray(V) return as_numeric( np.where(V < oetf_BT709(0.018), V / 4.5, ((V + 0.099) / 1.099)**(1 / 0.45)))
def log_decoding_ACEScct(ACEScct): """ Defines the *ACEScct* colourspace log decoding / electro-optical transfer function. Parameters ---------- ACEScct : numeric or array_like *ACEScct* non-linear value. Returns ------- numeric or ndarray *lin_AP1* value. References ---------- - :cite:`TheAcademyofMotionPictureArtsandSciences2014q` - :cite:`TheAcademyofMotionPictureArtsandSciences2014r` - :cite:`TheAcademyofMotionPictureArtsandSciences2016c` - :cite:`TheAcademyofMotionPictureArtsandSciencese` Examples -------- >>> log_decoding_ACEScct(0.413588402492442) # doctest: +ELLIPSIS 0.1799999... """ constants = ACES_CCT_CONSTANTS ACEScct = np.asarray(ACEScct) output = np.where(ACEScct > constants.Y_BRK, 2**(ACEScct * 17.52 - 9.72), (ACEScct - constants.B) / constants.A) return as_numeric(output)
def log_decoding_CanonLog3(clog3_ire): """ Defines the *Canon Log 3* log decoding curve / electro-optical transfer function. Parameters ---------- clog3_ire : numeric or array_like *Canon Log 3* non-linear *IRE* data. Returns ------- numeric or ndarray Linear data :math:`x`. Notes ----- - Input *Canon Log 3* non-linear *IRE* data should be converted from code value *CV* to *IRE* as follows: `IRE = (CV - 64) / (940 - 64)`. Examples -------- >>> log_decoding_CanonLog3(32.795356721989336 / 100) # doctest: +ELLIPSIS 0.2000000... """ clog3_ire = np.asarray(clog3_ire) x = np.select( (clog3_ire < 0.04076162, clog3_ire <= 0.105357102, clog3_ire > 0.105357102), (-(10**((0.069886632 - clog3_ire) / 0.42889912) - 1) / 14.98325, (clog3_ire - 0.073059361) / 2.3069815, (10**((clog3_ire - 0.069886632) / 0.42889912) - 1) / 14.98325)) return as_numeric(x)
def log_encoding_CanonLog3(x): """ Defines the *Canon Log 3* log encoding curve / opto-electronic transfer function. Parameters ---------- x : numeric or array_like Linear data :math:`x`. Returns ------- numeric or ndarray *Canon Log 3* non-linear *IRE* data. Notes ----- - Output *Canon Log 3* non-linear *IRE* data should be converted to code value *CV* as follows: `CV = IRE * (940 - 64) + 64`. Examples -------- >>> log_encoding_CanonLog3(0.20) * 100 # doctest: +ELLIPSIS 32.7953567... """ x = np.asarray(x) clog3_ire = np.select( (x < log_decoding_CanonLog3(0.04076162), x <= log_decoding_CanonLog3(0.105357102), x > log_decoding_CanonLog3(0.105357102)), (-(0.42889912 * (np.log10(-x * 14.98325 + 1)) - 0.069886632), 2.3069815 * x + 0.073059361, 0.42889912 * np.log10(x * 14.98325 + 1) + 0.069886632)) return as_numeric(clog3_ire)
def eotf_ROMMRGB(X_p, I_max=255): """ Defines the *ROMM RGB* encoding electro-optical transfer function (EOTF / EOCF). Parameters ---------- X_p : numeric or array_like Non-linear data :math:`X'_{ROMM}`. I_max : numeric, optional Maximum code value: 255, 4095 and 650535 for respectively 8-bit, 12-bit and 16-bit per channel. Returns ------- numeric or ndarray Linear data :math:`X_{ROMM}`. References ---------- - :cite:`ANSI2003a` - :cite:`Spaulding2000b` Examples -------- >>> eotf_ROMMRGB(98.356413311540095) # doctest: +ELLIPSIS 0.1... """ X_p = np.asarray(X_p) E_t = 16**(1.8 / (1 - 1.8)) return as_numeric( np.where(X_p < 16 * E_t * I_max, X_p / (16 * I_max), (X_p / I_max)**1.8))
def log_decoding_ACEScc(ACEScc): """ Defines the *ACEScc* colourspace log decoding / electro-optical transfer function. Parameters ---------- ACEScc : numeric or array_like *ACEScc* non-linear value. Returns ------- numeric or ndarray *lin_AP1* value. References ---------- - :cite:`TheAcademyofMotionPictureArtsandSciences2014q` - :cite:`TheAcademyofMotionPictureArtsandSciences2014r` - :cite:`TheAcademyofMotionPictureArtsandSciences2014t` - :cite:`TheAcademyofMotionPictureArtsandSciencese` Examples -------- >>> log_decoding_ACEScc(0.413588402492442) # doctest: +ELLIPSIS 0.1799999... """ ACEScc = np.asarray(ACEScc) output = np.where(ACEScc < (9.72 - 15) / 17.52, (2**(ACEScc * 17.52 - 9.72) - 2**-16) * 2, 2**(ACEScc * 17.52 - 9.72)) output = np.where(ACEScc >= (np.log2(65504) + 9.72) / 17.52, 65504, output) return as_numeric(output)
def log_encoding_ACEScc(lin_AP1): """ Defines the *ACEScc* colourspace log encoding / opto-electronic transfer function. Parameters ---------- lin_AP1 : numeric or array_like *lin_AP1* value. Returns ------- numeric or ndarray *ACEScc* non-linear value. References ---------- - :cite:`TheAcademyofMotionPictureArtsandSciences2014q` - :cite:`TheAcademyofMotionPictureArtsandSciences2014r` - :cite:`TheAcademyofMotionPictureArtsandSciences2014t` - :cite:`TheAcademyofMotionPictureArtsandSciencese` Examples -------- >>> log_encoding_ACEScc(0.18) # doctest: +ELLIPSIS 0.4135884... """ lin_AP1 = np.asarray(lin_AP1) output = np.where(lin_AP1 < 0, (np.log2(2**-16) + 9.72) / 17.52, (np.log2(2**-16 + lin_AP1 * 0.5) + 9.72) / 17.52) output = np.where(lin_AP1 >= 2**-15, (np.log2(lin_AP1) + 9.72) / 17.52, output) return as_numeric(output)
def oetf_BT709(L): """ Defines *Recommendation ITU-R BT.709-6* opto-electronic transfer function (OETF / OECF). Parameters ---------- L : numeric or array_like *Luminance* :math:`L` of the image. Returns ------- numeric or ndarray Corresponding electrical signal :math:`V`. Examples -------- >>> oetf_BT709(0.18) # doctest: +ELLIPSIS 0.4090077... """ L = np.asarray(L) return as_numeric(np.where(L < 0.018, L * 4.5, 1.099 * (L**0.45) - 0.099))
def CCT_to_xy_Hernandez1999(CCT, optimisation_kwargs=None, **kwargs): """ Returns the *CIE xy* chromaticity coordinates from given correlated colour temperature :math:`T_{cp}` using *Hernandez-Andres et al. (1999)* method. Parameters ---------- CCT : numeric or array_like Correlated colour temperature :math:`T_{cp}`. optimisation_kwargs : dict_like, optional Parameters for :func:`scipy.optimize.minimize` definition. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- ndarray *CIE xy* chromaticity coordinates. Warnings -------- *Hernandez-Andres et al. (1999)* method for computing *CIE xy* chromaticity coordinates from given correlated colour temperature is not a bijective function and might produce unexpected results. It is given for consistency with other correlated colour temperature computation methods but should be avoided for practical applications. The current implementation relies on optimization using :func:`scipy.optimize.minimize` definition and thus has reduced precision and poor performance. References ---------- :cite:`Hernandez-Andres1999a` Examples -------- >>> CCT_to_xy_Hernandez1999(6500.7420431786531) # doctest: +ELLIPSIS array([ 0.3127..., 0.329...]) """ optimisation_kwargs = handle_arguments_deprecation( { 'ArgumentRenamed': [['optimisation_parameters', 'optimisation_kwargs']], }, **kwargs).get('optimisation_kwargs', optimisation_kwargs) usage_warning('"Hernandez-Andres et al. (1999)" method for computing ' '"CIE xy" chromaticity coordinates from given correlated ' 'colour temperature is not a bijective function and and' 'might produce unexpected results. It is given for ' 'consistency with other correlated colour temperature ' 'computation methods but should be avoided for practical ' 'applications.') CCT = as_float_array(CCT) shape = list(CCT.shape) CCT = np.atleast_1d(CCT.reshape([-1, 1])) def objective_function(xy, CCT): """ Objective function. """ objective = np.linalg.norm(xy_to_CCT_Hernandez1999(xy) - CCT) return objective optimisation_settings = { 'method': 'Nelder-Mead', 'options': { 'fatol': 1e-10, }, } if optimisation_kwargs is not None: optimisation_settings.update(optimisation_kwargs) CCT = as_float_array([ minimize( objective_function, x0=CCS_ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65'], args=(CCT_i, ), **optimisation_settings).x for CCT_i in CCT ]) return as_numeric(CCT.reshape(shape + [2]))
def gamma_function(a, exponent=1, negative_number_handling='indeterminate'): """ Defines a typical gamma encoding / decoding function. Parameters ---------- a : numeric or array_like Array to encode / decode. exponent : numeric or array_like, optional Encoding / decoding exponent. negative_number_handling : unicode, optional **{'Indeterminate', 'Mirror', 'Preserve', 'Clamp'}**, Defines the behaviour for `a` negative numbers and / or the definition return value: - *Indeterminate*: The behaviour will be indeterminate and definition return value might contain *nans*. - *Mirror*: The definition return value will be mirrored around abscissa and ordinate axis, i.e. Blackmagic Design: Davinci Resolve behaviour. - *Preserve*: The definition will preserve any negative number in `a`, i.e. The Foundry Nuke behaviour. - *Clamp*: The definition will clamp any negative number in `a` to 0. Returns ------- numeric or ndarray Encoded / decoded array. Raises ------ ValueError If the negative number handling method is not defined. Examples -------- >>> gamma_function(0.18, 2.2) # doctest: +ELLIPSIS 0.0229932... >>> gamma_function(-0.18, 2.0) # doctest: +ELLIPSIS 0.0323999... >>> gamma_function(-0.18, 2.2) nan >>> gamma_function(-0.18, 2.2, 'Mirror') # doctest: +ELLIPSIS -0.0229932... >>> gamma_function(-0.18, 2.2, 'Preserve') # doctest: +ELLIPSIS -0.1... >>> gamma_function(-0.18, 2.2, 'Clamp') # doctest: +ELLIPSIS 0.0 """ a = np.asarray(a) exponent = np.asarray(exponent) negative_number_handling = negative_number_handling.lower() if negative_number_handling == 'indeterminate': return as_numeric(a**exponent) elif negative_number_handling == 'mirror': return as_numeric(np.sign(a) * np.abs(a)**exponent) elif negative_number_handling == 'preserve': return as_numeric(np.where(a < 0, a, a**exponent)) elif negative_number_handling == 'clamp': return as_numeric(np.where(a < 0, 0, a**exponent)) else: raise ValueError( 'Undefined negative number handling method: "{0}".'.format( negative_number_handling))
def uv_to_CCT_Krystek1985(uv, optimisation_parameters=None): """ Returns the correlated colour temperature :math:`T_{cp}` from given *CIE UCS* colourspace *uv* chromaticity coordinates using *Krystek (1985)* method. Parameters ---------- uv : array_like *CIE UCS* colourspace *uv* chromaticity coordinates. optimisation_parameters : dict_like, optional Parameters for :func:`scipy.optimize.minimize` definition. Returns ------- ndarray Correlated colour temperature :math:`T_{cp}`. Warnings -------- *Krystek (1985)* does not give an analytical inverse transformation to compute the correlated colour temperature :math:`T_{cp}` from given *CIE UCS* colourspace *uv* chromaticity coordinates, the current implementation relies on optimization using :func:`scipy.optimize.minimize` definition and thus has reduced precision and poor performance. Notes ----- - *Krystek (1985)* method computations are valid for correlated colour temperature :math:`T_{cp}` normalised to domain [1000, 15000]. References ---------- :cite:`Krystek1985b` Examples -------- >>> uv_to_CCT_Krystek1985(np.array([0.20047203, 0.31029290])) ... # doctest: +ELLIPSIS 6504.3894290... """ uv = as_float_array(uv) shape = uv.shape uv = np.atleast_1d(uv.reshape([-1, 2])) def objective_function(CCT, uv): """ Objective function. """ objective = np.linalg.norm(CCT_to_uv_Krystek1985(CCT) - uv) return objective optimisation_settings = { 'method': 'Nelder-Mead', 'options': { 'fatol': 1e-10, }, } if optimisation_parameters is not None: optimisation_settings.update(optimisation_parameters) CCT = as_float_array([ minimize(objective_function, x0=6500, args=(uv_i, ), **optimisation_settings).x for uv_i in uv ]) return as_numeric(CCT.reshape(shape[:-1]))