Coverage for tests/test_maskedImage.py: 12%

472 statements  

« prev     ^ index     » next       coverage.py v6.4.1, created at 2022-06-14 02:44 -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# (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 

22""" 

23Tests for MaskedImages 

24 

25Run with: 

26 python test_maskedImage.py 

27or 

28 pytest test_maskedImage.py 

29""" 

30 

31import itertools 

32import os 

33import unittest 

34 

35import numpy as np 

36 

37import lsst.utils 

38import lsst.utils.tests 

39import lsst.pex.exceptions 

40import lsst.daf.base 

41import lsst.geom 

42import lsst.afw.image as afwImage 

43import lsst.afw.math as afwMath 

44import lsst.afw.display as afwDisplay 

45 

46try: 

47 type(display) 

48except NameError: 

49 display = False 

50afwDisplay.setDefaultMaskTransparency(75) 

51 

52 

53def makeRampImage(width, height, imgClass=afwImage.MaskedImageF): 

54 """Make a ramp image of the specified size and image class 

55 

56 Image values start from 0 at the lower left corner and increase by 1 along rows 

57 Variance values equal image values + 100 

58 Mask values equal image values modulo 8 bits (leaving plenty of unused values) 

59 """ 

60 mi = imgClass(width, height) 

61 image = mi.image 

62 mask = mi.mask 

63 variance = mi.variance 

64 val = 0 

65 for yInd in range(height): 

66 for xInd in range(width): 

67 image[xInd, yInd] = val 

68 variance[xInd, yInd] = val + 100 

69 mask[xInd, yInd] = val % 0x100 

70 val += 1 

71 return mi 

72 

73 

74class MaskedImageTestCase(lsst.utils.tests.TestCase): 

75 """A test case for MaskedImage""" 

76 

77 def setUp(self): 

78 self.imgVal1, self.varVal1 = 100.0, 10.0 

79 self.imgVal2, self.varVal2 = 200.0, 15.0 

80 self.mimage = afwImage.MaskedImageF(100, 200) 

81 

82 self.mimage.image.set(self.imgVal1) 

83 # 

84 # Set center of mask to 0, with 2 pixel border set to EDGE 

85 # 

86 self.BAD = afwImage.Mask.getPlaneBitMask("BAD") 

87 self.EDGE = afwImage.Mask.getPlaneBitMask("EDGE") 

88 

89 self.mimage.mask.set(self.EDGE) 

90 centre = afwImage.Mask( 

91 self.mimage.mask, 

92 lsst.geom.Box2I(lsst.geom.Point2I(2, 2), 

93 self.mimage.getDimensions() - lsst.geom.Extent2I(4)), 

94 afwImage.LOCAL) 

95 centre.set(0x0) 

96 # 

97 self.mimage.variance.set(self.varVal1) 

98 # 

99 # Second MaskedImage 

100 # 

101 self.mimage2 = afwImage.MaskedImageF(self.mimage.getDimensions()) 

102 self.mimage2.image.set(self.imgVal2) 

103 self.mimage2.variance.set(self.varVal2) 

104 # 

105 # a Function2 

106 # 

107 self.function = afwMath.PolynomialFunction2D(2) 

108 self.function.setParameters( 

109 list(range(self.function.getNParameters()))) 

110 

111 def tearDown(self): 

112 del self.mimage 

113 del self.mimage2 

114 del self.function 

115 

116 def testArrays(self): 

117 """ 

118 This method is testing that ``lsst.afw.image.MaskedImageF.getArrays()`` 

119 returns the proper image, mask, and variance. 

120 """ 

121 image, mask, variance = self.mimage.getArrays() 

122 self.assertFloatsEqual(self.mimage.image.getArray(), image) 

123 self.assertFloatsEqual(self.mimage.mask.getArray(), mask) 

124 self.assertFloatsEqual(self.mimage.variance.getArray(), variance) 

125 mimage2 = afwImage.makeMaskedImageFromArrays(image, mask, variance) 

126 self.assertEqual(type(mimage2), type(self.mimage)) 

127 

128 def testProperties(self): 

129 self.assertImagesEqual(self.mimage.image, self.mimage.image) 

130 self.assertMasksEqual(self.mimage.mask, self.mimage.mask) 

131 self.assertImagesEqual(self.mimage.variance, self.mimage.variance) 

132 image2 = self.mimage.image.Factory(self.mimage.getDimensions()) 

133 image2.array[:] = 5.0 

134 self.mimage.image = image2 

135 self.assertImagesEqual(self.mimage.image, image2) 

136 mask2 = self.mimage.mask.Factory(self.mimage.getDimensions()) 

137 mask2.array[:] = 0x4 

138 self.mimage.mask = mask2 

139 self.assertMasksEqual(self.mimage.mask, mask2) 

140 var2 = self.mimage.image.Factory(self.mimage.getDimensions()) 

141 var2.array[:] = 3.0 

142 self.mimage.variance = var2 

143 self.assertImagesEqual(self.mimage.variance, var2) 

144 

145 def testSetGetValues(self): 

146 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], 

147 (self.imgVal1, self.EDGE, self.varVal1)) 

148 

149 self.assertEqual(self.mimage.mask[1, 1, afwImage.LOCAL], self.EDGE) 

150 self.assertEqual(self.mimage.mask[2, 2, afwImage.LOCAL], 0x0) 

151 

152 def testImagesOverlap(self): 

153 # make pairs of image, variance and mask planes 

154 # using the same dimensions for each so we can mix and match 

155 # while making masked images 

156 dim = lsst.geom.Extent2I(10, 8) 

157 # a set of bounding boxes, some of which overlap each other 

158 # and some of which do not, and include the full image bounding box 

159 bboxes = ( 

160 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), dim), 

161 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(3, 3)), 

162 lsst.geom.Box2I(lsst.geom.Point2I(2, 2), lsst.geom.Extent2I(6, 4)), 

163 lsst.geom.Box2I(lsst.geom.Point2I(4, 4), lsst.geom.Extent2I(6, 4)), 

164 ) 

165 masks = [afwImage.Mask(dim), afwImage.Mask(dim)] 

166 variances = [afwImage.ImageF(dim), afwImage.ImageF(dim)] 

167 imageClasses = (afwImage.ImageF, afwImage.ImageD, afwImage.ImageI, afwImage.ImageU) 

168 for ImageClass1, ImageClass2 in itertools.product(imageClasses, imageClasses): 

169 images = [ImageClass1(dim), ImageClass2(dim)] 

170 for image1, mask1, variance1, image2, mask2, variance2 in itertools.product( 

171 images, masks, variances, images, masks, variances): 

172 with self.subTest(ImageClass1=str(ImageClass1), ImageClass2=str(ImageClass2), 

173 image1=image1, mask1=mask1, variance1=variance1, 

174 image2=image2, mask2=mask2, variance2=variance2): 

175 shouldOverlap = (image1 is image2) or (mask1 is mask2) or (variance1 is variance2) 

176 

177 mi1 = afwImage.makeMaskedImage(image=image1, mask=mask1, variance=variance1) 

178 mi2 = afwImage.makeMaskedImage(image=image2, mask=mask2, variance=variance2) 

179 self.assertEqual(afwImage.imagesOverlap(mi1, mi2), shouldOverlap) 

180 self.assertEqual(afwImage.imagesOverlap(mi2, mi1), shouldOverlap) 

181 

182 for bbox1, bbox2 in itertools.product(bboxes, bboxes): 

183 with self.subTest(bbox1=bbox1, bbox2=bbox2): 

184 subMi1 = afwImage.makeMaskedImage(image=type(image1)(image1, bbox1), 

185 mask=afwImage.Mask(mask1, bbox1), 

186 variance=afwImage.ImageF(variance1, bbox1)) 

187 subMi2 = afwImage.makeMaskedImage(image=type(image2)(image2, bbox2), 

188 mask=afwImage.Mask(mask2, bbox2), 

189 variance=afwImage.ImageF(variance2, bbox2)) 

190 subregionsShouldOverlap = shouldOverlap and bbox1.overlaps(bbox2) 

191 self.assertEqual(afwImage.imagesOverlap(subMi1, subMi2), subregionsShouldOverlap) 

192 self.assertEqual(afwImage.imagesOverlap(subMi2, subMi1), subregionsShouldOverlap) 

193 

194 def testMaskedImageFromImage(self): 

195 w, h = 10, 20 

196 dims = lsst.geom.Extent2I(w, h) 

197 im, mask, var = afwImage.ImageF(dims), \ 

198 afwImage.Mask(dims), \ 

199 afwImage.ImageF(dims) 

200 im.set(666) 

201 

202 maskedImage = afwImage.MaskedImageF(im, mask, var) 

203 

204 maskedImage = afwImage.makeMaskedImage(im, mask, var) 

205 

206 maskedImage = afwImage.MaskedImageF(im) 

207 self.assertEqual(im.getDimensions(), 

208 maskedImage.image.getDimensions()) 

209 self.assertEqual(im.getDimensions(), 

210 maskedImage.mask.getDimensions()) 

211 self.assertEqual(im.getDimensions(), 

212 maskedImage.variance.getDimensions()) 

213 

214 self.assertEqual(maskedImage[0, 0, afwImage.LOCAL], (im[0, 0, afwImage.LOCAL], 0x0, 0.0)) 

215 

216 def testMakeMaskedImageXY0(self): 

217 """Test that makeMaskedImage sets XY0 correctly""" 

218 im = afwImage.ImageF(200, 300) 

219 xy0 = lsst.geom.PointI(10, 20) 

220 im.setXY0(*xy0) 

221 mi = afwImage.makeMaskedImage(im) 

222 

223 self.assertEqual(mi.image.getXY0(), xy0) 

224 self.assertEqual(mi.mask.getXY0(), xy0) 

225 self.assertEqual(mi.variance.getXY0(), xy0) 

226 

227 def testCopyMaskedImage(self): 

228 """Test copy constructor""" 

229 # 

230 # shallow copy 

231 # 

232 mi = self.mimage.Factory(self.mimage, False) 

233 

234 val00 = self.mimage[0, 0, afwImage.LOCAL] 

235 nval00 = (100, 0xff, -1) # the new value we'll set 

236 self.assertNotEqual(val00, nval00) 

237 

238 self.assertEqual(mi[0, 0, afwImage.LOCAL], val00) 

239 mi[0, 0, afwImage.LOCAL] = nval00 

240 

241 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], nval00) 

242 self.assertEqual(mi[0, 0, afwImage.LOCAL], nval00) 

243 mi[0, 0, afwImage.LOCAL] = val00 # reinstate initial value 

244 # 

245 # deep copy 

246 # 

247 mi = self.mimage.Factory(self.mimage, True) 

248 

249 self.assertEqual(mi[0, 0, afwImage.LOCAL], val00) 

250 mi[0, 0, afwImage.LOCAL] = nval00 

251 

252 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], val00) 

253 self.assertEqual(mi[0, 0, afwImage.LOCAL], nval00) 

254 # 

255 # Copy with change of Image type 

256 # 

257 mi = self.mimage.convertD() 

258 

259 self.assertEqual(mi[0, 0, afwImage.LOCAL], val00) 

260 mi[0, 0, afwImage.LOCAL] = nval00 

261 

262 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], val00) 

263 self.assertEqual(mi[0, 0, afwImage.LOCAL], nval00) 

264 # 

265 # Convert from U to F 

266 # 

267 mi = afwImage.MaskedImageU(lsst.geom.Extent2I(10, 20)) 

268 val00 = (10, 0x10, 1) 

269 mi.set(val00) 

270 self.assertEqual(mi[0, 0, afwImage.LOCAL], val00) 

271 

272 fmi = mi.convertF() 

273 self.assertEqual(fmi[0, 0, afwImage.LOCAL], val00) 

274 

275 def testAddImages(self): 

276 "Test addition" 

277 # add an image 

278 self.mimage2 += self.mimage 

279 

280 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], (self.imgVal1 + self.imgVal2, self.EDGE, 

281 self.varVal1 + self.varVal2)) 

282 

283 # Add an Image<int> to a MaskedImage<int> 

284 mimage_i = afwImage.MaskedImageI(self.mimage2.getDimensions()) 

285 mimage_i.set(900, 0x0, 1000.0) 

286 image_i = afwImage.ImageI(mimage_i.getDimensions(), 2) 

287 

288 mimage_i += image_i 

289 

290 self.assertEqual(mimage_i[0, 0, afwImage.LOCAL], (902, 0x0, 1000.0)) 

291 

292 # add a scalar 

293 self.mimage += self.imgVal1 

294 

295 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], 

296 (2*self.imgVal1, self.EDGE, self.varVal1)) 

297 

298 self.assertEqual(self.mimage.mask[1, 1, afwImage.LOCAL], self.EDGE) 

299 self.assertEqual(self.mimage.mask[2, 2, afwImage.LOCAL], 0x0) 

300 

301 # add a function 

302 self.mimage.set(self.imgVal1, 0x0, 0.0) 

303 self.mimage += self.function 

304 

305 for i, j in [(2, 3)]: 

306 self.assertEqual(self.mimage.image[i, j, afwImage.LOCAL], 

307 self.imgVal1 + self.function(i, j)) 

308 

309 def testAddScaledImages(self): 

310 "Test addition by a scaled MaskedImage" 

311 # add an image 

312 c = 10.0 

313 mimage2_copy = self.mimage2.Factory(self.mimage2, True) # make a copy 

314 self.mimage2.scaledPlus(c, self.mimage) 

315 # 

316 # Now repeat calculation using a temporary 

317 # 

318 tmp = self.mimage.Factory(self.mimage, True) 

319 tmp *= c 

320 mimage2_copy += tmp 

321 

322 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], mimage2_copy[0, 0, afwImage.LOCAL]) 

323 

324 def testAssignWithBBox(self): 

325 """Test assign(rhs, bbox) with non-empty bbox 

326 """ 

327 for xy0 in (lsst.geom.Point2I(*val) for val in ( 

328 (0, 0), 

329 (-100, 120), # an arbitrary value that is off the image 

330 )): 

331 destMIDim = lsst.geom.Extent2I(5, 4) 

332 srcMIDim = lsst.geom.Extent2I(3, 2) 

333 destMI = afwImage.MaskedImageF(destMIDim) 

334 destImage = destMI.image 

335 destVariance = destMI.variance 

336 destMask = destMI.mask 

337 destMI.setXY0(xy0) 

338 srcMI = makeRampImage(*srcMIDim) 

339 srcMI.setXY0(55, -33) # an arbitrary value that should be ignored 

340 self.assertRaises(Exception, destMI.set, srcMI) # size mismatch 

341 

342 for validMin in (lsst.geom.Point2I(*val) for val in ( 

343 (0, 0), 

344 (2, 0), 

345 (0, 1), 

346 (1, 2), 

347 )): 

348 # None to omit the argument 

349 for origin in (None, afwImage.PARENT, afwImage.LOCAL): 

350 destImage[:] = -1.0 

351 destVariance[:] = -1.0 

352 destMask[:] = 0xFFFF 

353 bbox = lsst.geom.Box2I(validMin, srcMI.getDimensions()) 

354 if origin != afwImage.LOCAL: 

355 bbox.shift(lsst.geom.Extent2I(xy0)) 

356 if origin is None: 

357 destMI.assign(srcMI, bbox) 

358 destMIView = afwImage.MaskedImageF(destMI, bbox) 

359 else: 

360 destMI.assign(srcMI, bbox, origin) 

361 destMIView = afwImage.MaskedImageF( 

362 destMI, bbox, origin) 

363 for i in range(3): 

364 self.assertListEqual(destMIView.getArrays()[i].flatten().tolist(), 

365 srcMI.getArrays()[i].flatten().tolist()) 

366 numPixNotAssigned = ( 

367 destMIDim[0] * destMIDim[1]) - (srcMIDim[0] * srcMIDim[1]) 

368 self.assertEqual( 

369 np.sum(destImage.getArray() < -0.5), numPixNotAssigned) 

370 self.assertEqual( 

371 np.sum(destVariance.getArray() < -0.5), numPixNotAssigned) 

372 self.assertEqual( 

373 np.sum(destMask.getArray() == 0xFFFF), numPixNotAssigned) 

374 

375 for badMin in (lsst.geom.Point2I(*val) + lsst.geom.Extent2I(xy0) for val in ( 

376 (-1, 0), 

377 (3, 0), 

378 (0, -1), 

379 (1, 3), 

380 )): 

381 # None to omit the argument 

382 for origin in (None, afwImage.PARENT, afwImage.LOCAL): 

383 bbox = lsst.geom.Box2I(validMin, srcMI.getDimensions()) 

384 if origin != afwImage.LOCAL: 

385 bbox.shift(lsst.geom.Extent2I(xy0)) 

386 if origin is None: 

387 self.assertRaises(Exception, destMI.set, srcMI, bbox) 

388 else: 

389 self.assertRaises( 

390 Exception, destMI.set, srcMI, bbox, origin) 

391 

392 def testAssignWithoutBBox(self): 

393 """Test assign(rhs, [bbox]) with an empty bbox and with no bbox specified; both set all pixels 

394 """ 

395 for xy0 in (lsst.geom.Point2I(*val) for val in ( 

396 (0, 0), 

397 (-100, 120), # an arbitrary value that is off the image 

398 )): 

399 destMIDim = lsst.geom.Extent2I(5, 4) 

400 destMI = afwImage.MaskedImageF(destMIDim) 

401 destMI.setXY0(xy0) 

402 destImage = destMI.image 

403 destVariance = destMI.variance 

404 destMask = destMI.mask 

405 srcMI = makeRampImage(*destMIDim) 

406 srcMI.setXY0(55, -33) # an arbitrary value that should be ignored 

407 

408 destImage[:] = -1.0 

409 destVariance[:] = -1.0 

410 destMask[:] = 0xFFFF 

411 destMI.assign(srcMI) 

412 for i in range(3): 

413 self.assertListEqual(destMI.getArrays()[i].flatten().tolist(), 

414 srcMI.getArrays()[i].flatten().tolist()) 

415 

416 destImage[:] = -1.0 

417 destVariance[:] = -1.0 

418 destMask[:] = 0xFFFF 

419 destMI.assign(srcMI, lsst.geom.Box2I()) 

420 for i in range(3): 

421 self.assertListEqual(destMI.getArrays()[i].flatten().tolist(), 

422 srcMI.getArrays()[i].flatten().tolist()) 

423 

424 def testSubtractImages(self): 

425 "Test subtraction" 

426 # subtract an image 

427 self.mimage2 -= self.mimage 

428 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], 

429 (self.imgVal2 - self.imgVal1, self.EDGE, self.varVal2 + self.varVal1)) 

430 

431 # Subtract an Image<int> from a MaskedImage<int> 

432 mimage_i = afwImage.MaskedImageI(self.mimage2.getDimensions()) 

433 mimage_i.set(900, 0x0, 1000.0) 

434 image_i = afwImage.ImageI(mimage_i.getDimensions(), 2) 

435 

436 mimage_i -= image_i 

437 

438 self.assertEqual(mimage_i[0, 0, afwImage.LOCAL], (898, 0x0, 1000.0)) 

439 

440 # subtract a scalar 

441 self.mimage -= self.imgVal1 

442 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], (0.0, self.EDGE, self.varVal1)) 

443 

444 def testSubtractScaledImages(self): 

445 "Test subtraction by a scaled MaskedImage" 

446 # subtract a scaled image 

447 c = 10.0 

448 mimage2_copy = self.mimage2.Factory(self.mimage2, True) # make a copy 

449 self.mimage2.scaledMinus(c, self.mimage) 

450 # 

451 # Now repeat calculation using a temporary 

452 # 

453 tmp = self.mimage.Factory(self.mimage, True) 

454 tmp *= c 

455 mimage2_copy -= tmp 

456 

457 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], mimage2_copy[0, 0, afwImage.LOCAL]) 

458 

459 def testArithmeticImagesMismatch(self): 

460 "Test arithmetic operations on MaskedImages of different sizes" 

461 i1 = afwImage.MaskedImageF(lsst.geom.Extent2I(100, 100)) 

462 i1.set(100) 

463 i2 = afwImage.MaskedImageF(lsst.geom.Extent2I(10, 10)) 

464 i2.set(10) 

465 

466 def tst1(i1, i2): 

467 i1 -= i2 

468 

469 def tst2(i1, i2): 

470 i1.scaledMinus(1.0, i2) 

471 

472 def tst3(i1, i2): 

473 i1 += i2 

474 

475 def tst4(i1, i2): 

476 i1.scaledPlus(1.0, i2) 

477 

478 def tst5(i1, i2): 

479 i1 *= i2 

480 

481 def tst6(i1, i2): 

482 i1.scaledMultiplies(1.0, i2) 

483 

484 def tst7(i1, i2): 

485 i1 /= i2 

486 

487 def tst8(i1, i2): 

488 i1.scaledDivides(1.0, i2) 

489 

490 tsts12 = [tst1, tst3, tst5, tst7] 

491 for tst in tsts12: 

492 self.assertRaises(lsst.pex.exceptions.LengthError, tst, i1, i2) 

493 

494 tsts21 = [tst2, tst4, tst6, tst8] 

495 for tst in tsts21: 

496 self.assertRaises(lsst.pex.exceptions.LengthError, tst, i2, i1) 

497 

498 def testMultiplyImages(self): 

499 """Test multiplication""" 

500 # Multiply by a MaskedImage 

501 self.mimage2 *= self.mimage 

502 

503 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], 

504 (self.imgVal2*self.imgVal1, self.EDGE, 

505 self.varVal2*pow(self.imgVal1, 2) + self.varVal1*pow(self.imgVal2, 2))) 

506 

507 # Divide a MaskedImage<int> by an Image<int>; this divides the variance Image<float> 

508 # by an Image<int> in C++ 

509 mimage_i = afwImage.MaskedImageI(self.mimage2.getDimensions()) 

510 mimage_i.set(900, 0x0, 1000.0) 

511 image_i = afwImage.ImageI(mimage_i.getDimensions(), 2) 

512 

513 mimage_i *= image_i 

514 

515 self.assertEqual(mimage_i[0, 0, afwImage.LOCAL], (1800, 0x0, 4000.0)) 

516 

517 # multiply by a scalar 

518 self.mimage *= self.imgVal1 

519 

520 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], 

521 (self.imgVal1*self.imgVal1, self.EDGE, self.varVal1*pow(self.imgVal1, 2))) 

522 

523 self.assertEqual(self.mimage.mask[1, 1, afwImage.LOCAL], self.EDGE) 

524 self.assertEqual(self.mimage.mask[2, 2, afwImage.LOCAL], 0x0) 

525 

526 def testScaledMultiplyImages(self): 

527 """Test multiplication by a scaled image""" 

528 # Multiply by an image 

529 c = 10.0 

530 mimage2_copy = self.mimage2.Factory(self.mimage2, True) # make a copy 

531 self.mimage2.scaledMultiplies(c, self.mimage) 

532 # 

533 # Now repeat calculation using a temporary 

534 # 

535 tmp = self.mimage.Factory(self.mimage, True) 

536 tmp *= c 

537 mimage2_copy *= tmp 

538 

539 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], mimage2_copy[0, 0, afwImage.LOCAL]) 

540 

541 def testDivideImages(self): 

542 """Test division""" 

543 # Divide by a MaskedImage 

544 mimage2_copy = self.mimage2.Factory(self.mimage2, True) # make a copy 

545 mimage2_copy /= self.mimage 

546 

547 self.assertEqual(mimage2_copy.image[0, 0, afwImage.LOCAL], 

548 self.imgVal2/self.imgVal1) 

549 self.assertEqual(mimage2_copy.mask[0, 0, afwImage.LOCAL], self.EDGE) 

550 self.assertAlmostEqual(mimage2_copy.variance[0, 0, afwImage.LOCAL], 

551 (self.varVal2*pow(self.imgVal1, 2) 

552 + self.varVal1*pow(self.imgVal2, 2))/pow(self.imgVal1, 4), 10) 

553 # Divide by an Image (of the same type as MaskedImage.image) 

554 mimage = self.mimage2.Factory(self.mimage2, True) 

555 mimage /= mimage.image 

556 

557 self.assertEqual(mimage[0, 0, afwImage.LOCAL], (self.imgVal2 / self.imgVal2, 0x0, self.varVal2)) 

558 

559 # Divide by an Image (of a different type from MaskedImage.image) 

560 # this isn't supported from python (it's OK in C++) 

561 if False: 

562 mimage = self.mimage2.Factory(self.mimage2, True) 

563 image = afwImage.ImageI(mimage.getDimensions(), 1) 

564 mimage /= image 

565 

566 self.assertEqual(mimage[0, 0, afwImage.LOCAL], 

567 (self.imgVal2, 0x0, self.varVal2)) 

568 

569 # Divide a MaskedImage<int> by an Image<int>; this divides the variance Image<float> 

570 # by an Image<int> in C++ 

571 mimage_i = afwImage.MaskedImageI(self.mimage2.getDimensions()) 

572 mimage_i.set(900, 0x0, 1000.0) 

573 image_i = afwImage.ImageI(mimage_i.getDimensions(), 2) 

574 

575 mimage_i /= image_i 

576 

577 self.assertEqual(mimage_i[0, 0, afwImage.LOCAL], (450, 0x0, 250.0)) 

578 

579 # divide by a scalar 

580 self.mimage /= self.imgVal1 

581 

582 self.assertEqual(self.mimage.image[0, 0, afwImage.LOCAL], 

583 self.imgVal1/self.imgVal1) 

584 self.assertEqual(self.mimage.mask[0, 0, afwImage.LOCAL], self.EDGE) 

585 self.assertAlmostEqual(self.mimage.variance[0, 0, afwImage.LOCAL], 

586 self.varVal1/pow(self.imgVal1, 2), 9) 

587 

588 self.assertEqual(self.mimage.mask[1, 1, afwImage.LOCAL], self.EDGE) 

589 self.assertEqual(self.mimage.mask[2, 2, afwImage.LOCAL], 0x0) 

590 

591 def testScaledDivideImages(self): 

592 """Test division by a scaled image""" 

593 # Divide by an image 

594 c = 10.0 

595 mimage2_copy = self.mimage2.Factory(self.mimage2, True) # make a copy 

596 self.mimage2.scaledDivides(c, self.mimage) 

597 # 

598 # Now repeat calculation using a temporary 

599 # 

600 tmp = self.mimage.Factory(self.mimage, True) 

601 tmp *= c 

602 mimage2_copy /= tmp 

603 

604 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], mimage2_copy[0, 0, afwImage.LOCAL]) 

605 

606 def testCopyConstructors(self): 

607 dimage = afwImage.MaskedImageF(self.mimage, True) # deep copy 

608 simage = afwImage.MaskedImageF(self.mimage) # shallow copy 

609 

610 self.mimage += 2 # should only change dimage 

611 self.assertEqual(dimage.image[0, 0, afwImage.LOCAL], self.imgVal1) 

612 self.assertEqual(simage.image[0, 0, afwImage.LOCAL], self.imgVal1 + 2) 

613 

614 def checkImgPatch12(self, img, x0, y0): 

615 """Check that a patch of an image is correct; origin of patch is at (x0, y0) in full image 

616 N.b. This isn't a general routine! Works only for testSubimages[12]""" 

617 

618 self.assertEqual(img[x0 - 1, y0 - 1, afwImage.LOCAL], 

619 (self.imgVal1, self.EDGE, self.varVal1)) 

620 self.assertEqual(img[x0, y0, afwImage.LOCAL], (666, self.BAD, 0)) 

621 self.assertEqual(img[x0 + 3, y0, afwImage.LOCAL], 

622 (self.imgVal1, 0x0, self.varVal1)) 

623 self.assertEqual(img[x0, y0 + 1, afwImage.LOCAL], (666, self.BAD, 0)) 

624 self.assertEqual(img[x0 + 3, y0 + 1, afwImage.LOCAL], 

625 (self.imgVal1, 0x0, self.varVal1)) 

626 self.assertEqual(img[x0, y0 + 2, afwImage.LOCAL], 

627 (self.imgVal1, 0x0, self.varVal1)) 

628 

629 def testOrigin(self): 

630 """Check that we can set and read the origin""" 

631 

632 im = afwImage.MaskedImageF(lsst.geom.ExtentI(10, 20)) 

633 x0 = y0 = 0 

634 

635 self.assertEqual(im.getX0(), x0) 

636 self.assertEqual(im.getY0(), y0) 

637 self.assertEqual(im.getXY0(), lsst.geom.PointI(x0, y0)) 

638 

639 x0, y0 = 3, 5 

640 im.setXY0(x0, y0) 

641 self.assertEqual(im.getX0(), x0) 

642 self.assertEqual(im.getY0(), y0) 

643 self.assertEqual(im.getXY0(), lsst.geom.PointI(x0, y0)) 

644 

645 x0, y0 = 30, 50 

646 im.setXY0(lsst.geom.Point2I(x0, y0)) 

647 self.assertEqual(im.getX0(), x0) 

648 self.assertEqual(im.getY0(), y0) 

649 self.assertEqual(im.getXY0(), lsst.geom.Point2I(x0, y0)) 

650 

651 def testSubimages1(self): 

652 smimage = afwImage.MaskedImageF( 

653 self.mimage, 

654 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(10, 5)), 

655 afwImage.LOCAL 

656 ) 

657 

658 simage = afwImage.MaskedImageF( 

659 smimage, 

660 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(3, 2)), 

661 afwImage.LOCAL 

662 ) 

663 self.assertEqual(simage.getX0(), 2) 

664 self.assertEqual(simage.getY0(), 2) # i.e. wrt self.mimage 

665 

666 mimage2 = afwImage.MaskedImageF(simage.getDimensions()) 

667 mimage2.image.set(666) 

668 mimage2.mask.set(self.BAD) 

669 simage[:] = mimage2 

670 

671 del simage 

672 del mimage2 

673 

674 self.checkImgPatch12(self.mimage, 2, 2) 

675 self.checkImgPatch12(smimage, 1, 1) 

676 

677 def testSubimages2(self): 

678 """Test subimages when we've played with the (x0, y0) value""" 

679 

680 self.mimage[9, 4, afwImage.LOCAL] = (888, 0x0, 0) 

681 

682 smimage = afwImage.MaskedImageF( 

683 self.mimage, 

684 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(10, 5)), 

685 afwImage.LOCAL 

686 ) 

687 # reset origin; doesn't affect pixel coordinate systems 

688 smimage.setXY0(lsst.geom.Point2I(0, 0)) 

689 

690 simage = afwImage.MaskedImageF( 

691 smimage, lsst.geom.Box2I(lsst.geom.Point2I(1, 1), 

692 lsst.geom.Extent2I(3, 2)), 

693 afwImage.LOCAL 

694 ) 

695 self.assertEqual(simage.getX0(), 1) 

696 self.assertEqual(simage.getY0(), 1) 

697 

698 mimage2 = afwImage.MaskedImageF(simage.getDimensions()) 

699 mimage2.set(666, self.BAD, 0.0) 

700 simage[:] = mimage2 

701 del simage 

702 del mimage2 

703 

704 self.checkImgPatch12(self.mimage, 2, 2) 

705 self.checkImgPatch12(smimage, 1, 1) 

706 

707 def checkImgPatch3(self, img, deep): 

708 """Check that a patch of an image is correct; origin of patch is at (x0, y0) in full image 

709 N.b. This isn't a general routine! Works only for testSubimages3""" 

710 

711 # Include deep in comparison so we can see which test fails 

712 self.assertEqual(img[0, 0, afwImage.LOCAL] + (deep, ), 

713 (100, 0x0, self.varVal1, deep)) 

714 self.assertEqual(img[10, 10, afwImage.LOCAL] + (deep, ), 

715 (200, 0xf, self.varVal1, deep)) 

716 

717 def testSubimages3(self): 

718 """Test subimages when we've played with the (x0, y0) value""" 

719 

720 self.mimage.image[20, 20, afwImage.LOCAL] = 200 

721 self.mimage.mask[20, 20, afwImage.LOCAL] = 0xf 

722 

723 for deep in (True, False): 

724 mimage = self.mimage.Factory( 

725 self.mimage, 

726 lsst.geom.Box2I(lsst.geom.Point2I(10, 10), 

727 lsst.geom.Extent2I(64, 64)), 

728 afwImage.LOCAL, 

729 deep) 

730 mimage.setXY0(lsst.geom.Point2I(0, 0)) 

731 mimage2 = mimage.Factory(mimage) 

732 

733 if display: 

734 afwDisplay.Display(frame=0).mtv(mimage2, title="testSubimages3") 

735 

736 self.checkImgPatch3(mimage2, deep) 

737 

738 def testSetCopiedMask(self): 

739 """Check that we can set the Mask with a copied Mask""" 

740 

741 crMask = self.mimage.mask.Factory(self.mimage.mask, True) 

742 msk = self.mimage.mask 

743 msk |= crMask 

744 del msk 

745 

746 def testVariance(self): 

747 """Check that we can set the variance from the gain""" 

748 gain = 2 

749 

750 var = self.mimage.variance 

751 var[:] = self.mimage.image 

752 var /= gain 

753 

754 def testTicket653(self): 

755 """How-to-repeat for #653""" 

756 # The original ticket read this file, but it doesn't reproduce for me, 

757 # As I don't see how reading an exposure from disk could make a difference 

758 # it's easier to just build an Image 

759 if False: 

760 im = afwImage.ImageF(os.path.join( 

761 lsst.utils.getPackageDir("afwdata"), "med_img.fits")) 

762 else: 

763 im = afwImage.ImageF(lsst.geom.Extent2I(10, 10)) 

764 mi = afwImage.MaskedImageF(im) 

765 afwImage.ExposureF(mi) 

766 

767 def testMaskedImageInitialisation(self): 

768 dims = self.mimage.getDimensions() 

769 factory = self.mimage.Factory 

770 

771 self.mimage.set(666) 

772 

773 del self.mimage # tempt C++ to reuse the memory 

774 self.mimage = factory(dims) 

775 self.assertEqual(self.mimage[10, 10, afwImage.LOCAL], (0, 0x0, 0)) 

776 

777 del self.mimage 

778 self.mimage = factory(lsst.geom.Extent2I(20, 20)) 

779 self.assertEqual(self.mimage[10, 10, afwImage.LOCAL], (0, 0x0, 0)) 

780 

781 def testImageSlices(self): 

782 """Test image slicing, which generate sub-images using Box2I under the covers""" 

783 im = afwImage.MaskedImageF(10, 20) 

784 im[4, 10] = (10, 0x2, 100) 

785 im[-3:, -2:, afwImage.LOCAL] = 100 

786 sim = im[1:4, 6:10] 

787 nan = -666 # a real NaN != NaN so tests fail 

788 sim[:] = (-1, 0x8, nan) 

789 im[0:4, 0:4] = im[2:6, 8:12] 

790 

791 if display: 

792 afwDisplay.Display(frame=1).mtv(im, title="testImageSlices") 

793 

794 self.assertEqual(im[0, 6, afwImage.LOCAL], (0, 0x0, 0)) 

795 self.assertEqual(im[6, 17, afwImage.LOCAL], (0, 0x0, 0)) 

796 self.assertEqual(im[7, 18, afwImage.LOCAL], (100, 0x0, 0)) 

797 self.assertEqual(im[9, 19, afwImage.LOCAL], (100, 0x0, 0)) 

798 self.assertEqual(im[1, 6, afwImage.LOCAL], (-1, 0x8, nan)) 

799 self.assertEqual(im[3, 9, afwImage.LOCAL], (-1, 0x8, nan)) 

800 self.assertEqual(im[4, 10, afwImage.LOCAL], (10, 0x2, 100)) 

801 self.assertEqual(im[4, 9, afwImage.LOCAL], (0, 0x0, 0)) 

802 self.assertEqual(im[2, 2, afwImage.LOCAL], (10, 0x2, 100)) 

803 self.assertEqual(im[0, 0, afwImage.LOCAL], (-1, 0x8, nan)) 

804 

805 def testConversionToScalar(self): 

806 """Test that even 1-pixel MaskedImages can't be converted to scalars""" 

807 im = afwImage.MaskedImageF(10, 20) 

808 

809 # only single pixel images may be converted 

810 self.assertRaises(TypeError, float, im) 

811 # actually, can't convert (img, msk, var) to scalar 

812 self.assertRaises(TypeError, float, im[0, 0]) 

813 

814 def testString(self): 

815 image = afwImage.MaskedImageF(100, 100) 

816 self.assertIn("image=", str(image)) 

817 self.assertIn("mask=", str(image)) 

818 self.assertIn("variance=", str(image)) 

819 self.assertIn(str(np.zeros((100, 100), dtype=image.image.dtype)), str(image)) 

820 self.assertIn(str(np.zeros((100, 100), dtype=image.mask.dtype)), str(image)) 

821 self.assertIn(str(np.zeros((100, 100), dtype=image.variance.dtype)), str(image)) 

822 self.assertIn("bbox=%s"%str(image.getBBox()), str(image)) 

823 self.assertIn("maskPlaneDict=%s"%str(image.mask.getMaskPlaneDict()), str(image)) 

824 

825 self.assertIn("MaskedImageF=(", repr(image)) 

826 

827 

828def printImg(img): 

829 print("%4s " % "", end=' ') 

830 for c in range(img.getWidth()): 

831 print("%7d" % c, end=' ') 

832 print() 

833 

834 for r in range(img.getHeight() - 1, -1, -1): 

835 print("%4d " % r, end=' ') 

836 for c in range(img.getWidth()): 

837 print("%7.1f" % float(img[c, r, afwImage.LOCAL]), end=' ') 

838 print() 

839 

840 

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

842 pass 

843 

844 

845def setup_module(module): 

846 lsst.utils.tests.init() 

847 

848 

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

850 lsst.utils.tests.init() 

851 unittest.main()