Coverage for tests/test_maskedImage.py: 12%

462 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-05-01 03:31 -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 testProperties(self): 

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

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

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

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

121 image2.array[:] = 5.0 

122 self.mimage.image = image2 

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

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

125 mask2.array[:] = 0x4 

126 self.mimage.mask = mask2 

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

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

129 var2.array[:] = 3.0 

130 self.mimage.variance = var2 

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

132 

133 def testSetGetValues(self): 

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

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

136 

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

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

139 

140 def testImagesOverlap(self): 

141 # make pairs of image, variance and mask planes 

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

143 # while making masked images 

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

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

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

147 bboxes = ( 

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

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

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

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

152 ) 

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

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

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

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

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

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

159 images, masks, variances, images, masks, variances): 

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

161 image1=image1, mask1=mask1, variance1=variance1, 

162 image2=image2, mask2=mask2, variance2=variance2): 

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

164 

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

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

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

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

169 

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

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

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

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

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

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

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

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

178 subregionsShouldOverlap = shouldOverlap and bbox1.overlaps(bbox2) 

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

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

181 

182 def testMaskedImageFromImage(self): 

183 w, h = 10, 20 

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

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

186 afwImage.Mask(dims), \ 

187 afwImage.ImageF(dims) 

188 im.set(666) 

189 

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

191 

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

193 

194 maskedImage = afwImage.MaskedImageF(im) 

195 self.assertEqual(im.getDimensions(), 

196 maskedImage.image.getDimensions()) 

197 self.assertEqual(im.getDimensions(), 

198 maskedImage.mask.getDimensions()) 

199 self.assertEqual(im.getDimensions(), 

200 maskedImage.variance.getDimensions()) 

201 

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

203 

204 def testMakeMaskedImageXY0(self): 

205 """Test that makeMaskedImage sets XY0 correctly""" 

206 im = afwImage.ImageF(200, 300) 

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

208 im.setXY0(*xy0) 

209 mi = afwImage.makeMaskedImage(im) 

210 

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

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

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

214 

215 def testCopyMaskedImage(self): 

216 """Test copy constructor""" 

217 # 

218 # shallow copy 

219 # 

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

221 

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

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

224 self.assertNotEqual(val00, nval00) 

225 

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

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

228 

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

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

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

232 # 

233 # deep copy 

234 # 

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

236 

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

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

239 

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

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

242 # 

243 # Copy with change of Image type 

244 # 

245 mi = self.mimage.convertD() 

246 

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

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

249 

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

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

252 # 

253 # Convert from U to F 

254 # 

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

256 val00 = (10, 0x10, 1) 

257 mi.set(val00) 

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

259 

260 fmi = mi.convertF() 

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

262 

263 def testAddImages(self): 

264 "Test addition" 

265 # add an image 

266 self.mimage2 += self.mimage 

267 

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

269 self.varVal1 + self.varVal2)) 

270 

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

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

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

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

275 

276 mimage_i += image_i 

277 

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

279 

280 # add a scalar 

281 self.mimage += self.imgVal1 

282 

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

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

285 

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

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

288 

289 # add a function 

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

291 self.mimage += self.function 

292 

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

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

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

296 

297 def testAddScaledImages(self): 

298 "Test addition by a scaled MaskedImage" 

299 # add an image 

300 c = 10.0 

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

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

303 # 

304 # Now repeat calculation using a temporary 

305 # 

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

307 tmp *= c 

308 mimage2_copy += tmp 

309 

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

311 

312 def testAssignWithBBox(self): 

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

314 """ 

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

316 (0, 0), 

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

318 )): 

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

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

321 destMI = afwImage.MaskedImageF(destMIDim) 

322 destImage = destMI.image 

323 destVariance = destMI.variance 

324 destMask = destMI.mask 

325 destMI.setXY0(xy0) 

326 srcMI = makeRampImage(*srcMIDim) 

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

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

329 

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

331 (0, 0), 

332 (2, 0), 

333 (0, 1), 

334 (1, 2), 

335 )): 

336 # None to omit the argument 

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

338 destImage[:] = -1.0 

339 destVariance[:] = -1.0 

340 destMask[:] = 0xFFFF 

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

342 if origin != afwImage.LOCAL: 

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

344 if origin is None: 

345 destMI.assign(srcMI, bbox) 

346 destMIView = afwImage.MaskedImageF(destMI, bbox) 

347 else: 

348 destMI.assign(srcMI, bbox, origin) 

349 destMIView = afwImage.MaskedImageF(destMI, bbox, origin) 

350 self.assertMaskedImagesEqual(destMIView, srcMI) 

351 numPixNotAssigned = ( 

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

353 self.assertEqual( 

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

355 self.assertEqual( 

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

357 self.assertEqual( 

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

359 

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

361 (-1, 0), 

362 (3, 0), 

363 (0, -1), 

364 (1, 3), 

365 )): 

366 # None to omit the argument 

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

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

369 if origin != afwImage.LOCAL: 

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

371 if origin is None: 

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

373 else: 

374 self.assertRaises( 

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

376 

377 def testAssignWithoutBBox(self): 

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

379 """ 

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

381 (0, 0), 

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

383 )): 

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

385 destMI = afwImage.MaskedImageF(destMIDim) 

386 destMI.setXY0(xy0) 

387 destImage = destMI.image 

388 destVariance = destMI.variance 

389 destMask = destMI.mask 

390 srcMI = makeRampImage(*destMIDim) 

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

392 

393 destImage[:] = -1.0 

394 destVariance[:] = -1.0 

395 destMask[:] = 0xFFFF 

396 destMI.assign(srcMI) 

397 self.assertMaskedImagesEqual(destMI, srcMI) 

398 

399 destImage[:] = -1.0 

400 destVariance[:] = -1.0 

401 destMask[:] = 0xFFFF 

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

403 self.assertMaskedImagesEqual(destMI, srcMI) 

404 

405 def testSubtractImages(self): 

406 "Test subtraction" 

407 # subtract an image 

408 self.mimage2 -= self.mimage 

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

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

411 

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

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

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

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

416 

417 mimage_i -= image_i 

418 

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

420 

421 # subtract a scalar 

422 self.mimage -= self.imgVal1 

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

424 

425 def testSubtractScaledImages(self): 

426 "Test subtraction by a scaled MaskedImage" 

427 # subtract a scaled image 

428 c = 10.0 

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

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

431 # 

432 # Now repeat calculation using a temporary 

433 # 

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

435 tmp *= c 

436 mimage2_copy -= tmp 

437 

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

439 

440 def testArithmeticImagesMismatch(self): 

441 "Test arithmetic operations on MaskedImages of different sizes" 

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

443 i1.set(100) 

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

445 i2.set(10) 

446 

447 def tst1(i1, i2): 

448 i1 -= i2 

449 

450 def tst2(i1, i2): 

451 i1.scaledMinus(1.0, i2) 

452 

453 def tst3(i1, i2): 

454 i1 += i2 

455 

456 def tst4(i1, i2): 

457 i1.scaledPlus(1.0, i2) 

458 

459 def tst5(i1, i2): 

460 i1 *= i2 

461 

462 def tst6(i1, i2): 

463 i1.scaledMultiplies(1.0, i2) 

464 

465 def tst7(i1, i2): 

466 i1 /= i2 

467 

468 def tst8(i1, i2): 

469 i1.scaledDivides(1.0, i2) 

470 

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

472 for tst in tsts12: 

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

474 

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

476 for tst in tsts21: 

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

478 

479 def testMultiplyImages(self): 

480 """Test multiplication""" 

481 # Multiply by a MaskedImage 

482 self.mimage2 *= self.mimage 

483 

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

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

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

487 

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

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

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

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

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

493 

494 mimage_i *= image_i 

495 

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

497 

498 # multiply by a scalar 

499 self.mimage *= self.imgVal1 

500 

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

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

503 

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

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

506 

507 def testScaledMultiplyImages(self): 

508 """Test multiplication by a scaled image""" 

509 # Multiply by an image 

510 c = 10.0 

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

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

513 # 

514 # Now repeat calculation using a temporary 

515 # 

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

517 tmp *= c 

518 mimage2_copy *= tmp 

519 

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

521 

522 def testDivideImages(self): 

523 """Test division""" 

524 # Divide by a MaskedImage 

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

526 mimage2_copy /= self.mimage 

527 

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

529 self.imgVal2/self.imgVal1) 

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

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

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

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

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

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

536 mimage /= mimage.image 

537 

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

539 

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

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

542 if False: 

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

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

545 mimage /= image 

546 

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

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

549 

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

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

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

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

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

555 

556 mimage_i /= image_i 

557 

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

559 

560 # divide by a scalar 

561 self.mimage /= self.imgVal1 

562 

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

564 self.imgVal1/self.imgVal1) 

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

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

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

568 

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

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

571 

572 def testScaledDivideImages(self): 

573 """Test division by a scaled image""" 

574 # Divide by an image 

575 c = 10.0 

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

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

578 # 

579 # Now repeat calculation using a temporary 

580 # 

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

582 tmp *= c 

583 mimage2_copy /= tmp 

584 

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

586 

587 def testCopyConstructors(self): 

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

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

590 

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

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

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

594 

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

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

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

598 

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

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

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

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

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

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

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

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

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

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

609 

610 def testOrigin(self): 

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

612 

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

614 x0 = y0 = 0 

615 

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

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

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

619 

620 x0, y0 = 3, 5 

621 im.setXY0(x0, y0) 

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

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

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

625 

626 x0, y0 = 30, 50 

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

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

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

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

631 

632 def testSubimages1(self): 

633 smimage = afwImage.MaskedImageF( 

634 self.mimage, 

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

636 afwImage.LOCAL 

637 ) 

638 

639 simage = afwImage.MaskedImageF( 

640 smimage, 

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

642 afwImage.LOCAL 

643 ) 

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

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

646 

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

648 mimage2.image.set(666) 

649 mimage2.mask.set(self.BAD) 

650 simage[:] = mimage2 

651 

652 del simage 

653 del mimage2 

654 

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

656 self.checkImgPatch12(smimage, 1, 1) 

657 

658 def testSubimages2(self): 

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

660 

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

662 

663 smimage = afwImage.MaskedImageF( 

664 self.mimage, 

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

666 afwImage.LOCAL 

667 ) 

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

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

670 

671 simage = afwImage.MaskedImageF( 

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

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

674 afwImage.LOCAL 

675 ) 

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

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

678 

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

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

681 simage[:] = mimage2 

682 del simage 

683 del mimage2 

684 

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

686 self.checkImgPatch12(smimage, 1, 1) 

687 

688 def checkImgPatch3(self, img, deep): 

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

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

691 

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

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

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

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

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

697 

698 def testSubimages3(self): 

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

700 

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

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

703 

704 for deep in (True, False): 

705 mimage = self.mimage.Factory( 

706 self.mimage, 

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

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

709 afwImage.LOCAL, 

710 deep) 

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

712 mimage2 = mimage.Factory(mimage) 

713 

714 if display: 

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

716 

717 self.checkImgPatch3(mimage2, deep) 

718 

719 def testSetCopiedMask(self): 

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

721 

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

723 msk = self.mimage.mask 

724 msk |= crMask 

725 del msk 

726 

727 def testVariance(self): 

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

729 gain = 2 

730 

731 var = self.mimage.variance 

732 var[:] = self.mimage.image 

733 var /= gain 

734 

735 def testTicket653(self): 

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

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

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

739 # it's easier to just build an Image 

740 if False: 

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

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

743 else: 

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

745 mi = afwImage.MaskedImageF(im) 

746 afwImage.ExposureF(mi) 

747 

748 def testMaskedImageInitialisation(self): 

749 dims = self.mimage.getDimensions() 

750 factory = self.mimage.Factory 

751 

752 self.mimage.set(666) 

753 

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

755 self.mimage = factory(dims) 

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

757 

758 del self.mimage 

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

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

761 

762 def testImageSlices(self): 

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

764 im = afwImage.MaskedImageF(10, 20) 

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

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

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

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

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

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

771 

772 if display: 

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

774 

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

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

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

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

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

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

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

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

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

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

785 

786 def testConversionToScalar(self): 

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

788 im = afwImage.MaskedImageF(10, 20) 

789 

790 # only single pixel images may be converted 

791 self.assertRaises(TypeError, float, im) 

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

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

794 

795 def testString(self): 

796 image = afwImage.MaskedImageF(100, 100) 

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

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

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

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

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

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

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

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

805 

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

807 

808 

809def printImg(img): 

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

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

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

813 print() 

814 

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

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

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

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

819 print() 

820 

821 

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

823 pass 

824 

825 

826def setup_module(module): 

827 lsst.utils.tests.init() 

828 

829 

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

831 lsst.utils.tests.init() 

832 unittest.main()