Coverage for tests/test_multiband.py: 11%

570 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-13 16:27 -0700

1# This file is part of afw. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://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 <http://www.gnu.org/licenses/>. 

21 

22""" 

23Tests for Multiband objects 

24""" 

25import unittest 

26import operator 

27 

28import numpy as np 

29 

30import lsst.utils 

31import lsst.utils.tests 

32from lsst.geom import Point2I, Box2I, Extent2I 

33from lsst.afw.geom import SpanSet, Stencil 

34from lsst.afw.detection import GaussianPsf, Footprint, makeHeavyFootprint, MultibandFootprint, HeavyFootprintF 

35from lsst.afw.image import ImageF, Mask, MaskPixel, MaskedImage, ExposureF, MaskedImageF, LOCAL 

36from lsst.afw.image import MultibandPixel, MultibandImage, MultibandMask, MultibandMaskedImage 

37from lsst.afw.image import MultibandExposure 

38 

39 

40def _testImageFilterSlicing(testCase, mImage, singleType, bbox, value): 

41 """Test slicing by filters for image-like objects""" 

42 testCase.assertIsInstance(mImage["R"], singleType) 

43 testCase.assertIsInstance(mImage[:], type(mImage)) 

44 

45 testCase.assertEqual(mImage["G", -1, -1, LOCAL], value) 

46 testCase.assertEqual(mImage["G"].array.shape, (100, 200)) 

47 testCase.assertEqual(mImage[:"I"].array.shape, (2, 100, 200)) 

48 testCase.assertEqual(mImage[:"I"].filters, ("G", "R")) 

49 testCase.assertEqual(mImage[:"I"].getBBox(), bbox) 

50 testCase.assertEqual(mImage[["G", "I"]].array.shape, (2, 100, 200)) 

51 testCase.assertEqual(mImage[["G", "I"]].filters, ("G", "I")) 

52 testCase.assertEqual(mImage[["G", "I"]].getBBox(), bbox) 

53 

54 testCase.assertEqual(mImage["G":"R"].filters, ("G",)) 

55 

56 if "Z" in mImage.filters: 

57 filterSlice = slice("R", "Z") 

58 else: 

59 filterSlice = slice("R", None) 

60 testCase.assertEqual(mImage[filterSlice].filters, ("R", "I")) 

61 testCase.assertEqual(mImage.filters, tuple(testCase.filters)) 

62 

63 

64def _testImageSlicing(testCase, mImage, gVal, rVal, iVal): 

65 """Test slicing in the spatial dimensions for image-like objects""" 

66 testCase.assertIsInstance(mImage[:, -1, -1, LOCAL], MultibandPixel) 

67 testCase.assertEqual(mImage["G", -1, -1, LOCAL], gVal) 

68 

69 testCase.assertEqual(mImage[:, 1100:, 2025:].getBBox(), Box2I(Point2I(1100, 2025), Extent2I(100, 75))) 

70 testCase.assertEqual(mImage[:, -20:-10, -10:-5, LOCAL].getBBox(), 

71 Box2I(Point2I(1180, 2090), Extent2I(10, 5))) 

72 testCase.assertEqual(mImage[:, :1100, :2050].getBBox(), Box2I(Point2I(1000, 2000), Extent2I(100, 50))) 

73 coord = Point2I(1075, 2015) 

74 bbox = Box2I(Point2I(1050, 2010), coord) 

75 testCase.assertEqual(mImage[:, bbox].getBBox(), bbox) 

76 testCase.assertEqual(mImage[:, 1010, 2010].getBBox().getMin(), Point2I(1010, 2010)) 

77 testCase.assertEqual(mImage[:, Point2I(1075, 2015)].getBBox().getMin(), coord) 

78 

79 testCase.assertEqual(mImage["G", 1100:, 2025:].getBBox(), Box2I(Point2I(1100, 2025), Extent2I(100, 75))) 

80 testCase.assertEqual(mImage["R", -20:-10, -10:-5, LOCAL].getBBox(), 

81 Box2I(Point2I(1180, 2090), Extent2I(10, 5))) 

82 testCase.assertEqual(mImage["I", :1100, :2050].getBBox(), Box2I(Point2I(1000, 2000), Extent2I(100, 50))) 

83 testCase.assertEqual(mImage["R", bbox].getBBox(), bbox) 

84 testCase.assertEqual(mImage["I", 1010, 2010], iVal) 

85 testCase.assertEqual(mImage["R", Point2I(1075, 2015)], rVal) 

86 

87 with testCase.assertRaises(TypeError): 

88 mImage[:, 0] 

89 with testCase.assertRaises(TypeError): 

90 mImage[:, 10:] 

91 with testCase.assertRaises(TypeError): 

92 mImage[:, :10] 

93 with testCase.assertRaises(TypeError): 

94 mImage[:, :, 0] 

95 

96 

97def _testImageModification(testCase, mImage1, mImage2, bbox1, bbox2, value1, value2): 

98 """Test the image-like objects can be modified""" 

99 mImage1[:"R", bbox2].array = value2 

100 testCase.assertFloatsEqual(mImage1["G", bbox2].array, mImage2["G"].array) 

101 testCase.assertFloatsEqual(mImage1["R"].array, value1) 

102 mImage1.setXY0(Point2I(500, 150)) 

103 testCase.assertEqual(mImage1.getBBox(), Box2I(Point2I(500, 150), Extent2I(bbox1.getDimensions()))) 

104 

105 mImage1["G"].array[:] = value2 

106 testCase.assertFloatsEqual(mImage1["G"].array, value2) 

107 testCase.assertFloatsEqual(mImage1.array[0], value2) 

108 

109 if "Z" in mImage1.filters: 

110 filterSlice = slice("R", "Z") 

111 else: 

112 filterSlice = slice("R", None) 

113 mImage1[filterSlice].array[:] = 7 

114 testCase.assertFloatsEqual(mImage1["I"].array, 7) 

115 newBBox = Box2I(Point2I(10000, 20000), mImage1.getBBox().getDimensions()) 

116 mImage1.setXY0(newBBox.getMin()) 

117 testCase.assertEqual(mImage1.getBBox(), newBBox) 

118 for image in mImage1: 

119 testCase.assertEqual(image.getBBox(), newBBox) 

120 

121 # Uncomment this test when DM-10781 is implemented 

122 # offset = Extent2I(-9000, -18000) 

123 # mImage1.shiftedBy(offset) 

124 # newBBox = Box2I(Point2I(1000, 2000), newBBox.getDimensions()) 

125 # testCase.assertEqual(mImage1.getBBox(), newBBox) 

126 # for image in mImage1: 

127 # testCase.assertEqual(image.getBBox(), newBBox) 

128 

129 

130def _testImageCopy(testCase, mImage1, value1, value2): 

131 """Test copy and deep copy in image-like objects""" 

132 mImage2 = mImage1.clone() 

133 mImage2.setXY0(Point2I(11, 23)) 

134 testCase.assertEqual(mImage2.getBBox(), Box2I(Point2I(11, 23), Extent2I(200, 100))) 

135 testCase.assertEqual(mImage1.getBBox(), Box2I(Point2I(1000, 2000), Extent2I(200, 100))) 

136 testCase.assertTrue(np.all([s.getBBox() == mImage1.getBBox() for s in mImage1.singles])) 

137 testCase.assertTrue(np.all([s.getBBox() == mImage2.getBBox() for s in mImage2.singles])) 

138 mImage2.array[:] = 17 

139 testCase.assertNotEqual(mImage1.array[0, 0, 0], 17) 

140 

141 mImage2.array[:] = value2 

142 testCase.assertFloatsEqual(mImage1.array, value1) 

143 testCase.assertFloatsEqual(mImage2.array, value2) 

144 testCase.assertFloatsEqual(mImage1["G"].array, value1) 

145 testCase.assertFloatsEqual(mImage2["G"].array, value2) 

146 

147 mImage2 = mImage1.clone(False) 

148 mImage2.setXY0(Point2I(11, 23)) 

149 mImage2.array[:] = 17 

150 testCase.assertFloatsEqual(mImage2.array, mImage1.array) 

151 

152 mImage2.array[:] = value2 

153 testCase.assertFloatsEqual(mImage1.array, value2) 

154 testCase.assertFloatsEqual(mImage2.array, value2) 

155 testCase.assertFloatsEqual(mImage1["G"].array, value2) 

156 testCase.assertFloatsEqual(mImage2["G"].array, value2) 

157 

158 

159class MultibandPixelTestCase(lsst.utils.tests.TestCase): 

160 """Test case for MultibandPixel 

161 """ 

162 def setUp(self): 

163 np.random.seed(1) 

164 self.bbox = Point2I(101, 502) 

165 self.filters = ["G", "R", "I", "Z", "Y"] 

166 singles = np.arange(5, dtype=float) 

167 self.pixel = MultibandPixel(self.filters, singles, self.bbox) 

168 

169 def tearDown(self): 

170 del self.bbox 

171 del self.filters 

172 del self.pixel 

173 

174 def testFilterSlicing(self): 

175 pixel = self.pixel 

176 self.assertEqual(pixel["R"], 1.) 

177 self.assertFloatsEqual(pixel.array, np.arange(5)) 

178 self.assertFloatsEqual(pixel.singles, np.arange(5)) 

179 self.assertFloatsEqual(pixel[["G", "I"]].array, [0, 2]) 

180 

181 def testPixelBBoxModification(self): 

182 pixel = self.pixel.clone() 

183 otherPixel = pixel.clone() 

184 pixel.getBBox().shift(Extent2I(9, -2)) 

185 self.assertEqual(pixel.getBBox().getMin(), Point2I(110, 500)) 

186 self.assertEqual(otherPixel.getBBox().getMin(), Point2I(101, 502)) 

187 

188 pixel = self.pixel.clone() 

189 otherPixel = pixel.clone(False) 

190 pixel.getBBox().shift(Extent2I(9, -2)) 

191 self.assertEqual(pixel.getBBox().getMin(), Point2I(110, 500)) 

192 self.assertEqual(otherPixel.getBBox().getMin(), Point2I(110, 500)) 

193 

194 def testPixelModification(self): 

195 pixel = self.pixel 

196 otherPixel = pixel.clone() 

197 otherPixel.array = np.arange(10, 15) 

198 self.assertFloatsEqual(otherPixel.array, np.arange(10, 15)) 

199 self.assertFloatsEqual(pixel.array, np.arange(0, 5)) 

200 

201 

202class MultibandImageTestCase(lsst.utils.tests.TestCase): 

203 """Test case for MultibandImage""" 

204 

205 def setUp(self): 

206 np.random.seed(1) 

207 self.bbox1 = Box2I(Point2I(1000, 2000), Extent2I(200, 100)) 

208 self.filters = ["G", "R", "I", "Z", "Y"] 

209 self.value1, self.value2 = 10, 100 

210 images = [ImageF(self.bbox1, self.value1) for f in self.filters] 

211 self.mImage1 = MultibandImage.fromImages(self.filters, images) 

212 self.bbox2 = Box2I(Point2I(1100, 2025), Extent2I(30, 50)) 

213 images = [ImageF(self.bbox2, self.value2) for f in self.filters] 

214 self.mImage2 = MultibandImage.fromImages(self.filters, images) 

215 

216 def tearDown(self): 

217 del self.bbox1 

218 del self.bbox2 

219 del self.filters 

220 del self.value1 

221 del self.value2 

222 del self.mImage1 

223 del self.mImage2 

224 

225 def testFilterSlicing(self): 

226 _testImageFilterSlicing(self, self.mImage1, ImageF, self.bbox1, self.value1) 

227 

228 def testImageSlicing(self): 

229 _testImageSlicing(self, self.mImage1, self.value1, self.value1, self.value1) 

230 

231 def testImageModification(self): 

232 _testImageModification(self, self.mImage1, self.mImage2, self.bbox1, self.bbox2, 

233 self.value1, self.value2) 

234 

235 def testImageCopy(self): 

236 _testImageCopy(self, self.mImage1, self.value1, 5.) 

237 

238 

239class MultibandMaskTestCase(lsst.utils.tests.TestCase): 

240 """A test case for Mask""" 

241 

242 def setUp(self): 

243 np.random.seed(1) 

244 self.filters = ["G", "R", "I"] 

245 self.Mask = Mask[MaskPixel] 

246 

247 # Store the default mask planes for later use 

248 maskPlaneDict = self.Mask().getMaskPlaneDict() 

249 self.defaultMaskPlanes = sorted(maskPlaneDict, key=maskPlaneDict.__getitem__) 

250 

251 # reset so tests will be deterministic 

252 self.Mask.clearMaskPlaneDict() 

253 for p in ("BAD", "SAT", "INTRP", "CR", "EDGE"): 

254 self.Mask.addMaskPlane(p) 

255 

256 self.BAD = self.Mask.getPlaneBitMask("BAD") 

257 self.CR = self.Mask.getPlaneBitMask("CR") 

258 self.EDGE = self.Mask.getPlaneBitMask("EDGE") 

259 

260 self.values1 = [self.BAD | self.CR, self.BAD | self.EDGE, self.BAD | self.CR | self.EDGE] 

261 self.bbox = Box2I(Point2I(1000, 2000), Extent2I(200, 100)) 

262 singles = [self.Mask(self.bbox) for f in range(len(self.filters))] 

263 for n in range(len(singles)): 

264 singles[n].set(self.values1[n]) 

265 self.mMask1 = MultibandMask.fromMasks(self.filters, singles) 

266 

267 self.values2 = [self.EDGE, self.BAD, self.CR | self.EDGE] 

268 singles = [self.Mask(self.bbox) for f in range(len(self.filters))] 

269 for n in range(len(singles)): 

270 singles[n].set(self.values2[n]) 

271 self.mMask2 = MultibandMask.fromMasks(self.filters, singles) 

272 

273 def tearDown(self): 

274 del self.mMask1 

275 del self.mMask2 

276 del self.bbox 

277 del self.values1 

278 del self.values2 

279 # Reset the mask plane to the default 

280 self.Mask.clearMaskPlaneDict() 

281 for p in self.defaultMaskPlanes: 

282 self.Mask.addMaskPlane(p) 

283 self.defaultMaskPlanes 

284 

285 def testInitializeMasks(self): 

286 self.assertTrue(np.all([s.getBBox() == self.mMask1.getBBox() for s in self.mMask1.singles])) 

287 self.assertTrue(np.all([s.array == self.values1[n] for n, s in enumerate(self.mMask1.singles)])) 

288 

289 def _bitOperator(self, op): 

290 op(self.mMask2, self.mMask1) 

291 for n, mask in enumerate(self.mMask1): 

292 op(mask, self.values2[n]) 

293 

294 self.assertFloatsEqual(self.mMask1.array, self.mMask2.array) 

295 expect = np.empty_like(self.mMask1.array) 

296 expect[:] = op(np.array(self.values1), np.array(self.values2))[:, None, None] 

297 self.assertFloatsEqual(self.mMask1.array, expect) 

298 

299 def testOrMasks(self): 

300 self._bitOperator(operator.ior) 

301 

302 def testAndMasks(self): 

303 self._bitOperator(operator.iand) 

304 

305 def testXorMasks(self): 

306 self._bitOperator(operator.ixor) 

307 

308 def testSetMask(self): 

309 mMask = self.mMask1.clone() 

310 mMask[:] = self.CR 

311 self.assertFloatsEqual(mMask.array, self.CR) 

312 mMask["G"] = self.EDGE 

313 self.assertFloatsEqual(mMask["R":].array, self.CR) 

314 self.assertFloatsEqual(mMask["G"].array, self.EDGE) 

315 mMask["R":] = self.BAD 

316 self.assertFloatsEqual(mMask["R":].array, self.BAD) 

317 mMask["R", 1100, 2050] = self.CR | self.EDGE 

318 self.assertEqual(mMask["R", 1100, 2050], self.CR | self.EDGE) 

319 self.assertEqual(mMask["R", 1101, 2051], self.BAD) 

320 

321 def testMaskPlanes(self): 

322 planes = self.mMask1.getMaskPlaneDict() 

323 self.assertEqual(len(planes), self.mMask1.getNumPlanesUsed()) 

324 

325 for k in sorted(planes.keys()): 

326 self.assertEqual(planes[k], self.mMask1.getMaskPlane(k)) 

327 

328 def testRemoveMaskPlane(self): 

329 mMask = self.mMask1 

330 # Add mask plane FOO and make sure it got added properly 

331 mMask.addMaskPlane("FOO") 

332 self.assertIn("FOO", mMask.getMaskPlaneDict()) 

333 self.assertIn("FOO", Mask().getMaskPlaneDict()) 

334 # Remove plane FOO, noting that removeMaskPlane removes it from the 

335 # default, but each instance remembers the version of the mask 

336 # dictionary that was current when it was created, so it will still 

337 # be in the mMask dict. 

338 mMask.removeMaskPlane("FOO") 

339 self.assertIn("FOO", mMask.getMaskPlaneDict()) 

340 self.assertNotIn("FOO", Mask().getMaskPlaneDict()) 

341 

342 def testRemoveAndClearMaskPlane(self): 

343 mMask = self.mMask1 

344 # Add mask plane FOO and test clearing it without removing plane from 

345 # default dict 

346 mMask.addMaskPlane("FOO") 

347 mMask.removeAndClearMaskPlane("FOO") 

348 self.assertNotIn("FOO", mMask.getMaskPlaneDict()) 

349 self.assertIn("FOO", Mask().getMaskPlaneDict()) 

350 # Now also remove it from default dict 

351 mMask.addMaskPlane("FOO") 

352 mMask.removeAndClearMaskPlane("FOO", removeFromDefault=True) 

353 self.assertNotIn("FOO", mMask.getMaskPlaneDict()) 

354 self.assertNotIn("FOO", Mask().getMaskPlaneDict()) 

355 # Now remove and clear the EDGE mask plane and make sure all of the planes 

356 # in the MultibandMask (i.e. the "singles") got updated accordingly 

357 mMask.removeAndClearMaskPlane("EDGE", removeFromDefault=True) 

358 self.assertNotIn("EDGE", mMask.getMaskPlaneDict()) 

359 self.assertNotIn("EDGE", Mask().getMaskPlaneDict()) 

360 # Assert that all mask planes were updated (i.e. having EDGE removed) 

361 self.assertTrue(np.all([s.array == self.values1[n] & ~self.EDGE for 

362 n, s in enumerate(mMask.singles)])) 

363 

364 def testFilterSlicing(self): 

365 _testImageFilterSlicing(self, self.mMask1, Mask, self.bbox, self.values1[0]) 

366 

367 def testImageSlicing(self): 

368 _testImageSlicing(self, self.mMask1, *self.values1) 

369 

370 def testImageModification(self): 

371 mMask1 = self.mMask1 

372 value1 = self.CR 

373 value2 = self.EDGE 

374 mMask1[:] = value1 

375 

376 bbox2 = Box2I(Point2I(1100, 2025), Extent2I(30, 50)) 

377 singles = [self.Mask(bbox2) for f in range(len(self.filters))] 

378 for n in range(len(singles)): 

379 singles[n].set(value2) 

380 mMask2 = MultibandMask.fromMasks(self.filters, singles) 

381 

382 _testImageModification(self, mMask1, mMask2, self.bbox, bbox2, value1, value2) 

383 

384 def testImageCopy(self): 

385 mMask = self.mMask1 

386 value1 = self.CR 

387 value2 = self.EDGE 

388 mMask[:] = value1 

389 _testImageCopy(self, mMask, value1, value2) 

390 

391 

392def _testMaskedImageFilters(testCase, maskedImage, singleType): 

393 testCase.assertIsInstance(maskedImage["R"], singleType) 

394 testCase.assertIsInstance(maskedImage.image["G"], ImageF) 

395 testCase.assertIsInstance(maskedImage.mask["R"], Mask) 

396 testCase.assertIsInstance(maskedImage.variance["I"], ImageF) 

397 

398 testCase.assertEqual(maskedImage["G"].image.array.shape, (100, 200)) 

399 testCase.assertEqual(maskedImage[:"I"].mask.array.shape, (2, 100, 200)) 

400 testCase.assertEqual(maskedImage[:"I"].filters, ("G", "R")) 

401 testCase.assertEqual(maskedImage[:"I"].getBBox(), testCase.bbox) 

402 testCase.assertEqual(maskedImage[["G", "I"]].getBBox(), testCase.bbox) 

403 

404 testCase.assertEqual(maskedImage.filters, tuple(testCase.filters)) 

405 

406 

407def _testMaskedImageSlicing(testCase, maskedImage): 

408 subBox = Box2I(Point2I(1100, 2025), Extent2I(30, 50)) 

409 testCase.assertEqual(maskedImage[:, subBox].getBBox(), subBox) 

410 testCase.assertEqual(maskedImage[:, subBox].image.getBBox(), subBox) 

411 testCase.assertEqual(maskedImage[:, subBox].mask.getBBox(), subBox) 

412 testCase.assertEqual(maskedImage[:, subBox].variance.getBBox(), subBox) 

413 

414 maskedPixel = maskedImage[:, 1100, 2025] 

415 testCase.assertFloatsEqual(maskedPixel[0].array, np.array([10., 10., 10.])) 

416 testCase.assertFloatsEqual(maskedPixel[1].array, np.array([1, 1, 1])) 

417 testCase.assertFloatsAlmostEqual(maskedPixel[2].array, np.array([.01, .01, .01]), 1e-6) 

418 

419 newBox = Box2I(Point2I(100, 500), Extent2I(200, 100)) 

420 maskedImage.setXY0(newBox.getMin()) 

421 testCase.assertEqual(maskedImage.getBBox(), newBox) 

422 testCase.assertEqual(maskedImage.image.getBBox(), newBox) 

423 testCase.assertEqual(maskedImage.mask.getBBox(), newBox) 

424 testCase.assertEqual(maskedImage.variance.getBBox(), newBox) 

425 testCase.assertEqual(maskedImage["G"].getBBox(), newBox) 

426 testCase.assertEqual(maskedImage["G"].image.getBBox(), newBox) 

427 testCase.assertEqual(maskedImage["R"].mask.getBBox(), newBox) 

428 testCase.assertEqual(maskedImage["I"].variance.getBBox(), newBox) 

429 

430 

431def _testMaskedmageModification(testCase, maskedImage): 

432 images = [ImageF(testCase.bbox, 10*testCase.imgValue) for f in testCase.filters] 

433 mImage = MultibandImage.fromImages(testCase.filters, images) 

434 maskedImage.image.array = mImage.array 

435 testCase.assertFloatsEqual(maskedImage.image["G"].array, mImage.array[0]) 

436 testCase.assertFloatsEqual(maskedImage["G"].image.array, mImage.array[0]) 

437 

438 singles = [testCase.Mask(testCase.bbox) for f in range(len(testCase.filters))] 

439 for n in range(len(singles)): 

440 singles[n].set(testCase.maskValue*2) 

441 mMask = MultibandMask.fromMasks(testCase.filters, singles) 

442 maskedImage.mask.array = mMask.array 

443 testCase.assertFloatsEqual(maskedImage.mask["G"].array, mMask.array[0]) 

444 testCase.assertFloatsEqual(maskedImage["G"].mask.array, mMask.array[0]) 

445 

446 images = [ImageF(testCase.bbox, .1 * testCase.varValue) for f in testCase.filters] 

447 mVariance = MultibandImage.fromImages(testCase.filters, images) 

448 maskedImage.variance.array = mVariance.array 

449 testCase.assertFloatsEqual(maskedImage.variance["G"].array, mVariance.array[0]) 

450 testCase.assertFloatsEqual(maskedImage["G"].variance.array, mVariance.array[0]) 

451 

452 subBox = Box2I(Point2I(1100, 2025), Extent2I(30, 50)) 

453 maskedImage.image[:, subBox].array = 12 

454 testCase.assertFloatsEqual(maskedImage.image["G", subBox].array, 12) 

455 testCase.assertFloatsEqual(maskedImage["G", subBox].image.array, 12) 

456 maskedImage["R", subBox].image[:] = 15 

457 testCase.assertFloatsEqual(maskedImage.image["R", subBox].array, 15) 

458 testCase.assertFloatsEqual(maskedImage["R", subBox].image.array, 15) 

459 

460 maskedImage.mask[:, subBox].array = 64 

461 testCase.assertFloatsEqual(maskedImage.mask["G", subBox].array, 64) 

462 testCase.assertFloatsEqual(maskedImage["G", subBox].mask.array, 64) 

463 maskedImage["R", subBox].mask[:] = 128 

464 testCase.assertFloatsEqual(maskedImage.mask["R", subBox].array, 128) 

465 testCase.assertFloatsEqual(maskedImage["R", subBox].mask.array, 128) 

466 

467 maskedImage.variance[:, subBox].array = 1e-6 

468 testCase.assertFloatsEqual(maskedImage.variance["G", subBox].array, 1e-6) 

469 testCase.assertFloatsEqual(maskedImage["G", subBox].variance.array, 1e-6) 

470 maskedImage["R", subBox].variance[:] = 1e-7 

471 testCase.assertFloatsEqual(maskedImage.variance["R", subBox].array, 1e-7) 

472 testCase.assertFloatsEqual(maskedImage["R", subBox].variance.array, 1e-7) 

473 

474 

475def _testMaskedImageCopy(testCase, maskedImage1): 

476 maskedImage2 = maskedImage1.clone() 

477 

478 maskedImage2.setXY0(Point2I(11, 23)) 

479 testCase.assertEqual(maskedImage2.getBBox(), Box2I(Point2I(11, 23), Extent2I(200, 100))) 

480 testCase.assertEqual(maskedImage1.getBBox(), Box2I(Point2I(1000, 2000), Extent2I(200, 100))) 

481 testCase.assertTrue(np.all([img.getBBox() == maskedImage1.getBBox() for img in maskedImage1.image])) 

482 testCase.assertTrue(np.all([img.getBBox() == maskedImage2.getBBox() for img in maskedImage2.image])) 

483 

484 maskedImage2.image.array = 1 

485 testCase.assertFloatsEqual(maskedImage1.image.array, testCase.imgValue) 

486 testCase.assertFloatsEqual(maskedImage2.image.array, 1) 

487 testCase.assertFloatsEqual(maskedImage1["G"].image.array, testCase.imgValue) 

488 testCase.assertFloatsEqual(maskedImage2["G"].image.array, 1) 

489 

490 maskedImage2 = maskedImage1.clone(False) 

491 maskedImage2.image.array = 1 

492 testCase.assertFloatsEqual(maskedImage1.image.array, 1) 

493 testCase.assertFloatsEqual(maskedImage2.image.array, 1) 

494 testCase.assertFloatsEqual(maskedImage1["G"].image.array, 1) 

495 testCase.assertFloatsEqual(maskedImage2["G"].image.array, 1) 

496 

497 

498class MultibandMaskedImageTestCase(lsst.utils.tests.TestCase): 

499 """Test case for MultibandMaskedImage""" 

500 

501 def setUp(self): 

502 np.random.seed(1) 

503 self.bbox = Box2I(Point2I(1000, 2000), Extent2I(200, 100)) 

504 self.filters = ["G", "R", "I"] 

505 

506 self.imgValue = 10 

507 images = [ImageF(self.bbox, self.imgValue) for f in self.filters] 

508 mImage = MultibandImage.fromImages(self.filters, images) 

509 

510 self.Mask = Mask[MaskPixel] 

511 # Store the default mask planes for later use 

512 maskPlaneDict = self.Mask().getMaskPlaneDict() 

513 self.defaultMaskPlanes = sorted(maskPlaneDict, key=maskPlaneDict.__getitem__) 

514 

515 # reset so tests will be deterministic 

516 self.Mask.clearMaskPlaneDict() 

517 for p in ("BAD", "SAT", "INTRP", "CR", "EDGE"): 

518 self.Mask.addMaskPlane(p) 

519 

520 self.maskValue = self.Mask.getPlaneBitMask("BAD") 

521 singles = [self.Mask(self.bbox) for f in range(len(self.filters))] 

522 for n in range(len(singles)): 

523 singles[n].set(self.maskValue) 

524 mMask = MultibandMask.fromMasks(self.filters, singles) 

525 

526 self.varValue = 1e-2 

527 images = [ImageF(self.bbox, self.varValue) for f in self.filters] 

528 mVariance = MultibandImage.fromImages(self.filters, images) 

529 

530 self.maskedImage = MultibandMaskedImage(self.filters, image=mImage, mask=mMask, variance=mVariance) 

531 

532 def tearDown(self): 

533 del self.maskedImage 

534 del self.bbox 

535 del self.imgValue 

536 del self.maskValue 

537 del self.varValue 

538 # Reset the mask plane to the default 

539 self.Mask.clearMaskPlaneDict() 

540 for p in self.defaultMaskPlanes: 

541 self.Mask.addMaskPlane(p) 

542 del self.defaultMaskPlanes 

543 

544 def testFilterSlicing(self): 

545 _testMaskedImageFilters(self, self.maskedImage, MaskedImage) 

546 

547 def testImageSlicing(self): 

548 _testMaskedImageSlicing(self, self.maskedImage) 

549 

550 def testModification(self): 

551 _testMaskedmageModification(self, self.maskedImage) 

552 

553 def testCopy(self): 

554 _testMaskedImageCopy(self, self.maskedImage) 

555 

556 

557class MultibandExposureTestCase(lsst.utils.tests.TestCase): 

558 """ 

559 A test case for the Exposure Class 

560 """ 

561 

562 def setUp(self): 

563 np.random.seed(1) 

564 self.bbox = Box2I(Point2I(1000, 2000), Extent2I(200, 100)) 

565 self.filters = ["G", "R", "I"] 

566 

567 self.imgValue = 10 

568 images = [ImageF(self.bbox, self.imgValue) for f in self.filters] 

569 mImage = MultibandImage.fromImages(self.filters, images) 

570 

571 self.Mask = Mask[MaskPixel] 

572 # Store the default mask planes for later use 

573 maskPlaneDict = self.Mask().getMaskPlaneDict() 

574 self.defaultMaskPlanes = sorted(maskPlaneDict, key=maskPlaneDict.__getitem__) 

575 

576 # reset so tests will be deterministic 

577 self.Mask.clearMaskPlaneDict() 

578 for p in ("BAD", "SAT", "INTRP", "CR", "EDGE"): 

579 self.Mask.addMaskPlane(p) 

580 

581 self.maskValue = self.Mask.getPlaneBitMask("BAD") 

582 singles = [self.Mask(self.bbox) for f in range(len(self.filters))] 

583 for n in range(len(singles)): 

584 singles[n].set(self.maskValue) 

585 mMask = MultibandMask.fromMasks(self.filters, singles) 

586 

587 self.varValue = 1e-2 

588 images = [ImageF(self.bbox, self.varValue) for f in self.filters] 

589 mVariance = MultibandImage.fromImages(self.filters, images) 

590 

591 self.kernelSize = 51 

592 self.psfs = [GaussianPsf(self.kernelSize, self.kernelSize, 4.0) for f in self.filters] 

593 self.psfImage = np.array([ 

594 p.computeKernelImage(p.getAveragePosition()).array for p in self.psfs 

595 ]) 

596 

597 self.exposure = MultibandExposure(image=mImage, mask=mMask, variance=mVariance, 

598 psfs=self.psfs, filters=self.filters) 

599 

600 def tearDown(self): 

601 del self.exposure 

602 del self.psfs 

603 del self.bbox 

604 del self.imgValue 

605 del self.maskValue 

606 del self.varValue 

607 # Reset the mask plane to the default 

608 self.Mask.clearMaskPlaneDict() 

609 for p in self.defaultMaskPlanes: 

610 self.Mask.addMaskPlane(p) 

611 del self.defaultMaskPlanes 

612 

613 def testConstructor(self): 

614 exposures = self.exposure.singles 

615 print(exposures[0].getPsf()) 

616 filters = self.exposure.filters 

617 newExposure = MultibandExposure.fromExposures(filters, exposures) 

618 for exposure in newExposure.singles: 

619 self.assertIsNotNone(exposure.getPsf()) 

620 

621 def testFilterSlicing(self): 

622 _testMaskedImageFilters(self, self.exposure, ExposureF) 

623 

624 def testImageSlicing(self): 

625 _testMaskedImageSlicing(self, self.exposure) 

626 

627 def testModification(self): 

628 _testMaskedmageModification(self, self.exposure) 

629 

630 def testCopy(self): 

631 _testMaskedImageCopy(self, self.exposure) 

632 

633 def testPsf(self): 

634 psfImage = self.exposure.computePsfKernelImage(self.exposure.getBBox().getCenter()) 

635 self.assertFloatsAlmostEqual(psfImage, self.psfImage) 

636 

637 newPsfs = [GaussianPsf(self.kernelSize, self.kernelSize, 1.0) for f in self.filters] 

638 newPsfImage = [p.computeImage(p.getAveragePosition()).array for p in newPsfs] 

639 for psf, exposure in zip(newPsfs, self.exposure.singles): 

640 exposure.setPsf(psf) 

641 psfImage = self.exposure.computePsfKernelImage(self.exposure.getBBox().getCenter()) 

642 self.assertFloatsAlmostEqual(psfImage, newPsfImage) 

643 

644 psfImage = self.exposure.computePsfImage(self.exposure.getBBox().getCenter())[0] 

645 self.assertFloatsAlmostEqual( 

646 psfImage, 

647 self.exposure["G"].getPsf().computeImage( 

648 self.exposure["G"].getPsf().getAveragePosition() 

649 ).array 

650 ) 

651 

652 

653class MultibandFootprintTestCase(lsst.utils.tests.TestCase): 

654 """ 

655 A test case for the Exposure Class 

656 """ 

657 

658 def setUp(self): 

659 np.random.seed(1) 

660 self.spans = SpanSet.fromShape(2, Stencil.CIRCLE) 

661 self.footprint = Footprint(self.spans) 

662 self.footprint.addPeak(3, 4, 10) 

663 self.footprint.addPeak(8, 1, 2) 

664 fp = Footprint(self.spans) 

665 for peak in self.footprint.getPeaks(): 

666 fp.addPeak(peak["f_x"], peak["f_y"], peak["peakValue"]) 

667 self.peaks = fp.getPeaks() 

668 self.bbox = self.footprint.getBBox() 

669 self.filters = ("G", "R", "I") 

670 singles = [] 

671 images = [] 

672 for n, f in enumerate(self.filters): 

673 image = ImageF(self.spans.getBBox()) 

674 image.set(n) 

675 images.append(image.array) 

676 maskedImage = MaskedImageF(image) 

677 heavy = makeHeavyFootprint(self.footprint, maskedImage) 

678 singles.append(heavy) 

679 self.image = np.array(images) 

680 self.mFoot = MultibandFootprint(self.filters, singles) 

681 

682 def tearDown(self): 

683 del self.spans 

684 del self.footprint 

685 del self.peaks 

686 del self.bbox 

687 del self.filters 

688 del self.mFoot 

689 del self.image 

690 

691 def verifyPeaks(self, peaks1, peaks2): 

692 self.assertEqual(len(peaks1), len(peaks2)) 

693 for n in range(len(peaks1)): 

694 pk1 = peaks1[n] 

695 pk2 = peaks2[n] 

696 # self.assertEqual(pk1["id"], pk2["id"]) 

697 self.assertEqual(pk1["f_x"], pk2["f_x"]) 

698 self.assertEqual(pk1["f_y"], pk2["f_y"]) 

699 self.assertEqual(pk1["i_x"], pk2["i_x"]) 

700 self.assertEqual(pk1["i_y"], pk2["i_y"]) 

701 self.assertEqual(pk1["peakValue"], pk2["peakValue"]) 

702 

703 def testConstructor(self): 

704 def projectSpans(radius, value, bbox, asArray): 

705 ss = SpanSet.fromShape(radius, Stencil.CIRCLE, offset=(10, 10)) 

706 image = ImageF(bbox) 

707 ss.setImage(image, value) 

708 if asArray: 

709 return image.array 

710 else: 

711 return image 

712 

713 def runTest(images, mFoot, peaks=self.peaks, footprintBBox=Box2I(Point2I(6, 6), Extent2I(9, 9))): 

714 self.assertEqual(mFoot.getBBox(), footprintBBox) 

715 try: 

716 fpImage = np.array(images)[:, 1:-1, 1:-1] 

717 except IndexError: 

718 fpImage = np.array([img.array for img in images])[:, 1:-1, 1:-1] 

719 # result = mFoot.getImage(fill=0).image.array 

720 self.assertFloatsAlmostEqual(mFoot.getImage(fill=0).image.array, fpImage) 

721 if peaks is not None: 

722 self.verifyPeaks(mFoot.getPeaks(), peaks) 

723 

724 bbox = Box2I(Point2I(5, 5), Extent2I(11, 11)) 

725 xy0 = Point2I(5, 5) 

726 

727 images = np.array([projectSpans(n, 5-n, bbox, True) for n in range(2, 5)]) 

728 mFoot = MultibandFootprint.fromArrays(self.filters, images, xy0=xy0, peaks=self.peaks) 

729 runTest(images, mFoot) 

730 

731 mFoot = MultibandFootprint.fromArrays(self.filters, images) 

732 runTest(images, mFoot, None, Box2I(Point2I(1, 1), Extent2I(9, 9))) 

733 

734 images = [projectSpans(n, 5-n, bbox, False) for n in range(2, 5)] 

735 mFoot = MultibandFootprint.fromImages(self.filters, images, peaks=self.peaks) 

736 runTest(images, mFoot) 

737 

738 images = np.array([projectSpans(n, n, bbox, True) for n in range(2, 5)]) 

739 mFoot = MultibandFootprint.fromArrays(self.filters, images, peaks=self.peaks, xy0=bbox.getMin()) 

740 runTest(images, mFoot) 

741 

742 images = np.array([projectSpans(n, 5-n, bbox, True) for n in range(2, 5)]) 

743 thresh = [1, 2, 2.5] 

744 mFoot = MultibandFootprint.fromArrays(self.filters, images, xy0=bbox.getMin(), thresh=thresh) 

745 footprintBBox = Box2I(Point2I(8, 8), Extent2I(5, 5)) 

746 self.assertEqual(mFoot.getBBox(), footprintBBox) 

747 

748 fpImage = np.array(images)[:, 3:-3, 3:-3] 

749 mask = np.all(fpImage <= np.array(thresh)[:, None, None], axis=0) 

750 fpImage[:, mask] = 0 

751 self.assertFloatsAlmostEqual(mFoot.getImage(fill=0).image.array, fpImage) 

752 img = mFoot.getImage().image.array 

753 img[~np.isfinite(img)] = 1.1 

754 self.assertFloatsAlmostEqual(mFoot.getImage(fill=1.1).image.array, img) 

755 

756 def testSlicing(self): 

757 self.assertIsInstance(self.mFoot["R"], HeavyFootprintF) 

758 self.assertIsInstance(self.mFoot[:], MultibandFootprint) 

759 

760 self.assertEqual(self.mFoot["I"], self.mFoot["I"]) 

761 self.assertEqual(self.mFoot[:"I"].filters, ("G", "R")) 

762 self.assertEqual(self.mFoot[:"I"].getBBox(), self.bbox) 

763 self.assertEqual(self.mFoot[["G", "I"]].filters, ("G", "I")) 

764 self.assertEqual(self.mFoot[["G", "I"]].getBBox(), self.bbox) 

765 

766 with self.assertRaises(TypeError): 

767 self.mFoot["I", 4, 5] 

768 self.mFoot["I", :, :] 

769 with self.assertRaises(IndexError): 

770 self.mFoot[:, :, :] 

771 

772 def testSpans(self): 

773 self.assertEqual(self.mFoot.getSpans(), self.spans) 

774 for footprint in self.mFoot.singles: 

775 self.assertEqual(footprint.getSpans(), self.spans) 

776 

777 def testPeaks(self): 

778 self.verifyPeaks(self.peaks, self.footprint.getPeaks()) 

779 for footprint in self.mFoot.singles: 

780 self.verifyPeaks(footprint.getPeaks(), self.peaks) 

781 

782 

783class TestMemory(lsst.utils.tests.MemoryTestCase): 

784 pass 

785 

786 

787def setup_module(module): 

788 lsst.utils.tests.init() 

789 

790 

791if __name__ == "__main__": 791 ↛ 792line 791 didn't jump to line 792, because the condition on line 791 was never true

792 lsst.utils.tests.init() 

793 unittest.main()