Coverage for utilities/metrics.py: 30%

1"""

2 Metrics

3=======

4

5 Define various metrics for evaluating signal quality and comparing data:

6

7- :func:`colour.utilities.metric_mse`

8- :func:`colour.utilities.metric_psnr`

9

10 References

11----------

12- :cite:`Wikipedia2003c` : Wikipedia. (2003). Mean squared error. Retrieved

13 March 5, 2018, from https://en.wikipedia.org/wiki/Mean_squared_error

14- :cite:`Wikipedia2004` : Wikipedia. (2004). Peak signal-to-noise ratio.

15 Retrieved March 5, 2018, from

16 https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio

17"""

18

19 from __future__ import annotations

20

21 import typing

22

23 import numpy as np

24

25 from colour.algebra import sdiv, sdiv_mode

26

27 if typing.TYPE_CHECKING:

28 from colour.hints import (

29 ArrayLike,

30 NDArrayFloat,

31 Real,

32 Tuple,

33 )

34

35 from colour.utilities import as_float, as_float_array, zeros

36

37 __author__ = "Colour Developers"

38 __copyright__ = "Copyright 2013 Colour Developers"

39 __license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"

40 __maintainer__ = "Colour Developers"

41 __email__ = "colour-developers@colour-science.org"

42 __status__ = "Production"

43

44 __all__ = [

45 "metric_mse",

46 "metric_psnr",

47]

48

49

50 def metric_mse(

51 a: ArrayLike,

52 b: ArrayLike,

53 axis: int | Tuple[int] | None = None,

54) -> NDArrayFloat:

55 """

56 Compute the mean squared error (MSE) between the specified arrays

57 :math:`a` and :math:`b`.

58

59 Parameters

60 ----------

61 a

62 Variable :math:`a`.

63 b

64 Variable :math:`b`.

65 axis

66 Axis or axes along which the means are computed. The default is to

67 compute the mean of the flattened array. If this is a tuple of

68 integers, a mean is performed over multiple axes instead of a

69 single axis or all the axes as before.

70

71 Returns

72 -------

73 :class:`numpy.ndarray`

74 Mean squared error (MSE).

75

76 References

77 ----------

78 :cite:`Wikipedia2003c`

79

80 Examples

81 --------

82 >>> a = np.array([0.48222001, 0.31654775, 0.22070353])

83 >>> b = a * 0.9

84 >>> metric_mse(a, b) # doctest: +ELLIPSIS

85 0.0012714...

86 """

87

88 return as_float(np.mean((as_float_array(a) - as_float_array(b)) ** 2, axis=axis))

89

90

91 def metric_psnr(

92 a: ArrayLike,

93 b: ArrayLike,

94 max_a: Real = 1,

95 axis: int | Tuple[int] | None = None,

96) -> NDArrayFloat:

97 """

98 Compute the peak signal-to-noise ratio (PSNR) between the specified

99 arrays :math:`a` and :math:`b`.

100

101 Parameters

102 ----------

103 a

104 Array :math:`a`.

105 b

106 Array :math:`b`.

107 max_a

108 Maximum possible value of the array :math:`a`.

109 axis

110 Axis or axes along which the means are computed. The default is

111 to compute the mean of the flattened array. If this is a tuple

112 of integers, a mean is performed over multiple axes, instead of

113 a single axis or all the axes as before.

114

115 Returns

116 -------

117 :class:`numpy.ndarray`

118 Peak signal-to-noise ratio (PSNR).

119

120 References

121 ----------

122 :cite:`Wikipedia2004`

123

124 Examples

125 --------

126 >>> a = np.array([0.48222001, 0.31654775, 0.22070353])

127 >>> b = a * 0.9

128 >>> metric_psnr(a, b) # doctest: +ELLIPSIS

129 28.9568515...

130 """

131

132 mse = as_float_array(metric_mse(a, b, axis))

133 psnr = zeros(mse.shape)

134

135 with sdiv_mode():

136 psnr[mse != 0] = 10 * np.log10(sdiv(max_a**2, mse[mse != 0]))

137

138 return as_float(psnr)