Coverage for tests/test_footprint2.py: 10%

408 statements  

« prev     ^ index     » next       coverage.py v7.1.0, created at 2023-02-05 17:50 -0800

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 Footprints, and FootprintSets 

24 

25Run with: 

26 python test_footprint2.py 

27or 

28 pytest test_footprint2.py 

29""" 

30 

31import unittest 

32 

33import lsst.utils.tests 

34import lsst.geom 

35import lsst.afw.image as afwImage 

36import lsst.afw.geom as afwGeom 

37import lsst.afw.detection as afwDetect 

38import lsst.afw.display as afwDisplay 

39 

40afwDisplay.setDefaultMaskTransparency(75) 

41try: 

42 type(display) 

43except NameError: 

44 display = False 

45 

46 

47def toString(*args): 

48 """toString written in python""" 

49 if len(args) == 1: 

50 args = args[0] 

51 

52 y, x0, x1 = args 

53 return f"{y}: {x0}..{x1}" 

54 

55 

56def peakFromImage(im, pos): 

57 """Function to extract the sort key of peak height. Sort by decreasing peak height.""" 

58 val = im[pos[0], pos[1], afwImage.LOCAL][0] 

59 return -1.0*val 

60 

61 

62class Object: 

63 

64 def __init__(self, val, spans): 

65 self.val = val 

66 self.spans = spans 

67 

68 def insert(self, im): 

69 """Insert self into an image""" 

70 for sp in self.spans: 

71 y, x0, x1 = sp 

72 for x in range(x0, x1 + 1): 

73 im[x, y, afwImage.LOCAL] = self.val 

74 

75 def __eq__(self, other): 

76 for osp, sp in zip(other.getSpans(), self.spans): 

77 if osp.toString() != toString(sp): 

78 return False 

79 

80 return True 

81 

82 

83class FootprintSetTestCase(unittest.TestCase): 

84 """A test case for FootprintSet""" 

85 

86 def setUp(self): 

87 self.im = afwImage.ImageU(lsst.geom.Extent2I(12, 8)) 

88 # 

89 # Objects that we should detect 

90 # 

91 self.objects = [] 

92 self.objects += [Object(10, [(1, 4, 4), (2, 3, 5), (3, 4, 4)])] 

93 self.objects += [Object(20, [(5, 7, 8), (5, 10, 10), (6, 8, 9)])] 

94 self.objects += [Object(20, [(6, 3, 3)])] 

95 

96 self.im.set(0) # clear image 

97 for obj in self.objects: 

98 obj.insert(self.im) 

99 

100 def tearDown(self): 

101 del self.im 

102 

103 def testGC(self): 

104 """Check that FootprintSets are automatically garbage collected (when MemoryTestCase runs)""" 

105 

106 afwDetect.FootprintSet(afwImage.ImageU(lsst.geom.Extent2I(10, 20)), 

107 afwDetect.Threshold(10)) 

108 

109 def testFootprints(self): 

110 """Check that we found the correct number of objects and that they are correct""" 

111 ds = afwDetect.FootprintSet(self.im, afwDetect.Threshold(10)) 

112 

113 objects = ds.getFootprints() 

114 

115 self.assertEqual(len(objects), len(self.objects)) 

116 for i in range(len(objects)): 

117 self.assertEqual(objects[i], self.objects[i]) 

118 

119 def testFootprints2(self): 

120 """Check that we found the correct number of objects using FootprintSet""" 

121 ds = afwDetect.FootprintSet(self.im, afwDetect.Threshold(10)) 

122 

123 objects = ds.getFootprints() 

124 

125 self.assertEqual(len(objects), len(self.objects)) 

126 for i in range(len(objects)): 

127 self.assertEqual(objects[i], self.objects[i]) 

128 

129 def testFootprintsImageId(self): 

130 """Check that we can insert footprints into an Image""" 

131 ds = afwDetect.FootprintSet(self.im, afwDetect.Threshold(10)) 

132 objects = ds.getFootprints() 

133 

134 idImage = afwImage.ImageU(self.im.getDimensions()) 

135 idImage.set(0) 

136 

137 for i, foot in enumerate(objects): 

138 foot.spans.setImage(idImage, i + 1) 

139 

140 for i in range(len(objects)): 

141 for sp in objects[i].getSpans(): 

142 for x in range(sp.getX0(), sp.getX1() + 1): 

143 self.assertEqual(idImage[x, sp.getY(), afwImage.LOCAL], i + 1) 

144 

145 def testFootprintSetImageId(self): 

146 """Check that we can insert a FootprintSet into an Image, setting relative IDs""" 

147 ds = afwDetect.FootprintSet(self.im, afwDetect.Threshold(10)) 

148 objects = ds.getFootprints() 

149 

150 idImage = ds.insertIntoImage() 

151 if display: 

152 afwDisplay.Display(frame=2).mtv(idImage, title=self._testMethodName + " image") 

153 

154 for i in range(len(objects)): 

155 for sp in objects[i].getSpans(): 

156 for x in range(sp.getX0(), sp.getX1() + 1): 

157 self.assertEqual(idImage[x, sp.getY(), afwImage.LOCAL], i + 1) 

158 

159 def testFootprintsImage(self): 

160 """Check that we can search Images as well as MaskedImages""" 

161 ds = afwDetect.FootprintSet(self.im, afwDetect.Threshold(10)) 

162 

163 objects = ds.getFootprints() 

164 

165 self.assertEqual(len(objects), len(self.objects)) 

166 for i in range(len(objects)): 

167 self.assertEqual(objects[i], self.objects[i]) 

168 

169 def testGrow2(self): 

170 """Grow some more interesting shaped Footprints. Informative with display, but no numerical tests""" 

171 # Can't set mask plane as the image is not a masked image. 

172 ds = afwDetect.FootprintSet(self.im, afwDetect.Threshold(10)) 

173 

174 idImage = afwImage.ImageU(self.im.getDimensions()) 

175 idImage.set(0) 

176 

177 i = 1 

178 for foot in ds.getFootprints()[0:1]: 

179 foot.dilate(3, afwGeom.Stencil.MANHATTAN) 

180 foot.spans.setImage(idImage, i, doClip=True) 

181 i += 1 

182 

183 if display: 

184 afwDisplay.Display(frame=1).mtv(idImage, title=self._testMethodName + " image") 

185 

186 def testGrow(self): 

187 """Grow footprints using the FootprintSet constructor""" 

188 fs = afwDetect.FootprintSet(self.im, afwDetect.Threshold(10)) 

189 self.assertEqual(len(fs.getFootprints()), len(self.objects)) 

190 for isotropic in (True, False, afwDetect.FootprintControl(True),): 

191 grown = afwDetect.FootprintSet(fs, 1, isotropic) 

192 self.assertEqual(len(fs.getFootprints()), len(self.objects)) 

193 

194 self.assertGreater(len(grown.getFootprints()), 0) 

195 self.assertLessEqual(len(grown.getFootprints()), 

196 len(fs.getFootprints())) 

197 

198 def testFootprintControl(self): 

199 """Test the FootprintControl constructor""" 

200 fctrl = afwDetect.FootprintControl() 

201 self.assertFalse(fctrl.isCircular()[0]) # not set 

202 self.assertFalse(fctrl.isIsotropic()[0]) # not set 

203 

204 fctrl.growIsotropic(False) 

205 self.assertTrue(fctrl.isCircular()[0]) 

206 self.assertTrue(fctrl.isIsotropic()[0]) 

207 self.assertTrue(fctrl.isCircular()[1]) 

208 self.assertFalse(fctrl.isIsotropic()[1]) 

209 

210 fctrl = afwDetect.FootprintControl() 

211 fctrl.growLeft(False) 

212 self.assertTrue(fctrl.isLeft()[0]) # it's now set 

213 self.assertFalse(fctrl.isLeft()[1]) # ... but False 

214 

215 fctrl = afwDetect.FootprintControl(True, False, False, False) 

216 self.assertTrue(fctrl.isLeft()[0]) 

217 self.assertTrue(fctrl.isRight()[0]) 

218 self.assertTrue(fctrl.isUp()[0]) 

219 self.assertTrue(fctrl.isDown()[0]) 

220 

221 self.assertTrue(fctrl.isLeft()[1]) 

222 self.assertFalse(fctrl.isRight()[1]) 

223 

224 def testGrowCircular(self): 

225 """Grow footprints in all 4 directions using the FootprintSet/FootprintControl constructor """ 

226 im = afwImage.MaskedImageF(11, 11) 

227 im[5, 5, afwImage.LOCAL] = (10, 0x0, 0.0) 

228 fs = afwDetect.FootprintSet(im, afwDetect.Threshold(10)) 

229 self.assertEqual(len(fs.getFootprints()), 1) 

230 

231 radius = 3 # How much to grow by 

232 for fctrl in (afwDetect.FootprintControl(), 

233 afwDetect.FootprintControl(True), 

234 afwDetect.FootprintControl(True, True), 

235 ): 

236 grown = afwDetect.FootprintSet(fs, radius, fctrl) 

237 afwDetect.setMaskFromFootprintList( 

238 im.getMask(), grown.getFootprints(), 0x10) 

239 

240 if display: 

241 afwDisplay.Display(frame=3).mtv(im, title=self._testMethodName + " image") 

242 

243 foot = grown.getFootprints()[0] 

244 

245 if not fctrl.isCircular()[0]: 

246 self.assertEqual(foot.getArea(), 1) 

247 elif fctrl.isCircular()[0]: 

248 assert radius == 3 

249 if fctrl.isIsotropic()[1]: 

250 self.assertEqual(foot.getArea(), 29) 

251 else: 

252 self.assertEqual(foot.getArea(), 25) 

253 

254 def testGrowLRUD(self): 

255 """Grow footprints in various directions using the FootprintSet/FootprintControl constructor """ 

256 im = afwImage.MaskedImageF(11, 11) 

257 x0, y0, ny = 5, 5, 3 

258 for y in range(y0 - ny//2, y0 + ny//2 + 1): 

259 im[x0, y, afwImage.LOCAL] = (10, 0x0, 0.0) 

260 fs = afwDetect.FootprintSet(im, afwDetect.Threshold(10)) 

261 self.assertEqual(len(fs.getFootprints()), 1) 

262 

263 ngrow = 2 # How much to grow by 

264 # 

265 # Test growing to the left and/or right 

266 # 

267 for fctrl in ( 

268 afwDetect.FootprintControl(False, True, False, False), 

269 afwDetect.FootprintControl(True, False, False, False), 

270 afwDetect.FootprintControl(True, True, False, False), 

271 ): 

272 fs = afwDetect.FootprintSet(im, afwDetect.Threshold(10)) 

273 grown = afwDetect.FootprintSet(fs, ngrow, fctrl) 

274 im.getMask().set(0) 

275 afwDetect.setMaskFromFootprintList( 

276 im.getMask(), grown.getFootprints(), 0x10) 

277 

278 if display: 

279 afwDisplay.Display(frame=3).mtv(im, title=self._testMethodName + " image") 

280 

281 foot = grown.getFootprints()[0] 

282 nextra = 0 

283 if fctrl.isLeft()[1]: 

284 nextra += ngrow 

285 for y in range(y0 - ny//2, y0 + ny//2 + 1): 

286 self.assertNotEqual(im.getMask()[x0 - 1, y, afwImage.LOCAL], 0) 

287 

288 if fctrl.isRight()[1]: 

289 nextra += ngrow 

290 for y in range(y0 - ny//2, y0 + ny//2 + 1): 

291 self.assertNotEqual(im.getMask()[x0 + 1, y, afwImage.LOCAL], 0) 

292 

293 self.assertEqual(foot.getArea(), (1 + nextra)*ny) 

294 # 

295 # Test growing to up and/or down 

296 # 

297 for fctrl in ( 

298 afwDetect.FootprintControl(False, False, True, False), 

299 afwDetect.FootprintControl(False, False, False, True), 

300 afwDetect.FootprintControl(False, False, True, True), 

301 ): 

302 grown = afwDetect.FootprintSet(fs, ngrow, fctrl) 

303 im.getMask().set(0) 

304 afwDetect.setMaskFromFootprintList( 

305 im.getMask(), grown.getFootprints(), 0x10) 

306 

307 if display: 

308 afwDisplay.Display(frame=2).mtv(im, title=self._testMethodName + " image") 

309 

310 foot = grown.getFootprints()[0] 

311 nextra = 0 

312 if fctrl.isUp()[1]: 

313 nextra += ngrow 

314 for y in range(y0 + ny//2 + 1, y0 + ny//2 + ngrow + 1): 

315 self.assertNotEqual(im.getMask()[x0, y, afwImage.LOCAL], 0) 

316 

317 if fctrl.isDown()[1]: 

318 nextra += ngrow 

319 for y in range(y0 - ny//2 - 1, y0 - ny//2 - ngrow - 1): 

320 self.assertNotEqual(im.getMask()[x0, y, afwImage.LOCAL], 0) 

321 

322 self.assertEqual(foot.getArea(), ny + nextra) 

323 

324 def testGrowLRUD2(self): 

325 """Grow footprints in various directions using the FootprintSet/FootprintControl constructor 

326 

327 Check that overlapping grown Footprints give the expected answers 

328 """ 

329 ngrow = 3 # How much to grow by 

330 for fctrl, xy in [ 

331 (afwDetect.FootprintControl(True, True, 

332 False, False), [(4, 5), (5, 6), (6, 5)]), 

333 (afwDetect.FootprintControl(False, False, 

334 True, True), [(5, 4), (6, 5), (5, 6)]), 

335 ]: 

336 im = afwImage.MaskedImageF(11, 11) 

337 for x, y in xy: 

338 im[x, y, afwImage.LOCAL] = (10, 0x0, 0.0) 

339 fs = afwDetect.FootprintSet(im, afwDetect.Threshold(10)) 

340 self.assertEqual(len(fs.getFootprints()), 1) 

341 

342 grown = afwDetect.FootprintSet(fs, ngrow, fctrl) 

343 im.getMask().set(0) 

344 afwDetect.setMaskFromFootprintList( 

345 im.getMask(), grown.getFootprints(), 0x10) 

346 

347 if display: 

348 afwDisplay.Display(frame=1).mtv(im, title=self._testMethodName + " image") 

349 

350 self.assertEqual(len(grown.getFootprints()), 1) 

351 foot = grown.getFootprints()[0] 

352 

353 npix = 1 + 2*ngrow 

354 npix += 3 + 2*ngrow # 3: distance between pair of set pixels 000X0X000 

355 self.assertEqual(foot.getArea(), npix) 

356 

357 def testInf(self): 

358 """Test detection for images with Infs""" 

359 

360 im = afwImage.MaskedImageF(lsst.geom.Extent2I(10, 20)) 

361 im.set(0) 

362 

363 import numpy 

364 for x in range(im.getWidth()): 

365 im[x, -1, afwImage.LOCAL] = (numpy.Inf, 0x0, 0) 

366 

367 ds = afwDetect.FootprintSet(im, afwDetect.createThreshold(100)) 

368 

369 objects = ds.getFootprints() 

370 afwDetect.setMaskFromFootprintList(im.getMask(), objects, 0x10) 

371 

372 if display: 

373 afwDisplay.Display(frame=2).mtv(im, title=self._testMethodName + " image") 

374 

375 self.assertEqual(len(objects), 1) 

376 

377 

378class PeaksInFootprintsTestCase(unittest.TestCase): 

379 """A test case for detecting Peaks within Footprints""" 

380 

381 def doSetUp(self, dwidth=0, dheight=0, x0=0, y0=0): 

382 width, height = 14 + x0 + dwidth, 10 + y0 + dheight 

383 self.im = afwImage.MaskedImageF(lsst.geom.Extent2I(width, height)) 

384 # 

385 # Objects that we should detect 

386 # 

387 self.objects, self.peaks = [], [] 

388 self.objects.append( 

389 [[4, 1, 10], [3, 2, 10], [4, 2, 20], [5, 2, 10], [4, 3, 10], ]) 

390 self.peaks.append([[4, 2]]) 

391 self.objects.append( 

392 [[9, 7, 30], [10, 7, 29], [12, 7, 25], [10, 8, 27], [11, 8, 26], ]) 

393 self.peaks.append([[9, 7]]) 

394 self.objects.append([[3, 8, 10], [4, 8, 10], ]) 

395 self.peaks.append([[3, 8], [4, 8], ]) 

396 

397 for pp in self.peaks: # allow for x0, y0 

398 for p in pp: 

399 p[0] += x0 

400 p[1] += y0 

401 for oo in self.objects: 

402 for o in oo: 

403 o[0] += x0 

404 o[1] += y0 

405 

406 self.im.set((0, 0x0, 0)) # clear image 

407 for obj in self.objects: 

408 for x, y, I in obj: 

409 self.im.getImage()[x, y, afwImage.LOCAL] = I 

410 

411 def setUp(self): 

412 self.im, self.fs = None, None 

413 

414 def tearDown(self): 

415 del self.im 

416 del self.fs 

417 

418 def doTestPeaks(self, dwidth=0, dheight=0, x0=0, y0=0, threshold=10, callback=None, polarity=True, 

419 grow=0): 

420 """Worker routine for tests 

421 polarity: True if should search for +ve pixels""" 

422 

423 self.doSetUp(dwidth, dheight, x0, y0) 

424 if not polarity: 

425 self.im *= -1 

426 

427 if callback: 

428 callback() 

429 

430 def peakDescending(p): 

431 """Sort self.peaks in decreasing peak height to match Footprint.getPeaks()""" 

432 return p[2]*-1.0 

433 for i, peaks in enumerate(self.peaks): 

434 self.peaks[i] = sorted([(x, y, self.im.getImage()[x, y, afwImage.LOCAL]) for x, y in peaks], 

435 key=peakDescending) 

436 

437 threshold = afwDetect.Threshold( 

438 threshold, afwDetect.Threshold.VALUE, polarity) 

439 fs = afwDetect.FootprintSet(self.im, threshold, "BINNED1") 

440 

441 if grow: 

442 fs = afwDetect.FootprintSet(fs, grow, True) 

443 msk = self.im.getMask() 

444 afwDetect.setMaskFromFootprintList( 

445 msk, fs.getFootprints(), msk.getPlaneBitMask("DETECTED")) 

446 del msk 

447 

448 self.fs = fs 

449 self.checkPeaks(dwidth, dheight, frame=3) 

450 

451 def checkPeaks(self, dwidth=0, dheight=0, frame=3): 

452 """Check that we got the peaks right""" 

453 feet = self.fs.getFootprints() 

454 # 

455 # Check that we found all the peaks 

456 # 

457 self.assertEqual(sum([len(f.getPeaks()) for f in feet]), 

458 sum([len(f.getPeaks()) for f in feet])) 

459 

460 if display: 

461 disp = afwDisplay.Display(frame=frame) 

462 disp.mtv(self.im, title=self._testMethodName + " image") 

463 

464 with disp.Buffering(): 

465 for i, foot in enumerate(feet): 

466 for p in foot.getPeaks(): 

467 disp.dot("+", p.getIx(), p.getIy(), size=0.4) 

468 

469 if i < len(self.peaks): 

470 for trueX, trueY, peakVal in self.peaks[i]: 

471 disp.dot("x", trueX, trueY, size=0.4, ctype=afwDisplay.RED) 

472 

473 for i, foot in enumerate(feet): 

474 npeak = None 

475 # 

476 # Peaks that touch the edge are handled differently, as only the single highest/lowest pixel 

477 # is treated as a Peak 

478 # 

479 if (dwidth != 0 or dheight != 0): 

480 if (foot.getBBox().getMinX() == 0 

481 or foot.getBBox().getMaxX() == self.im.getWidth() - 1 

482 or foot.getBBox().getMinY() == 0 

483 or foot.getBBox().getMaxY() == self.im.getHeight() - 1): 

484 npeak = 1 

485 

486 if npeak is None: 

487 npeak = len(self.peaks[i]) 

488 

489 self.assertEqual(len(foot.getPeaks()), npeak) 

490 

491 for j, p in enumerate(foot.getPeaks()): 

492 trueX, trueY, peakVal = self.peaks[i][j] 

493 self.assertEqual((p.getIx(), p.getIy()), (trueX, trueY)) 

494 

495 def testSinglePeak(self): 

496 """Test that we can find single Peaks in Footprints""" 

497 

498 self.doTestPeaks() 

499 

500 def testSingleNegativePeak(self): 

501 """Test that we can find single Peaks in Footprints when looking for -ve detections""" 

502 

503 self.doTestPeaks(polarity=False) 

504 

505 def testSinglePeakAtEdge(self): 

506 """Test that we handle Peaks correctly at the edge""" 

507 

508 self.doTestPeaks(dheight=-1) 

509 

510 def testSingleNegativePeakAtEdge(self): 

511 """Test that we handle -ve Peaks correctly at the edge""" 

512 

513 self.doTestPeaks(dheight=-1, polarity=False) 

514 

515 def testMultiPeak(self): 

516 """Test that multiple peaks are handled correctly""" 

517 def callback(): 

518 x, y = 12, 7 

519 self.im.getImage()[x, y, afwImage.LOCAL] = 100 

520 self.peaks[1].append((x, y)) 

521 

522 self.doTestPeaks(callback=callback) 

523 

524 def testMultiNegativePeak(self): 

525 """Test that multiple negative peaks are handled correctly""" 

526 def callback(): 

527 x, y = 12, 7 

528 self.im.getImage()[x, y, afwImage.LOCAL] = -100 

529 self.peaks[1].append((x, y)) 

530 

531 self.doTestPeaks(polarity=False, callback=callback) 

532 

533 def testGrowFootprints(self): 

534 """Test that we can grow footprints, correctly merging those that now touch""" 

535 def callback(): 

536 self.im.getImage()[10, 4, afwImage.LOCAL] = 20 

537 self.peaks[-2].append((10, 4,)) 

538 

539 self.doTestPeaks(dwidth=1, dheight=1, callback=callback, grow=1) 

540 

541 def testGrowFootprints2(self): 

542 """Test that we can grow footprints, correctly merging those that now overlap 

543 N.b. this caused RHL's initial implementation to crash 

544 """ 

545 def callback(): 

546 self.im.getImage()[10, 4, afwImage.LOCAL] = 20 

547 self.peaks[-2].append((10, 4, )) 

548 

549 def peaksSortKey(p): 

550 return peakFromImage(self.im, p) 

551 self.peaks[0] = sorted(sum(self.peaks, []), key=peaksSortKey) 

552 

553 self.doTestPeaks(x0=0, y0=2, dwidth=2, dheight=2, 

554 callback=callback, grow=2) 

555 

556 def testGrowFootprints3(self): 

557 """Test that we can grow footprints, correctly merging those that now totally overwritten""" 

558 

559 self.im = afwImage.MaskedImageF(14, 11) 

560 

561 self.im.getImage().set(0) 

562 self.peaks = [] 

563 

564 value = 11 

565 for x, y in [(4, 7), (5, 7), (6, 7), (7, 7), (8, 7), 

566 (4, 6), (8, 6), 

567 (4, 5), (8, 5), 

568 (4, 4), (8, 4), 

569 (4, 3), (8, 3), 

570 ]: 

571 self.im.getImage()[x, y, afwImage.LOCAL] = value 

572 value -= 1e-3 

573 

574 self.im.getImage()[4, 7, afwImage.LOCAL] = 15 

575 self.peaks.append([(4, 7,), ]) 

576 

577 self.im.getImage()[6, 5, afwImage.LOCAL] = 30 

578 self.peaks[0].append((6, 5,)) 

579 

580 self.fs = afwDetect.FootprintSet( 

581 self.im, afwDetect.Threshold(10), "BINNED1") 

582 # 

583 # The disappearing Footprint special case only shows up if the outer Footprint is grown 

584 # _after_ the inner one. So arrange the order properly 

585 feet = self.fs.getFootprints() 

586 feet[0], feet[1] = feet[1], feet[0] 

587 

588 msk = self.im.getMask() 

589 

590 grow = 2 

591 self.fs = afwDetect.FootprintSet(self.fs, grow, False) 

592 afwDetect.setMaskFromFootprintList(msk, self.fs.getFootprints(), 

593 msk.getPlaneBitMask("DETECTED_NEGATIVE")) 

594 

595 if display: 

596 frame = 0 

597 

598 disp = afwDisplay.Display(frame=frame) 

599 disp.mtv(self.im, title=self._testMethodName + " image") 

600 

601 with disp.Buffering(): 

602 for i, foot in enumerate(self.fs.getFootprints()): 

603 for p in foot.getPeaks(): 

604 disp.dot("+", p.getIx(), p.getIy(), size=0.4) 

605 

606 if i < len(self.peaks): 

607 for trueX, trueY in self.peaks[i]: 

608 disp.dot("x", trueX, trueY, size=0.4, ctype=afwDisplay.RED) 

609 

610 self.assertEqual(len(self.fs.getFootprints()), 1) 

611 self.assertEqual(len(self.fs.getFootprints()[ 

612 0].getPeaks()), len(self.peaks[0])) 

613 

614 def testMergeFootprints(self): # YYYY 

615 """Merge positive and negative Footprints""" 

616 x0, y0 = 5, 6 

617 dwidth, dheight = 6, 7 

618 

619 def callback(): 

620 x, y, value = x0 + 10, y0 + 4, -20 

621 self.im.getImage()[x, y, afwImage.LOCAL] = value 

622 peaks2.append((x, y, value)) 

623 

624 for grow1, grow2 in [(1, 1), (3, 3), (6, 6), ]: 

625 peaks2 = [] 

626 self.doTestPeaks(threshold=10, callback=callback, grow=0, 

627 x0=x0, y0=y0, dwidth=dwidth, dheight=dheight) 

628 

629 threshold = afwDetect.Threshold( 

630 10, afwDetect.Threshold.VALUE, False) 

631 fs2 = afwDetect.FootprintSet(self.im, threshold) 

632 

633 msk = self.im.getMask() 

634 afwDetect.setMaskFromFootprintList( 

635 msk, fs2.getFootprints(), msk.getPlaneBitMask("DETECTED_NEGATIVE")) 

636 

637 self.fs.merge(fs2, grow1, grow2) 

638 self.peaks[-2] += peaks2 

639 

640 if grow1 + grow2 > 2: # grow merged all peaks 

641 def peaksSortKey(p): 

642 return peakFromImage(self.im, p) 

643 self.peaks[0] = sorted(sum(self.peaks, []), key=peaksSortKey) 

644 

645 afwDetect.setMaskFromFootprintList( 

646 msk, self.fs.getFootprints(), msk.getPlaneBitMask("EDGE")) 

647 

648 self.checkPeaks(frame=3) 

649 

650 def testMergeFootprintsEngulf(self): 

651 """Merge two Footprints when growing one Footprint totally replaces the other""" 

652 def callback(): 

653 self.im.set(0) 

654 self.peaks, self.objects = [], [] 

655 

656 for x, y, I in [[6, 4, 20], [6, 5, 10]]: 

657 self.im.getImage()[x, y, afwImage.LOCAL] = I 

658 self.peaks.append([[6, 4]]) 

659 

660 x, y, value = 8, 4, -20 

661 self.im.getImage()[x, y, afwImage.LOCAL] = value 

662 peaks2.append((x, y, value)) 

663 

664 grow1, grow2 = 0, 3 

665 peaks2 = [] 

666 self.doTestPeaks(threshold=10, callback=callback, grow=0) 

667 

668 threshold = afwDetect.Threshold(10, afwDetect.Threshold.VALUE, False) 

669 fs2 = afwDetect.FootprintSet(self.im, threshold) 

670 

671 msk = self.im.getMask() 

672 afwDetect.setMaskFromFootprintList( 

673 msk, fs2.getFootprints(), msk.getPlaneBitMask("DETECTED_NEGATIVE")) 

674 

675 self.fs.merge(fs2, grow1, grow2) 

676 self.peaks[0] += peaks2 

677 

678 def peaksSortKey(p): 

679 return peakFromImage(self.im, p) 

680 self.peaks[0] = sorted(sum(self.peaks, []), key=peaksSortKey) 

681 

682 afwDetect.setMaskFromFootprintList( 

683 msk, self.fs.getFootprints(), msk.getPlaneBitMask("EDGE")) 

684 

685 self.checkPeaks(frame=3) 

686 

687 

688class MemoryTester(lsst.utils.tests.MemoryTestCase): 

689 pass 

690 

691 

692def setup_module(module): 

693 lsst.utils.tests.init() 

694 

695 

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

697 lsst.utils.tests.init() 

698 unittest.main()