Coverage for tests/test_footprint1.py: 9%

Shortcuts on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

808 statements  

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_footprint1.py 

27or 

28 pytest test_footprint1.py 

29""" 

30 

31import math 

32import sys 

33import unittest 

34import os 

35 

36import numpy as np 

37 

38import lsst.utils.tests 

39import lsst.geom 

40import lsst.afw.geom as afwGeom 

41import lsst.afw.geom.ellipses as afwGeomEllipses 

42import lsst.afw.image as afwImage 

43import lsst.afw.math as afwMath 

44import lsst.afw.detection as afwDetect 

45import lsst.afw.detection.utils as afwDetectUtils 

46import lsst.afw.display as afwDisplay 

47 

48try: 

49 type(display) 

50except NameError: 

51 display = False 

52 

53testPath = os.path.abspath(os.path.dirname(__file__)) 

54 

55 

56def toString(*args): 

57 """toString written in python""" 

58 if len(args) == 1: 

59 args = args[0] 

60 

61 y, x0, x1 = args 

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

63 

64 

65class Object: 

66 

67 def __init__(self, val, spans): 

68 self.val = val 

69 self.spans = spans 

70 

71 def __str__(self): 

72 return ", ".join([str(s) for s in self.spans]) 

73 

74 def insert(self, im): 

75 """Insert self into an image""" 

76 for sp in self.spans: 

77 y, x0, x1 = sp 

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

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

80 

81 def __eq__(self, other): 

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

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

84 return False 

85 

86 return True 

87 

88 

89class SpanTestCase(unittest.TestCase): 

90 

91 def testLessThan(self): 

92 span1 = afwGeom.Span(42, 0, 100) 

93 span2 = afwGeom.Span(41, 0, 100) 

94 span3 = afwGeom.Span(43, 0, 100) 

95 span4 = afwGeom.Span(42, -100, 100) 

96 span5 = afwGeom.Span(42, 100, 200) 

97 span6 = afwGeom.Span(42, 0, 10) 

98 span7 = afwGeom.Span(42, 0, 200) 

99 span8 = afwGeom.Span(42, 0, 100) 

100 

101 # Cannot use assertLess and friends here 

102 # because Span only has operator < 

103 def assertOrder(x1, x2): 

104 self.assertTrue(x1 < x2) 

105 self.assertFalse(x2 < x1) 

106 

107 assertOrder(span2, span1) 

108 assertOrder(span1, span3) 

109 assertOrder(span4, span1) 

110 assertOrder(span1, span5) 

111 assertOrder(span6, span1) 

112 assertOrder(span1, span7) 

113 self.assertFalse(span1 < span8) 

114 self.assertFalse(span8 < span1) 

115 

116 

117class ThresholdTestCase(unittest.TestCase): 

118 

119 def testThresholdFactory(self): 

120 """ 

121 Test the creation of a Threshold object 

122 

123 This is a white-box test. 

124 -tests missing parameters 

125 -tests mal-formed parameters 

126 """ 

127 try: 

128 afwDetect.createThreshold(3.4) 

129 except Exception: 

130 self.fail("Failed to build Threshold with proper parameters") 

131 

132 try: 

133 afwDetect.createThreshold(3.4, "foo bar") 

134 except Exception: 

135 pass 

136 else: 

137 self.fail("Threhold parameters not properly validated") 

138 

139 try: 

140 afwDetect.createThreshold(3.4, "variance") 

141 except Exception: 

142 self.fail("Failed to build Threshold with proper parameters") 

143 

144 try: 

145 afwDetect.createThreshold(3.4, "stdev") 

146 except Exception: 

147 self.fail("Failed to build Threshold with proper parameters") 

148 

149 try: 

150 afwDetect.createThreshold(3.4, "value") 

151 except Exception: 

152 self.fail("Failed to build Threshold with proper parameters") 

153 

154 try: 

155 afwDetect.createThreshold(3.4, "value", False) 

156 except Exception: 

157 self.fail("Failed to build Threshold with VALUE, False parameters") 

158 

159 try: 

160 afwDetect.createThreshold(0x4, "bitmask") 

161 except Exception: 

162 self.fail("Failed to build Threshold with BITMASK parameters") 

163 

164 try: 

165 afwDetect.createThreshold(5, "pixel_stdev") 

166 except Exception: 

167 self.fail("Failed to build Threshold with PIXEL_STDEV parameters") 

168 

169 

170class FootprintTestCase(lsst.utils.tests.TestCase): 

171 """A test case for Footprint""" 

172 

173 def setUp(self): 

174 self.foot = afwDetect.Footprint() 

175 

176 def tearDown(self): 

177 del self.foot 

178 

179 def testToString(self): 

180 y, x0, x1 = 10, 100, 101 

181 s = afwGeom.Span(y, x0, x1) 

182 self.assertEqual(s.toString(), toString(y, x0, x1)) 

183 

184 def testGC(self): 

185 """Check that Footprints are automatically garbage collected (when MemoryTestCase runs)""" 

186 

187 afwDetect.Footprint() 

188 

189 def testIntersectMask(self): 

190 bbox = lsst.geom.BoxI(lsst.geom.PointI(0, 0), lsst.geom.ExtentI(10)) 

191 fp = afwDetect.Footprint(afwGeom.SpanSet(bbox)) 

192 maskBBox = lsst.geom.BoxI(bbox) 

193 maskBBox.grow(-2) 

194 mask = afwImage.Mask(maskBBox) 

195 innerBBox = lsst.geom.BoxI(maskBBox) 

196 innerBBox.grow(-2) 

197 subMask = mask.Factory(mask, innerBBox) 

198 subMask.set(1) 

199 

200 # We only want the pixels that are unmasked, and lie in the bounding box 

201 # of the mask, so not the mask (selecting only zero values) and clipped 

202 fp.spans = fp.spans.intersectNot(mask).clippedTo(mask.getBBox()) 

203 fp.removeOrphanPeaks() 

204 fpBBox = fp.getBBox() 

205 self.assertEqual(fpBBox.getMinX(), maskBBox.getMinX()) 

206 self.assertEqual(fpBBox.getMinY(), maskBBox.getMinY()) 

207 self.assertEqual(fpBBox.getMaxX(), maskBBox.getMaxX()) 

208 self.assertEqual(fpBBox.getMaxY(), maskBBox.getMaxY()) 

209 

210 self.assertEqual(fp.getArea(), maskBBox.getArea() - innerBBox.getArea()) 

211 

212 def testTablePersistence(self): 

213 ellipse = afwGeom.Ellipse(afwGeomEllipses.Axes(8, 6, 0.25), 

214 lsst.geom.Point2D(9, 15)) 

215 fp1 = afwDetect.Footprint(afwGeom.SpanSet.fromShape(ellipse)) 

216 fp1.addPeak(6, 7, 2) 

217 fp1.addPeak(8, 9, 3) 

218 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: 

219 fp1.writeFits(tmpFile) 

220 fp2 = afwDetect.Footprint.readFits(tmpFile) 

221 self.assertEqual(fp1.getArea(), fp2.getArea()) 

222 self.assertEqual(list(fp1.getSpans()), list(fp2.getSpans())) 

223 # can't use Peak operator== for comparison because it compares IDs, not positions/values 

224 self.assertEqual(len(fp1.getPeaks()), len(fp2.getPeaks())) 

225 for peak1, peak2 in zip(fp1.getPeaks(), fp2.getPeaks()): 

226 self.assertEqual(peak1.getIx(), peak2.getIx()) 

227 self.assertEqual(peak1.getIy(), peak2.getIy()) 

228 self.assertEqual(peak1.getFx(), peak2.getFx()) 

229 self.assertEqual(peak1.getFy(), peak2.getFy()) 

230 self.assertEqual(peak1.getPeakValue(), peak2.getPeakValue()) 

231 

232 def testBbox(self): 

233 """Add Spans and check bounding box""" 

234 foot = afwDetect.Footprint() 

235 spanLists = [afwGeom.Span(10, 100, 105), afwGeom.Span(11, 99, 104)] 

236 spanSet = afwGeom.SpanSet(spanLists) 

237 foot.spans = spanSet 

238 

239 bbox = foot.getBBox() 

240 self.assertEqual(bbox.getWidth(), 7) 

241 self.assertEqual(bbox.getHeight(), 2) 

242 self.assertEqual(bbox.getMinX(), 99) 

243 self.assertEqual(bbox.getMinY(), 10) 

244 self.assertEqual(bbox.getMaxX(), 105) 

245 self.assertEqual(bbox.getMaxY(), 11) 

246 # clip with a bbox that doesn't overlap at all 

247 bbox2 = lsst.geom.Box2I(lsst.geom.Point2I(5, 90), lsst.geom.Extent2I(1, 2)) 

248 foot.clipTo(bbox2) 

249 self.assertTrue(foot.getBBox().isEmpty()) 

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

251 

252 def testFootprintFromBBox1(self): 

253 """Create a rectangular Footprint""" 

254 x0, y0, w, h = 9, 10, 7, 4 

255 spanSet = afwGeom.SpanSet(lsst.geom.Box2I(lsst.geom.Point2I(x0, y0), 

256 lsst.geom.Extent2I(w, h))) 

257 foot = afwDetect.Footprint(spanSet) 

258 

259 bbox = foot.getBBox() 

260 

261 self.assertEqual(bbox.getWidth(), w) 

262 self.assertEqual(bbox.getHeight(), h) 

263 self.assertEqual(bbox.getMinX(), x0) 

264 self.assertEqual(bbox.getMinY(), y0) 

265 self.assertEqual(bbox.getMaxX(), x0 + w - 1) 

266 self.assertEqual(bbox.getMaxY(), y0 + h - 1) 

267 

268 def testGetBBox(self): 

269 """Check that Footprint.getBBox() returns a copy""" 

270 x0, y0, w, h = 9, 10, 7, 4 

271 spanSet = afwGeom.SpanSet(lsst.geom.Box2I(lsst.geom.Point2I(x0, y0), 

272 lsst.geom.Extent2I(w, h))) 

273 foot = afwDetect.Footprint(spanSet) 

274 bbox = foot.getBBox() 

275 

276 dx, dy = 10, 20 

277 bbox.shift(lsst.geom.Extent2I(dx, dy)) 

278 

279 self.assertEqual(bbox.getMinX(), x0 + dx) 

280 self.assertEqual(foot.getBBox().getMinX(), x0) 

281 

282 def testFootprintFromEllipse(self): 

283 """Create an elliptical Footprint""" 

284 cen = lsst.geom.Point2D(23, 25) 

285 a, b, theta = 25, 15, 30 

286 ellipse = afwGeom.Ellipse( 

287 afwGeomEllipses.Axes(a, b, math.radians(theta)), 

288 cen) 

289 spanSet = afwGeom.SpanSet.fromShape(ellipse) 

290 foot = afwDetect.Footprint(spanSet, 

291 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

292 lsst.geom.Extent2I(50, 60))) 

293 

294 idImage = afwImage.ImageU(lsst.geom.Extent2I( 

295 foot.getRegion().getWidth(), foot.getRegion().getHeight())) 

296 idImage.set(0) 

297 

298 foot.spans.setImage(idImage, 42) 

299 

300 if display: 

301 disp = afwDisplay.Display(frame=2) 

302 disp.mtv(idImage, title=self._testMethodName + " image") 

303 afwDisplay.utils.drawFootprint(foot, frame=2) 

304 shape = foot.getShape() 

305 shape.scale(2) # <r^2> = 1/2 for a disk 

306 disp.dot(shape, *cen, ctype=afwDisplay.RED) 

307 

308 shape = foot.getShape() 

309 shape.scale(2) # <r^2> = 1/2 for a disk 

310 disp.dot(shape, *cen, ctype=afwDisplay.MAGENTA) 

311 

312 axes = afwGeom.ellipses.Axes(foot.getShape()) 

313 axes.scale(2) # <r^2> = 1/2 for a disk 

314 

315 self.assertEqual(foot.getCentroid(), cen) 

316 self.assertLess(abs(a - axes.getA()), 0.15, f"a: {a:g} vs. {axes.getA():g}") 

317 self.assertLess(abs(b - axes.getB()), 0.02, f"b: {b:g} va. {axes.getB():g}") 

318 self.assertLess(abs(theta - math.degrees(axes.getTheta())), 0.2, 

319 f"theta: {theta:g} vs. {math.degrees(axes.getTheta()):g}") 

320 

321 def testCopy(self): 

322 bbox = lsst.geom.BoxI(lsst.geom.PointI(0, 2), lsst.geom.PointI(5, 6)) 

323 

324 fp = afwDetect.Footprint(afwGeom.SpanSet(bbox), bbox) 

325 

326 # test copy construct 

327 fp2 = afwDetect.Footprint(fp) 

328 

329 self.assertEqual(fp2.getBBox(), bbox) 

330 self.assertEqual(fp2.getRegion(), bbox) 

331 self.assertEqual(fp2.getArea(), bbox.getArea()) 

332 

333 y = bbox.getMinY() 

334 for s in fp2.getSpans(): 

335 self.assertEqual(s.getY(), y) 

336 self.assertEqual(s.getX0(), bbox.getMinX()) 

337 self.assertEqual(s.getX1(), bbox.getMaxX()) 

338 y += 1 

339 

340 # test assignment 

341 fp3 = afwDetect.Footprint() 

342 fp3.assign(fp) 

343 self.assertEqual(fp3.getBBox(), bbox) 

344 self.assertEqual(fp3.getRegion(), bbox) 

345 self.assertEqual(fp3.getArea(), bbox.getArea()) 

346 

347 y = bbox.getMinY() 

348 for s in fp3.getSpans(): 

349 self.assertEqual(s.getY(), y) 

350 self.assertEqual(s.getX0(), bbox.getMinX()) 

351 self.assertEqual(s.getX1(), bbox.getMaxX()) 

352 y += 1 

353 

354 def testShrink(self): 

355 width, height = 5, 10 # Size of footprint 

356 x0, y0 = 50, 50 # Position of footprint 

357 imwidth, imheight = 100, 100 # Size of image 

358 

359 spanSet = afwGeom.SpanSet(lsst.geom.Box2I(lsst.geom.Point2I(x0, y0), 

360 lsst.geom.Extent2I(width, height))) 

361 region = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

362 lsst.geom.Extent2I(imwidth, imheight)) 

363 foot = afwDetect.Footprint(spanSet, region) 

364 self.assertEqual(foot.getArea(), width*height) 

365 

366 # Add some peaks to the original footprint and check that those lying outside 

367 # the shrunken footprint are omitted from the returned shrunken footprint. 

368 foot.addPeak(50, 50, 1) # should be omitted in shrunken footprint 

369 foot.addPeak(52, 52, 2) # should be kept in shrunken footprint 

370 foot.addPeak(50, 59, 3) # should be omitted in shrunken footprint 

371 self.assertEqual(len(foot.getPeaks()), 3) # check that all three peaks were added 

372 

373 # Shrinking by one pixel makes each dimension *two* pixels shorter. 

374 shrunk = afwDetect.Footprint().assign(foot) 

375 shrunk.erode(1) 

376 self.assertEqual(3*8, shrunk.getArea()) 

377 

378 # Shrunken footprint should now only contain one peak at (52, 52) 

379 self.assertEqual(len(shrunk.getPeaks()), 1) 

380 peak = shrunk.getPeaks()[0] 

381 self.assertEqual((peak.getIx(), peak.getIy()), (52, 52)) 

382 

383 # Without shifting the centroid 

384 self.assertEqual(shrunk.getCentroid(), foot.getCentroid()) 

385 

386 # Get the same result from a Manhattan shrink 

387 shrunk = afwDetect.Footprint().assign(foot) 

388 shrunk.erode(1, afwGeom.Stencil.MANHATTAN) 

389 self.assertEqual(3*8, shrunk.getArea()) 

390 self.assertEqual(shrunk.getCentroid(), foot.getCentroid()) 

391 

392 # Shrinking by a large amount leaves nothing. 

393 shrunkToNothing = afwDetect.Footprint().assign(foot) 

394 shrunkToNothing.erode(100) 

395 self.assertEqual(shrunkToNothing.getArea(), 0) 

396 

397 def testShrinkIsoVsManhattan(self): 

398 # Demonstrate that isotropic and Manhattan shrinks are different. 

399 radius = 8 

400 imwidth, imheight = 100, 100 

401 x0, y0 = imwidth//2, imheight//2 

402 nshrink = 4 

403 

404 ellipse = afwGeom.Ellipse( 

405 afwGeomEllipses.Axes(1.5*radius, 2*radius, 0), 

406 lsst.geom.Point2D(x0, y0)) 

407 spanSet = afwGeom.SpanSet.fromShape(ellipse) 

408 foot = afwDetect.Footprint( 

409 spanSet, 

410 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

411 lsst.geom.Extent2I(imwidth, imheight))) 

412 footIsotropic = afwDetect.Footprint() 

413 footIsotropic.assign(foot) 

414 

415 foot.erode(nshrink, afwGeom.Stencil.MANHATTAN) 

416 footIsotropic.erode(nshrink) 

417 self.assertNotEqual(foot, footIsotropic) 

418 

419 def _fig8Test(self, x1, y1, x2, y2): 

420 # Construct a "figure of 8" consisting of two circles touching at the 

421 # centre of an image, then demonstrate that it shrinks correctly. 

422 # (Helper method for tests below.) 

423 radius = 3 

424 imwidth, imheight = 100, 100 

425 nshrink = 1 

426 

427 # These are the correct values for footprint sizes given the paramters 

428 # above. 

429 circle_npix = 29 

430 initial_npix = circle_npix*2 - 1 # touch at one pixel 

431 shrunk_npix = 26 

432 

433 box = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

434 lsst.geom.Extent2I(imwidth, imheight)) 

435 

436 e1 = afwGeom.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), 

437 lsst.geom.Point2D(x1, y1)) 

438 spanSet1 = afwGeom.SpanSet.fromShape(e1) 

439 f1 = afwDetect.Footprint(spanSet1, box) 

440 self.assertEqual(f1.getArea(), circle_npix) 

441 

442 e2 = afwGeom.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), 

443 lsst.geom.Point2D(x2, y2)) 

444 spanSet2 = afwGeom.SpanSet.fromShape(e2) 

445 f2 = afwDetect.Footprint(spanSet2, box) 

446 self.assertEqual(f2.getArea(), circle_npix) 

447 

448 initial = afwDetect.mergeFootprints(f1, f2) 

449 initial.setRegion(f2.getRegion()) # merge does not propagate the region 

450 self.assertEqual(initial_npix, initial.getArea()) 

451 

452 shrunk = afwDetect.Footprint().assign(initial) 

453 shrunk.erode(nshrink) 

454 self.assertEqual(shrunk_npix, shrunk.getArea()) 

455 

456 if display: 

457 idImage = afwImage.ImageU(imwidth, imheight) 

458 for i, foot in enumerate([initial, shrunk]): 

459 print(foot.getArea()) 

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

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

462 

463 def testShrinkEightVertical(self): 

464 # Test a "vertical" figure of 8. 

465 radius = 3 

466 imwidth, imheight = 100, 100 

467 self._fig8Test(imwidth//2, imheight//2 - radius, imwidth//2, imheight//2 + radius) 

468 

469 def testShrinkEightHorizontal(self): 

470 # Test a "horizontal" figure of 8. 

471 radius = 3 

472 imwidth, imheight = 100, 100 

473 self._fig8Test(imwidth//2 - radius, imheight//2, imwidth//2 + radius, imheight//2) 

474 

475 def testGrow(self): 

476 """Test growing a footprint""" 

477 x0, y0 = 20, 20 

478 width, height = 20, 30 

479 spanSet = afwGeom.SpanSet(lsst.geom.Box2I(lsst.geom.Point2I(x0, y0), 

480 lsst.geom.Extent2I(width, height))) 

481 foot1 = afwDetect.Footprint(spanSet, 

482 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

483 lsst.geom.Extent2I(100, 100))) 

484 

485 # Add some peaks and check that they get copied into the new grown footprint 

486 foot1.addPeak(20, 20, 1) 

487 foot1.addPeak(30, 35, 2) 

488 foot1.addPeak(25, 45, 3) 

489 self.assertEqual(len(foot1.getPeaks()), 3) 

490 

491 bbox1 = foot1.getBBox() 

492 

493 self.assertEqual(bbox1.getMinX(), x0) 

494 self.assertEqual(bbox1.getMaxX(), x0 + width - 1) 

495 self.assertEqual(bbox1.getWidth(), width) 

496 

497 self.assertEqual(bbox1.getMinY(), y0) 

498 self.assertEqual(bbox1.getMaxY(), y0 + height - 1) 

499 self.assertEqual(bbox1.getHeight(), height) 

500 

501 ngrow = 5 

502 for isotropic in (True, False): 

503 foot2 = afwDetect.Footprint().assign(foot1) 

504 stencil = afwGeom.Stencil.CIRCLE if isotropic else \ 

505 afwGeom.Stencil.MANHATTAN 

506 foot2.dilate(ngrow, stencil) 

507 

508 # Check that the grown footprint is bigger than the original 

509 self.assertGreater(foot2.getArea(), foot1.getArea()) 

510 

511 # Check that peaks got copied into grown footprint 

512 self.assertEqual(len(foot2.getPeaks()), 3) 

513 for peak in foot2.getPeaks(): 

514 self.assertIn((peak.getIx(), peak.getIy()), 

515 [(20, 20), (30, 35), (25, 45)]) 

516 

517 bbox2 = foot2.getBBox() 

518 

519 # check bbox2 

520 self.assertEqual(bbox2.getMinX(), x0 - ngrow) 

521 self.assertEqual(bbox2.getWidth(), width + 2*ngrow) 

522 

523 self.assertEqual(bbox2.getMinY(), y0 - ngrow) 

524 self.assertEqual(bbox2.getHeight(), height + 2*ngrow) 

525 # Check that region was preserved 

526 self.assertEqual(foot1.getRegion(), foot2.getRegion()) 

527 

528 def testFootprintToBBoxList(self): 

529 """Test footprintToBBoxList""" 

530 region = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(12, 10)) 

531 foot = afwDetect.Footprint(afwGeom.SpanSet(), region) 

532 spanList = [afwGeom.Span(*span) for span in ((3, 3, 5), (3, 7, 7), 

533 (4, 2, 3), (4, 5, 7), 

534 (5, 2, 3), (5, 5, 8), 

535 (6, 3, 5))] 

536 foot.spans = afwGeom.SpanSet(spanList) 

537 

538 idImage = afwImage.ImageU(region.getDimensions()) 

539 idImage.set(0) 

540 

541 foot.spans.setImage(idImage, 1) 

542 if display: 

543 disp = afwDisplay.Display(frame=1) 

544 disp.mtv(idImage, title=self._testMethodName + " image") 

545 

546 idImageFromBBox = idImage.Factory(idImage, True) 

547 idImageFromBBox.set(0) 

548 bboxes = afwDetect.footprintToBBoxList(foot) 

549 for bbox in bboxes: 

550 x0, y0, x1, y1 = bbox.getMinX(), bbox.getMinY(), \ 

551 bbox.getMaxX(), bbox.getMaxY() 

552 

553 for y in range(y0, y1 + 1): 

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

555 idImageFromBBox[x, y, afwImage.LOCAL] = 1 

556 

557 if display: 

558 x0 -= 0.5 

559 y0 -= 0.5 

560 x1 += 0.5 

561 y1 += 0.5 

562 

563 disp.line([(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)], ctype=afwDisplay.RED) 

564 

565 idImageFromBBox -= idImage # should be blank 

566 stats = afwMath.makeStatistics(idImageFromBBox, afwMath.MAX) 

567 

568 self.assertEqual(stats.getValue(), 0) 

569 

570 def testWriteDefect(self): 

571 """Write a Footprint as a set of Defects""" 

572 region = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(12, 10)) 

573 spanSet = afwGeom.SpanSet([afwGeom.Span(*span) for span in [(3, 3, 5), 

574 (3, 7, 7), 

575 (4, 2, 3), 

576 (4, 5, 7), 

577 (5, 2, 3), 

578 (5, 5, 8), 

579 (6, 3, 5)]]) 

580 foot = afwDetect.Footprint(spanSet, region) 

581 

582 openedFile = False 

583 if True: 

584 fd = open("/dev/null", "w") 

585 openedFile = True 

586 else: 

587 fd = sys.stdout 

588 

589 afwDetectUtils.writeFootprintAsDefects(fd, foot) 

590 if openedFile: 

591 fd.close() 

592 

593 def testSetFromFootprint(self): 

594 """Test setting mask/image pixels from a Footprint list""" 

595 mi = afwImage.MaskedImageF(lsst.geom.Extent2I(12, 8)) 

596 im = mi.getImage() 

597 # 

598 # Objects that we should detect 

599 # 

600 self.objects = [] 

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

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

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

604 

605 im.set(0) # clear image 

606 for obj in self.objects: 

607 obj.insert(im) 

608 

609 ds = afwDetect.FootprintSet(mi, afwDetect.Threshold(15)) 

610 

611 objects = ds.getFootprints() 

612 afwDetect.setMaskFromFootprintList(mi.getMask(), objects, 0x1) 

613 

614 self.assertEqual(mi.getMask()[4, 2, afwImage.LOCAL], 0x0) 

615 self.assertEqual(mi.getMask()[3, 6, afwImage.LOCAL], 0x1) 

616 

617 self.assertEqual(mi.getImage()[3, 6, afwImage.LOCAL], 20) 

618 for ft in objects: 

619 ft.spans.setImage(mi.getImage(), 5.0) 

620 self.assertEqual(mi.getImage()[4, 2, afwImage.LOCAL], 10) 

621 self.assertEqual(mi.getImage()[3, 6, afwImage.LOCAL], 5) 

622 

623 if display: 

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

625 # 

626 # Check Footprint.contains() while we are about it 

627 # 

628 self.assertTrue(objects[0].contains(lsst.geom.Point2I(7, 5))) 

629 self.assertFalse(objects[0].contains(lsst.geom.Point2I(10, 6))) 

630 self.assertFalse(objects[0].contains(lsst.geom.Point2I(7, 6))) 

631 self.assertFalse(objects[0].contains(lsst.geom.Point2I(4, 2))) 

632 

633 self.assertTrue(objects[1].contains(lsst.geom.Point2I(3, 6))) 

634 

635 # Verify the FootprintSet footprint list setter can accept inputs from 

636 # the footprint list getter 

637 # Create a copy of the ds' FootprintList 

638 dsFpList = ds.getFootprints() 

639 footprintListCopy = [afwDetect.Footprint().assign(f) for f in dsFpList] 

640 # Use the FootprintList setter with the output from the getter 

641 ds.setFootprints(ds.getFootprints()[:-1]) 

642 dsFpListNew = ds.getFootprints() 

643 self.assertTrue(len(dsFpListNew) == len(footprintListCopy)-1) 

644 for new, old in zip(dsFpListNew, footprintListCopy[:-1]): 

645 self.assertEqual(new, old) 

646 

647 def testMakeFootprintSetXY0(self): 

648 """Test setting mask/image pixels from a Footprint list""" 

649 mi = afwImage.MaskedImageF(lsst.geom.Extent2I(12, 8)) 

650 im = mi.getImage() 

651 im.set(100) 

652 

653 mi.setXY0(lsst.geom.PointI(2, 2)) 

654 afwDetect.FootprintSet(mi, afwDetect.Threshold(1), "DETECTED") 

655 

656 bitmask = mi.getMask().getPlaneBitMask("DETECTED") 

657 for y in range(im.getHeight()): 

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

659 self.assertEqual(mi.getMask()[x, y, afwImage.LOCAL], bitmask) 

660 

661 def testTransform(self): 

662 dims = lsst.geom.Extent2I(512, 512) 

663 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), dims) 

664 radius = 5 

665 offset = lsst.geom.Extent2D(123, 456) 

666 crval = lsst.geom.SpherePoint(0, 0, lsst.geom.degrees) 

667 crpix = lsst.geom.Point2D(0, 0) 

668 cdMatrix = np.array([1.0e-5, 0.0, 0.0, 1.0e-5]) 

669 cdMatrix.shape = (2, 2) 

670 source = afwGeom.makeSkyWcs(crval=crval, crpix=crpix, cdMatrix=cdMatrix) 

671 target = afwGeom.makeSkyWcs(crval=crval, crpix=crpix + offset, cdMatrix=cdMatrix) 

672 sourceSpanSet = afwGeom.SpanSet.fromShape(radius, 

673 afwGeom.Stencil.CIRCLE) 

674 sourceSpanSet = sourceSpanSet.shiftedBy(12, 34) 

675 fpSource = afwDetect.Footprint(sourceSpanSet, bbox) 

676 

677 fpTarget = fpSource.transform(source, target, bbox) 

678 

679 self.assertEqual(len(fpSource.getSpans()), len(fpTarget.getSpans())) 

680 self.assertEqual(fpSource.getArea(), fpTarget.getArea()) 

681 imSource = afwImage.ImageU(dims) 

682 fpSource.spans.setImage(imSource, 1) 

683 

684 imTarget = afwImage.ImageU(dims) 

685 fpTarget.spans.setImage(imTarget, 1) 

686 

687 subSource = imSource.Factory(imSource, fpSource.getBBox()) 

688 subTarget = imTarget.Factory(imTarget, fpTarget.getBBox()) 

689 self.assertTrue(np.all(subSource.getArray() == subTarget.getArray())) 

690 

691 # make a bbox smaller than the target footprint 

692 bbox2 = lsst.geom.Box2I(fpTarget.getBBox()) 

693 bbox2.grow(-1) 

694 fpTarget2 = fpSource.transform(source, target, bbox2) # this one clips 

695 fpTarget3 = fpSource.transform(source, target, bbox2, False) # this one doesn't 

696 self.assertTrue(bbox2.contains(fpTarget2.getBBox())) 

697 self.assertFalse(bbox2.contains(fpTarget3.getBBox())) 

698 self.assertNotEqual(fpTarget.getArea(), fpTarget2.getArea()) 

699 self.assertEqual(fpTarget.getArea(), fpTarget3.getArea()) 

700 

701 # Test that peakCatalogs get Transformed correctly 

702 truthList = [(x, y, 10) for x, y in zip(range(-2, 2), range(-1, 3))] 

703 for value in truthList: 

704 fpSource.addPeak(*value) 

705 scaleFactor = 2 

706 linTrans = lsst.geom.LinearTransform(np.array([[scaleFactor, 0], 

707 [0, scaleFactor]], 

708 dtype=float)) 

709 linTransFootprint = fpSource.transform(linTrans, fpSource.getBBox(), 

710 False) 

711 for peak, truth in zip(linTransFootprint.peaks, truthList): 

712 # Multiplied by two because that is the linear transform scaling 

713 # factor 

714 self.assertEqual(peak.getIx(), truth[0]*scaleFactor) 

715 self.assertEqual(peak.getIy(), truth[1]*scaleFactor) 

716 

717 def testCopyWithinFootprintImage(self): 

718 W, H = 10, 10 

719 dims = lsst.geom.Extent2I(W, H) 

720 source = afwImage.ImageF(dims) 

721 dest = afwImage.ImageF(dims) 

722 sa = source.getArray() 

723 for i in range(H): 

724 for j in range(W): 

725 sa[i, j] = 100*i + j 

726 

727 footSpans = [s for s in self.foot.spans] 

728 footSpans.append(afwGeom.Span(4, 3, 6)) 

729 footSpans.append(afwGeom.Span(5, 2, 4)) 

730 self.foot.spans = afwGeom.SpanSet(footSpans) 

731 

732 self.foot.spans.copyImage(source, dest) 

733 

734 da = dest.getArray() 

735 self.assertEqual(da[4, 2], 0) 

736 self.assertEqual(da[4, 3], 403) 

737 self.assertEqual(da[4, 4], 404) 

738 self.assertEqual(da[4, 5], 405) 

739 self.assertEqual(da[4, 6], 406) 

740 self.assertEqual(da[4, 7], 0) 

741 self.assertEqual(da[5, 1], 0) 

742 self.assertEqual(da[5, 2], 502) 

743 self.assertEqual(da[5, 3], 503) 

744 self.assertEqual(da[5, 4], 504) 

745 self.assertEqual(da[5, 5], 0) 

746 self.assertTrue(np.all(da[:4, :] == 0)) 

747 self.assertTrue(np.all(da[6:, :] == 0)) 

748 

749 def testCopyWithinFootprintOutside(self): 

750 """Copy a footprint that is larger than the image""" 

751 target = afwImage.ImageF(100, 100) 

752 target.set(0) 

753 subTarget = afwImage.ImageF(target, lsst.geom.Box2I(lsst.geom.Point2I(40, 40), 

754 lsst.geom.Extent2I(20, 20))) 

755 source = afwImage.ImageF(10, 30) 

756 source.setXY0(45, 45) 

757 source.set(1.0) 

758 

759 foot = afwDetect.Footprint() 

760 spanList = [afwGeom.Span(*s) for s in ( 

761 (50, 50, 60), # Oversized on the source image, right; only some pixels overlap 

762 (60, 0, 100), # Oversized on the source, left and right; and on sub-target image, top 

763 (99, 0, 1000), # Oversized on the source image, top, left and right; aiming for segfault 

764 )] 

765 foot.spans = afwGeom.SpanSet(spanList) 

766 

767 foot.spans.clippedTo(subTarget.getBBox()).clippedTo(source.getBBox()).\ 

768 copyImage(source, subTarget) 

769 

770 expected = np.zeros((100, 100)) 

771 expected[50, 50:55] = 1.0 

772 

773 self.assertTrue(np.all(target.getArray() == expected)) 

774 

775 def testCopyWithinFootprintMaskedImage(self): 

776 W, H = 10, 10 

777 dims = lsst.geom.Extent2I(W, H) 

778 source = afwImage.MaskedImageF(dims) 

779 dest = afwImage.MaskedImageF(dims) 

780 sa = source.getImage().getArray() 

781 sv = source.getVariance().getArray() 

782 sm = source.getMask().getArray() 

783 for i in range(H): 

784 for j in range(W): 

785 sa[i, j] = 100*i + j 

786 sv[i, j] = 100*j + i 

787 sm[i, j] = 1 

788 

789 footSpans = [s for s in self.foot.spans] 

790 footSpans.append(afwGeom.Span(4, 3, 6)) 

791 footSpans.append(afwGeom.Span(5, 2, 4)) 

792 self.foot.spans = afwGeom.SpanSet(footSpans) 

793 

794 self.foot.spans.copyMaskedImage(source, dest) 

795 

796 da = dest.getImage().getArray() 

797 dv = dest.getVariance().getArray() 

798 dm = dest.getMask().getArray() 

799 

800 self.assertEqual(da[4, 2], 0) 

801 self.assertEqual(da[4, 3], 403) 

802 self.assertEqual(da[4, 4], 404) 

803 self.assertEqual(da[4, 5], 405) 

804 self.assertEqual(da[4, 6], 406) 

805 self.assertEqual(da[4, 7], 0) 

806 self.assertEqual(da[5, 1], 0) 

807 self.assertEqual(da[5, 2], 502) 

808 self.assertEqual(da[5, 3], 503) 

809 self.assertEqual(da[5, 4], 504) 

810 self.assertEqual(da[5, 5], 0) 

811 self.assertTrue(np.all(da[:4, :] == 0)) 

812 self.assertTrue(np.all(da[6:, :] == 0)) 

813 

814 self.assertEqual(dv[4, 2], 0) 

815 self.assertEqual(dv[4, 3], 304) 

816 self.assertEqual(dv[4, 4], 404) 

817 self.assertEqual(dv[4, 5], 504) 

818 self.assertEqual(dv[4, 6], 604) 

819 self.assertEqual(dv[4, 7], 0) 

820 self.assertEqual(dv[5, 1], 0) 

821 self.assertEqual(dv[5, 2], 205) 

822 self.assertEqual(dv[5, 3], 305) 

823 self.assertEqual(dv[5, 4], 405) 

824 self.assertEqual(dv[5, 5], 0) 

825 self.assertTrue(np.all(dv[:4, :] == 0)) 

826 self.assertTrue(np.all(dv[6:, :] == 0)) 

827 

828 self.assertTrue(np.all(dm[4, 3:7] == 1)) 

829 self.assertTrue(np.all(dm[5, 2:5] == 1)) 

830 self.assertTrue(np.all(dm[:4, :] == 0)) 

831 self.assertTrue(np.all(dm[6:, :] == 0)) 

832 self.assertTrue(np.all(dm[4, :3] == 0)) 

833 self.assertTrue(np.all(dm[4, 7:] == 0)) 

834 

835 def testMergeFootprints(self): 

836 f1 = self.foot 

837 f2 = afwDetect.Footprint() 

838 

839 spanList1 = [(10, 10, 20), 

840 (10, 30, 40), 

841 (10, 50, 60), 

842 (11, 30, 50), 

843 (12, 30, 50), 

844 (13, 10, 20), 

845 (13, 30, 40), 

846 (13, 50, 60), 

847 (15, 10, 20), 

848 (15, 31, 40), 

849 (15, 51, 60)] 

850 spanSet1 = afwGeom.SpanSet([afwGeom.Span(*span) for span in spanList1]) 

851 f1.spans = spanSet1 

852 

853 spanList2 = [(8, 10, 20), 

854 (9, 20, 30), 

855 (10, 0, 9), 

856 (10, 35, 65), 

857 (10, 70, 80), 

858 (13, 49, 54), 

859 (14, 10, 30), 

860 (15, 21, 30), 

861 (15, 41, 50), 

862 (15, 61, 70)] 

863 spanSet2 = afwGeom.SpanSet([afwGeom.Span(*span) for span in spanList2]) 

864 f2.spans = spanSet2 

865 

866 fA = afwDetect.mergeFootprints(f1, f2) 

867 fB = afwDetect.mergeFootprints(f2, f1) 

868 

869 ims = [] 

870 for i, f in enumerate([f1, f2, fA, fB]): 

871 im1 = afwImage.ImageU(100, 100) 

872 im1.set(0) 

873 imbb = im1.getBBox() 

874 f.setRegion(imbb) 

875 f.spans.setImage(im1, 1) 

876 ims.append(im1) 

877 

878 for i, merged in enumerate([ims[2], ims[3]]): 

879 m = merged.getArray() 

880 a1 = ims[0].getArray() 

881 a2 = ims[1].getArray() 

882 # Slightly looser tests to start... 

883 # Every pixel in f1 is in f[AB] 

884 self.assertTrue(np.all(m.flat[np.flatnonzero(a1)] == 1)) 

885 # Every pixel in f2 is in f[AB] 

886 self.assertTrue(np.all(m.flat[np.flatnonzero(a2)] == 1)) 

887 # merged == a1 | a2. 

888 self.assertTrue(np.all(m == np.maximum(a1, a2))) 

889 

890 def testPeakSort(self): 

891 spanSet = afwGeom.SpanSet(lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

892 lsst.geom.Point2I(10, 10))) 

893 footprint = afwDetect.Footprint(spanSet) 

894 footprint.addPeak(4, 5, 1) 

895 footprint.addPeak(3, 2, 5) 

896 footprint.addPeak(7, 8, -2) 

897 footprint.addPeak(5, 7, 4) 

898 footprint.sortPeaks() 

899 self.assertEqual([peak.getIx() for peak in footprint.getPeaks()], 

900 [3, 5, 4, 7]) 

901 

902 def testInclude(self): 

903 """Test that we can expand a Footprint to include the union of itself and all others provided.""" 

904 region = lsst.geom.Box2I(lsst.geom.Point2I(-6, -6), lsst.geom.Point2I(6, 6)) 

905 parentSpanSet = afwGeom.SpanSet(lsst.geom.Box2I(lsst.geom.Point2I(-2, -2), 

906 lsst.geom.Point2I(2, 2))) 

907 parent = afwDetect.Footprint(parentSpanSet, region) 

908 parent.addPeak(0, 0, float("NaN")) 

909 child1SpanSet = afwGeom.SpanSet(lsst.geom.Box2I(lsst.geom.Point2I(-3, 0), 

910 lsst.geom.Point2I(0, 3))) 

911 child1 = afwDetect.Footprint(child1SpanSet, region) 

912 child1.addPeak(-1, 1, float("NaN")) 

913 child2SpanSet = afwGeom.SpanSet(lsst.geom.Box2I(lsst.geom.Point2I(-4, -3), 

914 lsst.geom.Point2I(-1, 0))) 

915 child2 = afwDetect.Footprint(child2SpanSet, region) 

916 child3SpanSet = afwGeom.SpanSet(lsst.geom.Box2I(lsst.geom.Point2I(4, -1), 

917 lsst.geom.Point2I(6, 1))) 

918 child3 = afwDetect.Footprint(child3SpanSet) 

919 merge123 = afwDetect.Footprint(parent) 

920 merge123.spans = merge123.spans.union(child1.spans).union(child2.spans).union(child3.spans) 

921 self.assertTrue(merge123.getBBox().contains(parent.getBBox())) 

922 self.assertTrue(merge123.getBBox().contains(child1.getBBox())) 

923 self.assertTrue(merge123.getBBox().contains(child2.getBBox())) 

924 self.assertTrue(merge123.getBBox().contains(child3.getBBox())) 

925 mask123a = afwImage.Mask(region) 

926 mask123b = afwImage.Mask(region) 

927 parent.spans.setMask(mask123a, 1) 

928 child1.spans.setMask(mask123a, 1) 

929 child2.spans.setMask(mask123a, 1) 

930 child3.spans.setMask(mask123a, 1) 

931 merge123.spans.setMask(mask123b, 1) 

932 self.assertEqual(mask123a.getArray().sum(), merge123.getArea()) 

933 self.assertFloatsAlmostEqual(mask123a.getArray(), mask123b.getArray(), 

934 rtol=0, atol=0) 

935 

936 # Test that ignoreSelf=True works for include 

937 childOnly = afwDetect.Footprint() 

938 childOnly.spans = childOnly.spans.union(child1.spans).union(child2.spans).union(child3.spans) 

939 merge123 = afwDetect.Footprint(parent) 

940 merge123.spans = child1.spans.union(child2.spans).union(child3.spans) 

941 maskChildren = afwImage.Mask(region) 

942 mask123 = afwImage.Mask(region) 

943 childOnly.spans.setMask(maskChildren, 1) 

944 merge123.spans.setMask(mask123, 1) 

945 self.assertTrue(np.all(maskChildren.getArray() == mask123.getArray())) 

946 

947 def checkEdge(self, footprint): 

948 """Check that Footprint::findEdgePixels() works""" 

949 bbox = footprint.getBBox() 

950 bbox.grow(3) 

951 

952 def makeImage(area): 

953 """Make an ImageF with 1 in the footprint, and 0 elsewhere""" 

954 ones = afwImage.ImageI(bbox) 

955 ones.set(1) 

956 image = afwImage.ImageI(bbox) 

957 image.set(0) 

958 if isinstance(area, afwDetect.Footprint): 

959 area.spans.copyImage(ones, image) 

960 if isinstance(area, afwGeom.SpanSet): 

961 area.copyImage(ones, image) 

962 return image 

963 

964 edges = self.foot.spans.findEdgePixels() 

965 edgeImage = makeImage(edges) 

966 

967 # Find edges with an edge-detection kernel 

968 image = makeImage(self.foot) 

969 kernel = afwImage.ImageD(3, 3) 

970 kernel[1, 1, afwImage.LOCAL] = 4 

971 for x, y in [(1, 2), (0, 1), (1, 0), (2, 1)]: 

972 kernel[x, y, afwImage.LOCAL] = -1 

973 kernel.setXY0(1, 1) 

974 result = afwImage.ImageI(bbox) 

975 result.set(0) 

976 afwMath.convolve(result, image, afwMath.FixedKernel(kernel), 

977 afwMath.ConvolutionControl(False)) 

978 result.getArray().__imul__(image.getArray()) 

979 trueEdges = np.where(result.getArray() > 0, 1, 0) 

980 

981 self.assertTrue(np.all(trueEdges == edgeImage.getArray())) 

982 

983 def testEdge(self): 

984 """Test for Footprint::findEdgePixels()""" 

985 foot = afwDetect.Footprint() 

986 spanList = [afwGeom.Span(*span) for span in ((3, 3, 9), 

987 (4, 2, 4), 

988 (4, 6, 7), 

989 (4, 9, 11), 

990 (5, 3, 9), 

991 (6, 6, 7))] 

992 foot.spans = afwGeom.SpanSet(spanList) 

993 self.checkEdge(foot) 

994 

995 # This footprint came from a very large Footprint in a deep HSC coadd patch 

996 self.checkEdge(afwDetect.Footprint.readFits( 

997 os.path.join(testPath, "testFootprintEdge.fits"))) 

998 

999 

1000class FootprintSetTestCase(unittest.TestCase): 

1001 """A test case for FootprintSet""" 

1002 

1003 def setUp(self): 

1004 self.ms = afwImage.MaskedImageF(lsst.geom.Extent2I(12, 8)) 

1005 im = self.ms.getImage() 

1006 # 

1007 # Objects that we should detect 

1008 # 

1009 self.objects = [] 

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

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

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

1013 

1014 self.ms.set((0, 0x0, 4.0)) # clear image; set variance 

1015 for obj in self.objects: 

1016 obj.insert(im) 

1017 

1018 def tearDown(self): 

1019 del self.ms 

1020 

1021 def testGC(self): 

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

1023 afwDetect.FootprintSet(afwImage.MaskedImageF(lsst.geom.Extent2I(10, 20)), 

1024 afwDetect.Threshold(10)) 

1025 

1026 def testFootprints(self): 

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

1028 ds = afwDetect.FootprintSet(self.ms, afwDetect.Threshold(10)) 

1029 

1030 objects = ds.getFootprints() 

1031 

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

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

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

1035 

1036 def testFootprints2(self): 

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

1038 ds = afwDetect.FootprintSet(self.ms, afwDetect.Threshold(10)) 

1039 

1040 objects = ds.getFootprints() 

1041 

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

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

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

1045 

1046 def testFootprints3(self): 

1047 """Check that we found the correct number of objects using FootprintSet and PIXEL_STDEV""" 

1048 threshold = 4.5 # in units of sigma 

1049 

1050 self.ms[2, 4, afwImage.LOCAL] = (10, 0x0, 36) # not detected (high variance) 

1051 

1052 y, x = self.objects[2].spans[0][0:2] 

1053 self.ms[x, y, afwImage.LOCAL] = (threshold, 0x0, 1.0) 

1054 

1055 ds = afwDetect.FootprintSet(self.ms, 

1056 afwDetect.createThreshold(threshold, "pixel_stdev"), "OBJECT") 

1057 

1058 objects = ds.getFootprints() 

1059 

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

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

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

1063 

1064 def testFootprintsMasks(self): 

1065 """Check that detectionSets have the proper mask bits set""" 

1066 ds = afwDetect.FootprintSet(self.ms, afwDetect.Threshold(10), "OBJECT") 

1067 objects = ds.getFootprints() 

1068 

1069 if display: 

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

1071 

1072 mask = self.ms.getMask() 

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

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

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

1076 self.assertEqual(mask[x, sp.getY(), afwImage.LOCAL], 

1077 mask.getPlaneBitMask("OBJECT")) 

1078 

1079 def testFootprintsImageId(self): 

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

1081 ds = afwDetect.FootprintSet(self.ms, afwDetect.Threshold(10)) 

1082 objects = ds.getFootprints() 

1083 

1084 idImage = afwImage.ImageU(self.ms.getDimensions()) 

1085 idImage.set(0) 

1086 

1087 for i, foot in enumerate(objects): 

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

1089 

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

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

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

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

1094 

1095 def testFootprintSetImageId(self): 

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

1097 ds = afwDetect.FootprintSet(self.ms, afwDetect.Threshold(10)) 

1098 objects = ds.getFootprints() 

1099 

1100 idImage = ds.insertIntoImage() 

1101 if display: 

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

1103 

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

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

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

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

1108 

1109 def testFootprintsImage(self): 

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

1111 ds = afwDetect.FootprintSet(self.ms.getImage(), afwDetect.Threshold(10)) 

1112 

1113 objects = ds.getFootprints() 

1114 

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

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

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

1118 

1119 def testGrow2(self): 

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

1121 ds = afwDetect.FootprintSet(self.ms, afwDetect.Threshold(10), "OBJECT") 

1122 

1123 idImage = afwImage.ImageU(self.ms.getDimensions()) 

1124 idImage.set(0) 

1125 

1126 i = 1 

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

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

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

1130 i += 1 

1131 

1132 if display: 

1133 afwDisplay.Display(frame=0).mtv(self.ms, title=self._testMethodName + " self.ms") 

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

1135 

1136 def testFootprintPeaks(self): 

1137 """Test that we can extract the peaks from a Footprint""" 

1138 fs = afwDetect.FootprintSet(self.ms, afwDetect.Threshold(10), "OBJECT") 

1139 

1140 foot = fs.getFootprints()[0] 

1141 

1142 self.assertEqual(len(foot.getPeaks()), 5) 

1143 

1144 

1145class MaskFootprintSetTestCase(unittest.TestCase): 

1146 """A test case for generating FootprintSet from Masks""" 

1147 

1148 def setUp(self): 

1149 self.mim = afwImage.MaskedImageF(lsst.geom.ExtentI(12, 8)) 

1150 # 

1151 # Objects that we should detect 

1152 # 

1153 self.objects = [] 

1154 self.objects += [Object(0x2, [(1, 4, 4), (2, 3, 5), (3, 4, 4)])] 

1155 self.objects += [Object(0x41, [(5, 7, 8), (6, 8, 8)])] 

1156 self.objects += [Object(0x42, [(5, 10, 10)])] 

1157 self.objects += [Object(0x82, [(6, 3, 3)])] 

1158 

1159 self.mim.set((0, 0, 0)) # clear image 

1160 for obj in self.objects: 

1161 obj.insert(self.mim.getImage()) 

1162 obj.insert(self.mim.getMask()) 

1163 

1164 if display: 

1165 afwDisplay.Display(frame=0).mtv(self.mim, title=self._testMethodName + " self.mim") 

1166 

1167 def tearDown(self): 

1168 del self.mim 

1169 

1170 def testFootprints(self): 

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

1172 level = 0x2 

1173 ds = afwDetect.FootprintSet(self.mim.getMask(), 

1174 afwDetect.createThreshold(level, "bitmask")) 

1175 

1176 objects = ds.getFootprints() 

1177 

1178 if 0 and display: 

1179 afwDisplay.Display(frame=0).mtv(self.mim, title=self._testMethodName + " self.mim") 

1180 

1181 self.assertEqual(len(objects), 

1182 len([o for o in self.objects if (o.val & level)])) 

1183 

1184 i = 0 

1185 for o in self.objects: 

1186 if o.val & level: 

1187 self.assertEqual(o, objects[i]) 

1188 i += 1 

1189 

1190 

1191class NaNFootprintSetTestCase(unittest.TestCase): 

1192 """A test case for FootprintSet when the image contains NaNs""" 

1193 

1194 def setUp(self): 

1195 self.ms = afwImage.MaskedImageF(lsst.geom.Extent2I(12, 8)) 

1196 im = self.ms.getImage() 

1197 # 

1198 # Objects that we should detect 

1199 # 

1200 self.objects = [] 

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

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

1203 self.objects += [Object(20, [(5, 10, 10)])] 

1204 self.objects += [Object(30, [(6, 3, 3)])] 

1205 

1206 im.set(0) # clear image 

1207 for obj in self.objects: 

1208 obj.insert(im) 

1209 

1210 self.NaN = float("NaN") 

1211 im[3, 7, afwImage.LOCAL] = self.NaN 

1212 im[0, 0, afwImage.LOCAL] = self.NaN 

1213 im[8, 2, afwImage.LOCAL] = self.NaN 

1214 

1215 # connects the two objects with value==20 together if NaN is detected 

1216 im[9, 6, afwImage.LOCAL] = self.NaN 

1217 

1218 def tearDown(self): 

1219 del self.ms 

1220 

1221 def testFootprints(self): 

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

1223 ds = afwDetect.FootprintSet(self.ms, afwDetect.Threshold(10), "DETECTED") 

1224 

1225 objects = ds.getFootprints() 

1226 

1227 if display: 

1228 afwDisplay.Display(frame=0).mtv(self.ms, title=self._testMethodName + " self.ms") 

1229 

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

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

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

1233 

1234 

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

1236 pass 

1237 

1238 

1239def setup_module(module): 

1240 lsst.utils.tests.init() 

1241 

1242 

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

1244 lsst.utils.tests.init() 

1245 unittest.main()