Coverage for colour/io/luts/tests/test_cinespace_csp.py: 100%

83 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-15 19:01 +1300

1"""Define the unit tests for the :mod:`colour.io.luts.cinespace_csp` module.""" 

2 

3from __future__ import annotations 

4 

5import os 

6import shutil 

7import tempfile 

8 

9import numpy as np 

10import pytest 

11 

12from colour.constants import TOLERANCE_ABSOLUTE_TESTS 

13from colour.hints import cast 

14from colour.io import ( 

15 LUT1D, 

16 LUT3D, 

17 LUT3x1D, 

18 LUTSequence, 

19 read_LUT_Cinespace, 

20 write_LUT_Cinespace, 

21) 

22from colour.utilities import tstack 

23 

24__author__ = "Colour Developers" 

25__copyright__ = "Copyright 2013 Colour Developers" 

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

27__maintainer__ = "Colour Developers" 

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

29__status__ = "Production" 

30 

31__all__ = [ 

32 "ROOT_LUTS", 

33 "TestReadLUTCinespace", 

34 "TestWriteLUTCinespace", 

35] 

36 

37ROOT_LUTS: str = os.path.join(os.path.dirname(__file__), "resources", "cinespace") 

38 

39 

40class TestReadLUTCinespace: 

41 """ 

42 Define :func:`colour.io.luts.cinespace_csp.read_LUT_Cinespace` definition 

43 unit tests methods. 

44 """ 

45 

46 def test_read_LUT_Cinespace(self) -> None: 

47 """ 

48 Test :func:`colour.io.luts.cinespace_csp.read_LUT_Cinespace` 

49 definition. 

50 """ 

51 

52 LUT_1 = cast( 

53 "LUT3x1D", 

54 read_LUT_Cinespace(os.path.join(ROOT_LUTS, "ACES_Proxy_10_to_ACES.csp")), 

55 ) 

56 

57 np.testing.assert_allclose( 

58 LUT_1.table, 

59 np.array( 

60 [ 

61 [4.88300000e-04, 4.88300000e-04, 4.88300000e-04], 

62 [7.71400000e-04, 7.71400000e-04, 7.71400000e-04], 

63 [1.21900000e-03, 1.21900000e-03, 1.21900000e-03], 

64 [1.92600000e-03, 1.92600000e-03, 1.92600000e-03], 

65 [3.04400000e-03, 3.04400000e-03, 3.04400000e-03], 

66 [4.80900000e-03, 4.80900000e-03, 4.80900000e-03], 

67 [7.59900000e-03, 7.59900000e-03, 7.59900000e-03], 

68 [1.20100000e-02, 1.20100000e-02, 1.20100000e-02], 

69 [1.89700000e-02, 1.89700000e-02, 1.89700000e-02], 

70 [2.99800000e-02, 2.99800000e-02, 2.99800000e-02], 

71 [4.73700000e-02, 4.73700000e-02, 4.73700000e-02], 

72 [7.48400000e-02, 7.48400000e-02, 7.48400000e-02], 

73 [1.18300000e-01, 1.18300000e-01, 1.18300000e-01], 

74 [1.86900000e-01, 1.86900000e-01, 1.86900000e-01], 

75 [2.95200000e-01, 2.95200000e-01, 2.95200000e-01], 

76 [4.66500000e-01, 4.66500000e-01, 4.66500000e-01], 

77 [7.37100000e-01, 7.37100000e-01, 7.37100000e-01], 

78 [1.16500000e00, 1.16500000e00, 1.16500000e00], 

79 [1.84000000e00, 1.84000000e00, 1.84000000e00], 

80 [2.90800000e00, 2.90800000e00, 2.90800000e00], 

81 [4.59500000e00, 4.59500000e00, 4.59500000e00], 

82 [7.26000000e00, 7.26000000e00, 7.26000000e00], 

83 [1.14700000e01, 1.14700000e01, 1.14700000e01], 

84 [1.81300000e01, 1.81300000e01, 1.81300000e01], 

85 [2.86400000e01, 2.86400000e01, 2.86400000e01], 

86 [4.52500000e01, 4.52500000e01, 4.52500000e01], 

87 [7.15100000e01, 7.15100000e01, 7.15100000e01], 

88 [1.13000000e02, 1.13000000e02, 1.13000000e02], 

89 [1.78500000e02, 1.78500000e02, 1.78500000e02], 

90 [2.82100000e02, 2.82100000e02, 2.82100000e02], 

91 [4.45700000e02, 4.45700000e02, 4.45700000e02], 

92 [7.04300000e02, 7.04300000e02, 7.04300000e02], 

93 ] 

94 ), 

95 atol=TOLERANCE_ABSOLUTE_TESTS, 

96 ) 

97 assert LUT_1.name == "ACES Proxy 10 to ACES" 

98 assert LUT_1.dimensions == 2 

99 np.testing.assert_array_equal(LUT_1.domain, np.array([[0, 0, 0], [1, 1, 1]])) 

100 assert LUT_1.size == 32 

101 assert LUT_1.comments == [] 

102 

103 LUT_2 = cast("LUT3x1D", read_LUT_Cinespace(os.path.join(ROOT_LUTS, "Demo.csp"))) 

104 assert LUT_2.comments == ["Comments are ignored by most parsers"] 

105 np.testing.assert_array_equal(LUT_2.domain, np.array([[0, 0, 0], [1, 2, 3]])) 

106 

107 LUT_3 = cast( 

108 "LUT3D", 

109 read_LUT_Cinespace(os.path.join(ROOT_LUTS, "Three_Dimensional_Table.csp")), 

110 ) 

111 assert LUT_3.dimensions == 3 

112 assert LUT_3.size == 2 

113 

114 LUT_4 = cast( 

115 "LUTSequence", 

116 read_LUT_Cinespace(os.path.join(ROOT_LUTS, "Explicit_Domain.csp")), 

117 ) 

118 assert LUT_4[0].is_domain_explicit() is True 

119 assert LUT_4[1].table.shape == (2, 3, 4, 3) 

120 

121 LUT_5 = cast( 

122 "LUTSequence", 

123 read_LUT_Cinespace( 

124 os.path.join(ROOT_LUTS, "Uncommon_3x1D_With_Pre_Lut.csp") 

125 ), 

126 ) 

127 assert isinstance(LUT_5[0], LUT3x1D) 

128 assert isinstance(LUT_5[1], LUT3x1D) 

129 

130 

131class TestWriteLUTCinespace: 

132 """ 

133 Define :func:`colour.io.luts.cinespace_csp.write_LUT_Cinespace` definition 

134 unit tests methods. 

135 """ 

136 

137 def setup_method(self) -> None: 

138 """Initialise the common tests attributes.""" 

139 

140 self._temporary_directory = tempfile.mkdtemp() 

141 

142 def teardown_method(self) -> None: 

143 """After tests actions.""" 

144 

145 shutil.rmtree(self._temporary_directory) 

146 

147 def test_write_LUT_Cinespace(self) -> None: 

148 """ 

149 Test :func:`colour.io.luts.cinespace_csp.write_LUT_Cinespace` 

150 definition. 

151 """ 

152 

153 LUT_1_r = read_LUT_Cinespace( 

154 os.path.join(ROOT_LUTS, "ACES_Proxy_10_to_ACES.csp") 

155 ) 

156 write_LUT_Cinespace( 

157 LUT_1_r, 

158 os.path.join(self._temporary_directory, "ACES_Proxy_10_to_ACES.csp"), 

159 ) 

160 LUT_1_t = read_LUT_Cinespace( 

161 os.path.join(self._temporary_directory, "ACES_Proxy_10_to_ACES.csp") 

162 ) 

163 assert LUT_1_r == LUT_1_t 

164 assert LUT_1_r == LUT_1_t 

165 

166 LUT_2_r = cast( 

167 "LUT3x1D", read_LUT_Cinespace(os.path.join(ROOT_LUTS, "Demo.csp")) 

168 ) 

169 write_LUT_Cinespace( 

170 LUT_2_r, os.path.join(self._temporary_directory, "Demo.csp") 

171 ) 

172 LUT_2_t = cast( 

173 "LUT3x1D", 

174 read_LUT_Cinespace(os.path.join(self._temporary_directory, "Demo.csp")), 

175 ) 

176 assert LUT_2_r == LUT_2_t 

177 assert LUT_2_r.comments == LUT_2_t.comments 

178 

179 LUT_3_r = cast( 

180 "LUT3D", 

181 read_LUT_Cinespace(os.path.join(ROOT_LUTS, "Three_Dimensional_Table.csp")), 

182 ) 

183 write_LUT_Cinespace( 

184 LUT_3_r, 

185 os.path.join(self._temporary_directory, "Three_Dimensional_Table.csp"), 

186 ) 

187 LUT_3_t = cast( 

188 "LUT3D", 

189 read_LUT_Cinespace( 

190 os.path.join(self._temporary_directory, "Three_Dimensional_Table.csp") 

191 ), 

192 ) 

193 assert LUT_3_r == LUT_3_t 

194 

195 domain = tstack( 

196 ( 

197 np.array([0.0, 0.1, 0.2, 0.4, 0.8, 1.2]), 

198 np.array([-0.1, 0.5, 1.0, np.nan, np.nan, np.nan]), 

199 np.array([-1.0, -0.5, 0.0, 0.5, 1.0, np.nan]), 

200 ) 

201 ) 

202 LUT_4_t = LUT3x1D(domain=domain, table=domain * 2, name="Ragged Domain") 

203 write_LUT_Cinespace( 

204 LUT_4_t, 

205 os.path.join(self._temporary_directory, "Ragged_Domain.csp"), 

206 ) 

207 LUT_4_r = cast( 

208 "LUT3x1D", read_LUT_Cinespace(os.path.join(ROOT_LUTS, "Ragged_Domain.csp")) 

209 ) 

210 np.testing.assert_allclose( 

211 LUT_4_t.domain, LUT_4_r.domain, atol=TOLERANCE_ABSOLUTE_TESTS 

212 ) 

213 np.testing.assert_allclose(LUT_4_t.table, LUT_4_r.table, atol=5e-5) 

214 

215 LUT_5_r = cast( 

216 "LUTSequence", 

217 read_LUT_Cinespace( 

218 os.path.join(ROOT_LUTS, "Three_Dimensional_Table_With_Shaper.csp") 

219 ), 

220 ) 

221 LUT_5_r.sequence[0] = LUT_5_r.sequence[0].convert( # pyright: ignore 

222 LUT1D, force_conversion=True 

223 ) 

224 write_LUT_Cinespace( 

225 LUT_5_r, 

226 os.path.join( 

227 self._temporary_directory, 

228 "Three_Dimensional_Table_With_Shaper.csp", 

229 ), 

230 ) 

231 LUT_5_r = cast( 

232 "LUTSequence", 

233 read_LUT_Cinespace( 

234 os.path.join(ROOT_LUTS, "Three_Dimensional_Table_With_Shaper.csp") 

235 ), 

236 ) 

237 LUT_5_t = cast( 

238 "LUTSequence", 

239 read_LUT_Cinespace( 

240 os.path.join( 

241 self._temporary_directory, 

242 "Three_Dimensional_Table_With_Shaper.csp", 

243 ) 

244 ), 

245 ) 

246 assert LUT_5_r == LUT_5_t 

247 

248 LUT_6_r = cast( 

249 "LUTSequence", 

250 read_LUT_Cinespace( 

251 os.path.join(ROOT_LUTS, "Three_Dimensional_Table_With_Shaper.csp") 

252 ), 

253 ) 

254 LUT_6_r.sequence[0] = LUT_6_r.sequence[0].convert( # pyright: ignore 

255 LUT3x1D, force_conversion=True 

256 ) 

257 write_LUT_Cinespace( 

258 LUT_6_r, 

259 os.path.join( 

260 self._temporary_directory, 

261 "Three_Dimensional_Table_With_Shaper.csp", 

262 ), 

263 ) 

264 LUT_6_r = cast( 

265 "LUTSequence", 

266 read_LUT_Cinespace( 

267 os.path.join(ROOT_LUTS, "Three_Dimensional_Table_With_Shaper.csp") 

268 ), 

269 ) 

270 LUT_6_t = cast( 

271 "LUTSequence", 

272 read_LUT_Cinespace( 

273 os.path.join( 

274 self._temporary_directory, 

275 "Three_Dimensional_Table_With_Shaper.csp", 

276 ) 

277 ), 

278 ) 

279 assert LUT_6_r == LUT_6_t 

280 

281 LUT_7_r = cast( 

282 "LUT3x1D", 

283 read_LUT_Cinespace(os.path.join(ROOT_LUTS, "ACES_Proxy_10_to_ACES.csp")), 

284 ) 

285 write_LUT_Cinespace( 

286 cast("LUT1D", LUT_7_r.convert(LUT1D, force_conversion=True)), 

287 os.path.join(self._temporary_directory, "ACES_Proxy_10_to_ACES.csp"), 

288 ) 

289 LUT_7_t = cast( 

290 "LUT3x1D", 

291 read_LUT_Cinespace( 

292 os.path.join(self._temporary_directory, "ACES_Proxy_10_to_ACES.csp") 

293 ), 

294 ) 

295 assert LUT_7_r == LUT_7_t 

296 

297 def test_raise_exception_write_LUT_Cinespace(self) -> None: 

298 """ 

299 Test :func:`colour.io.luts.cinespace_csp.write_LUT_Cinespace` 

300 definition raised exception. 

301 """ 

302 

303 pytest.raises(TypeError, write_LUT_Cinespace, object(), "")