Coverage for tests/test_bbox.py: 11%

134 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-05-01 15:13 -0700

1# This file is part of scarlet_lite. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22import numpy as np 

23from lsst.scarlet.lite import Box 

24from utils import ScarletTestCase 

25 

26 

27class TestBox(ScarletTestCase): 

28 def check_bbox(self, bbox: Box, shape: tuple[int, ...], origin: tuple[int, ...]): 

29 """Check the attributes and properties of a Box 

30 

31 Parameters 

32 ---------- 

33 bbox: 

34 The box to test. 

35 shape: 

36 The shape of the Box. 

37 origin: 

38 The origin of the Box. 

39 """ 

40 self.assertTupleEqual(bbox.shape, shape) 

41 self.assertTupleEqual(bbox.origin, origin) 

42 self.assertEqual(bbox.ndim, len(shape)) 

43 self.assertTupleEqual(bbox.start, origin) 

44 

45 def test_constructors(self): 

46 shape = (2, 3, 4) 

47 origin = (0, 0, 0) 

48 bbox = Box(shape) 

49 self.check_bbox(bbox, shape=shape, origin=origin) 

50 

51 shape = (2, 4) 

52 origin = (5, 6) 

53 bbox = Box(shape, origin) 

54 self.check_bbox(bbox, shape=shape, origin=origin) 

55 

56 bbox = Box.from_bounds((5, 7), (6, 10)) 

57 self.check_bbox(bbox, shape, origin) 

58 

59 def test_from_data(self): 

60 x = np.arange(25).reshape(5, 5) 

61 x[0] = 0 

62 x[:, -2:] = 0 

63 bbox = Box.from_data(x) 

64 self.assertBoxEqual(bbox, Box((4, 3), origin=(1, 0))) 

65 

66 x += 10 

67 bbox = Box.from_data(x) 

68 self.assertBoxEqual(bbox, Box((5, 5), origin=(0, 0))) 

69 

70 bbox = Box.from_data(x, threshold=10) 

71 self.assertBoxEqual(bbox, Box((4, 3), origin=(1, 0))) 

72 

73 bbox = Box.from_data(x, threshold=100) 

74 self.assertBoxEqual(bbox, Box((0, 0), origin=(0, 0))) 

75 

76 def test_contains(self): 

77 bbox = Box((6, 4, 3), origin=(0, 1, 0)) 

78 p = (2, 2, 2) 

79 self.assertTrue(bbox.contains(p)) 

80 

81 p = (3, 0, 3) 

82 self.assertFalse(bbox.contains(p)) 

83 

84 p = (7, 3, 3) 

85 self.assertFalse(bbox.contains(p)) 

86 

87 p = (3, 3, -1) 

88 self.assertFalse(bbox.contains(p)) 

89 

90 with self.assertRaises(ValueError): 

91 bbox.contains((1, 2)) 

92 

93 def test_properties(self): 

94 shape = (10, 3, 8) 

95 origin = (2, 7, 5) 

96 bbox = Box(shape, origin) 

97 self.assertTupleEqual(bbox.stop, (12, 10, 13)) 

98 self.assertTupleEqual(bbox.center, (7, 8.5, 9)) 

99 self.assertTupleEqual(bbox.bounds, ((2, 12), (7, 10), (5, 13))) 

100 self.assertTupleEqual(bbox.shape, shape) 

101 self.assertTupleEqual(bbox.origin, origin) 

102 self.assertEqual(len(bbox.slices), 3) 

103 self.assertEqual(bbox.slices[0], slice(2, 12)) 

104 self.assertEqual(bbox.slices[1], slice(7, 10)) 

105 self.assertEqual(bbox.slices[2], slice(5, 13)) 

106 self.assertEqual(hash(bbox), hash((shape, origin))) 

107 

108 def test_simple_methods(self): 

109 shape = (2, 4, 8, 16) 

110 origin = (9, 5, 3, 9) 

111 bbox = Box(shape, origin) 

112 self.check_bbox(bbox, shape, origin) 

113 

114 # Grow the box 

115 grown = bbox.grow(3) 

116 self.check_bbox(grown, (8, 10, 14, 22), (6, 2, 0, 6)) 

117 

118 # Shift the box 

119 shifted = bbox.shifted_by((0, 5, 2, 10)) 

120 self.check_bbox(shifted, shape, (9, 10, 5, 19)) 

121 

122 def test_union(self): 

123 bbox1 = Box((3, 4), (20, 34)) 

124 bbox2 = Box((10, 15), (1, 2)) 

125 bbox3 = Box((20, 30, 40), (10, 20, 30)) 

126 

127 result = bbox1 | bbox2 

128 truth = Box((22, 36), (1, 2)) 

129 self.assertBoxEqual(result, truth) 

130 

131 with self.assertRaises(ValueError): 

132 bbox1 | bbox3 

133 

134 def test_intersection(self): 

135 bbox1 = Box((3, 4), (20, 34)) 

136 bbox2 = Box((20, 30), (10, 20)) 

137 bbox3 = Box((20, 30, 40), (10, 20, 30)) 

138 

139 result = bbox1 & bbox2 

140 truth = Box((3, 4), (20, 34)) 

141 self.assertBoxEqual(result, truth) 

142 

143 with self.assertRaises(ValueError): 

144 bbox1 & bbox3 

145 

146 def test_intersections(self): 

147 bbox1 = Box((3, 4), (20, 34)) 

148 bbox2 = Box((10, 15), (1, 2)) 

149 bbox3 = Box((20, 30), (10, 20)) 

150 

151 # Test intersection test 

152 self.assertFalse(bbox1.intersects(bbox2)) 

153 self.assertTrue(bbox1.intersects(bbox3)) 

154 self.assertFalse(bbox2.intersects(bbox1)) 

155 self.assertFalse(bbox2.intersects(bbox3)) 

156 self.assertTrue(bbox3.intersects(bbox1)) 

157 

158 # Test overlapping slices 

159 slices = bbox1.overlapped_slices(bbox2) 

160 self.assertTupleEqual(slices, ((slice(0, 0), slice(0, 0)), (slice(0, 0), slice(0, 0)))) 

161 slices = bbox1.overlapped_slices(bbox3) 

162 self.assertTupleEqual(slices, ((slice(0, 3), slice(0, 4)), (slice(10, 13), (slice(14, 18))))) 

163 

164 def test_offset(self): 

165 shape = (2, 5, 7) 

166 origin = (82, 34, 15) 

167 bbox = Box(shape, origin) 

168 bbox = bbox + 1 

169 self.assertBoxEqual(bbox, Box(shape, (83, 35, 16))) 

170 

171 def test_arithmetic(self): 

172 shape = (2, 5, 7) 

173 origin = (82, 34, 15) 

174 bbox = Box(shape, origin) 

175 

176 # Check addition 

177 shifted = bbox + (2, 4, 6) 

178 self.check_bbox(bbox, shape, origin) 

179 self.check_bbox(shifted, shape, (84, 38, 21)) 

180 

181 # Check subtraction 

182 shifted = bbox - (2, 4, 6) 

183 self.check_bbox(bbox, shape, origin) 

184 self.check_bbox(shifted, shape, (80, 30, 9)) 

185 

186 # Check "matrix multiplication" 

187 prebox = Box((2, 5), (3, 4)) 

188 new_box = prebox @ bbox 

189 self.check_bbox(new_box, (2, 5, 2, 5, 7), (3, 4, 82, 34, 15)) 

190 

191 # Check equality 

192 bbox1 = Box((1, 2, 3), (2, 4, 6)) 

193 bbox2 = Box((1, 2, 3), (2, 4, 6)) 

194 bbox3 = Box((1, 2), (5, 6)) 

195 

196 self.assertBoxEqual(bbox1, bbox2) 

197 with self.assertRaises(AssertionError): 

198 self.assertBoxEqual(bbox2, bbox3) 

199 

200 # Check a copy 

201 bbox2 = bbox.copy() 

202 self.assertBoxEqual(bbox, bbox2) 

203 

204 self.assertFalse(bbox1 == shape) 

205 self.assertNotEqual(bbox1, bbox2) 

206 self.assertEqual(bbox1, bbox1) 

207 

208 def test_slicing(self): 

209 bbox = Box((1, 2, 3, 4), (2, 4, 6, 8)) 

210 # Check integer index 

211 self.assertBoxEqual(bbox[2], Box((3,), (6,))) 

212 # check slice index 

213 self.assertBoxEqual(bbox[:3], Box((1, 2, 3), (2, 4, 6))) 

214 # check tuple index 

215 self.assertBoxEqual(bbox[(3, 1)], Box((4, 2), (8, 4)))