Coverage for tests/test_heavyFootprint.py: 16%

191 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-20 02:20 -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 HeavyFootprints 

24 

25Run with: 

26 python test_heavyFootprint.py 

27or 

28 pytest test_heavyFootprint.py 

29""" 

30 

31import os 

32import unittest 

33 

34import numpy as np 

35 

36import lsst.utils.tests 

37import lsst.geom 

38import lsst.afw.image as afwImage 

39import lsst.afw.detection as afwDetect 

40import lsst.afw.geom as afwGeom 

41import lsst.afw.display as afwDisplay 

42from lsst.log import Log 

43 

44Log.getLogger("lsst.afw.image.Mask").setLevel(Log.INFO) 

45afwDisplay.setDefaultMaskTransparency(75) 

46 

47try: 

48 type(display) 

49except NameError: 

50 display = False 

51 

52 

53class HeavyFootprintTestCase(lsst.utils.tests.TestCase): 

54 """A test case for HeavyFootprint""" 

55 

56 def setUp(self): 

57 self.mi = afwImage.MaskedImageF(20, 10) 

58 self.objectPixelVal = (10, 0x1, 100) 

59 

60 spanList = [] 

61 for y, x0, x1 in [(2, 10, 13), 

62 (3, 11, 14)]: 

63 spanList.append(afwGeom.Span(y, x0, x1)) 

64 

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

66 self.mi[x, y, afwImage.LOCAL] = self.objectPixelVal 

67 self.foot = afwDetect.Footprint(afwGeom.SpanSet(spanList)) 

68 

69 def tearDown(self): 

70 del self.foot 

71 del self.mi 

72 

73 def testCreate(self): 

74 """Check that we can create a HeavyFootprint""" 

75 

76 imi = self.mi.Factory(self.mi, True) # copy of input image 

77 

78 hfoot = afwDetect.makeHeavyFootprint(self.foot, self.mi) 

79 # check we can call a base-class method 

80 self.assertTrue(hfoot.isHeavy()) 

81 # 

82 # Check we didn't modify the input image 

83 # 

84 self.assertFloatsEqual( 

85 self.mi.getImage().getArray(), imi.getImage().getArray()) 

86 

87 omi = self.mi.Factory(self.mi.getDimensions()) 

88 omi.set((1, 0x4, 0.1)) 

89 hfoot.insert(omi) 

90 

91 if display: 

92 afwDisplay.Display(frame=0).mtv(imi, title="testCreate input") 

93 afwDisplay.Display(frame=1).mtv(omi, title="testCreate output") 

94 

95 for s in self.foot.getSpans(): 

96 y = s.getY() 

97 for x in range(s.getX0(), s.getX1() + 1): 

98 self.assertEqual(imi[x, y, afwImage.LOCAL], omi[x, y, afwImage.LOCAL]) 

99 

100 # Check that we can call getImageArray(), etc 

101 arr = hfoot.getImageArray() 

102 # Check that it's iterable 

103 for x in arr: 

104 pass 

105 arr = hfoot.getMaskArray() 

106 for x in arr: 

107 pass 

108 arr = hfoot.getVarianceArray() 

109 # Check that it's iterable 

110 for x in arr: 

111 pass 

112 

113 def testSetFootprint(self): 

114 """Check that we can create a HeavyFootprint and set the pixels under it""" 

115 

116 ctrl = afwDetect.HeavyFootprintCtrl() 

117 # clear the pixels in the Footprint 

118 ctrl.setModifySource(afwDetect.HeavyFootprintCtrl.SET) 

119 ctrl.setMaskVal(self.objectPixelVal[1]) 

120 

121 afwDetect.makeHeavyFootprint(self.foot, self.mi, ctrl) 

122 # 

123 # Check that we cleared all the pixels 

124 # 

125 self.assertEqual(np.min(self.mi.getImage().getArray()), 0.0) 

126 self.assertEqual(np.max(self.mi.getImage().getArray()), 0.0) 

127 self.assertEqual(np.min(self.mi.getMask().getArray()), 0.0) 

128 self.assertEqual(np.max(self.mi.getMask().getArray()), 0.0) 

129 self.assertEqual(np.min(self.mi.getVariance().getArray()), 0.0) 

130 self.assertEqual(np.max(self.mi.getVariance().getArray()), 0.0) 

131 

132 def testMakeHeavy(self): 

133 """Test that we can make a FootprintSet heavy""" 

134 fs = afwDetect.FootprintSet(self.mi, afwDetect.Threshold(1)) 

135 

136 ctrl = afwDetect.HeavyFootprintCtrl(afwDetect.HeavyFootprintCtrl.NONE) 

137 fs.makeHeavy(self.mi, ctrl) 

138 

139 omi = self.mi.Factory(self.mi.getDimensions()) 

140 

141 for foot in fs.getFootprints(): 

142 foot.insert(omi) 

143 

144 for foot in fs.getFootprints(): 

145 foot.insert(omi) 

146 

147 if display: 

148 afwDisplay.Display(frame=0).mtv(self.mi, title="testMakeHeavy input") 

149 afwDisplay.Display(frame=1).mtv(omi, title="testMakeHeavy output") 

150 

151 self.assertFloatsEqual( 

152 self.mi.getImage().getArray(), omi.getImage().getArray()) 

153 

154 def testXY0(self): 

155 """Test that inserting a HeavyFootprint obeys XY0""" 

156 fs = afwDetect.FootprintSet(self.mi, afwDetect.Threshold(1)) 

157 

158 fs.makeHeavy(self.mi) 

159 

160 bbox = lsst.geom.BoxI(lsst.geom.PointI(9, 1), lsst.geom.ExtentI(7, 4)) 

161 omi = self.mi.Factory(self.mi, bbox, afwImage.LOCAL, True) 

162 omi.set((0, 0x0, 0)) 

163 

164 for foot in fs.getFootprints(): 

165 foot.insert(omi) 

166 

167 if display: 

168 afwDisplay.Display(frame=0).mtv(self.mi, title="testXY0 input") 

169 afwDisplay.Display(frame=1).mtv(omi, title="testXY0 sub") 

170 

171 submi = self.mi.Factory(self.mi, bbox, afwImage.LOCAL) 

172 self.assertFloatsEqual(submi.getImage().getArray(), 

173 omi.getImage().getArray()) 

174 

175 def testMergeHeavyFootprints(self): 

176 mi = afwImage.MaskedImageF(20, 10) 

177 objectPixelVal = (42, 0x9, 400) 

178 

179 spanList = [] 

180 for y, x0, x1 in [(1, 9, 12), 

181 (2, 12, 13), 

182 (3, 11, 15)]: 

183 spanList.append(afwGeom.Span(y, x0, x1)) 

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

185 mi[x, y, afwImage.LOCAL] = objectPixelVal 

186 

187 foot = afwDetect.Footprint(afwGeom.SpanSet(spanList)) 

188 

189 hfoot1 = afwDetect.makeHeavyFootprint(self.foot, self.mi) 

190 hfoot2 = afwDetect.makeHeavyFootprint(foot, mi) 

191 

192 hsum = afwDetect.mergeHeavyFootprints(hfoot1, hfoot2) 

193 

194 bb = hsum.getBBox() 

195 self.assertEqual(bb.getMinX(), 9) 

196 self.assertEqual(bb.getMaxX(), 15) 

197 self.assertEqual(bb.getMinY(), 1) 

198 self.assertEqual(bb.getMaxY(), 3) 

199 

200 msum = afwImage.MaskedImageF(20, 10) 

201 hsum.insert(msum) 

202 

203 sa = msum.getImage().getArray() 

204 

205 self.assertFloatsEqual(sa[1, 9:13], objectPixelVal[0]) 

206 self.assertFloatsEqual( 

207 sa[2, 12:14], objectPixelVal[0] + self.objectPixelVal[0]) 

208 self.assertFloatsEqual(sa[2, 10:12], self.objectPixelVal[0]) 

209 

210 sv = msum.getVariance().getArray() 

211 

212 self.assertFloatsEqual(sv[1, 9:13], objectPixelVal[2]) 

213 self.assertFloatsEqual( 

214 sv[2, 12:14], objectPixelVal[2] + self.objectPixelVal[2]) 

215 self.assertFloatsEqual(sv[2, 10:12], self.objectPixelVal[2]) 

216 

217 sm = msum.getMask().getArray() 

218 

219 self.assertFloatsEqual(sm[1, 9:13], objectPixelVal[1]) 

220 self.assertFloatsEqual( 

221 sm[2, 12:14], objectPixelVal[1] | self.objectPixelVal[1]) 

222 self.assertFloatsEqual(sm[2, 10:12], self.objectPixelVal[1]) 

223 

224 if False: 

225 import matplotlib 

226 matplotlib.use('Agg') 

227 import pylab as plt 

228 im1 = afwImage.ImageF(bb) 

229 hfoot1.insert(im1) 

230 im2 = afwImage.ImageF(bb) 

231 hfoot2.insert(im2) 

232 im3 = afwImage.ImageF(bb) 

233 hsum.insert(im3) 

234 plt.clf() 

235 plt.subplot(1, 3, 1) 

236 plt.imshow(im1.getArray(), interpolation='nearest', origin='lower') 

237 plt.subplot(1, 3, 2) 

238 plt.imshow(im2.getArray(), interpolation='nearest', origin='lower') 

239 plt.subplot(1, 3, 3) 

240 plt.imshow(im3.getArray(), interpolation='nearest', origin='lower') 

241 plt.savefig('merge.png') 

242 

243 def testFitsPersistence(self): 

244 heavy1 = afwDetect.HeavyFootprintF(self.foot) 

245 heavy1.getImageArray()[:] = \ 

246 np.random.randn(self.foot.getArea()).astype(np.float32) 

247 heavy1.getMaskArray()[:] = \ 

248 np.random.randint(low=0, high=2, size=self.foot.getArea()).astype(np.uint16) 

249 heavy1.getVarianceArray()[:] = \ 

250 np.random.randn(self.foot.getArea()).astype(np.float32) 

251 with lsst.utils.tests.getTempFilePath(".fits") as filename: 

252 heavy1.writeFits(filename) 

253 heavy2 = afwDetect.HeavyFootprintF.readFits(filename) 

254 self.assertEqual(heavy1.getArea(), heavy2.getArea()) 

255 self.assertEqual(list(heavy1.getSpans()), list(heavy2.getSpans())) 

256 self.assertEqual(list(heavy1.getPeaks()), list(heavy2.getPeaks())) 

257 self.assertFloatsAlmostEqual(heavy1.getImageArray(), 

258 heavy2.getImageArray(), rtol=0.0, atol=0.0) 

259 self.assertFloatsAlmostEqual(heavy1.getMaskArray(), 

260 heavy2.getMaskArray(), rtol=0.0, atol=0.0) 

261 self.assertFloatsAlmostEqual(heavy1.getVarianceArray(), 

262 heavy2.getVarianceArray(), rtol=0.0, atol=0.0) 

263 

264 def testLegacyHeavyFootprintMaskLoading(self): 

265 filename = os.path.join(os.path.split(__file__)[0], 

266 "data", "legacyHeavyFootprint.fits") 

267 heavyFp = afwDetect.HeavyFootprintF.readFits(filename) 

268 self.assertTrue(all(heavyFp.getMaskArray() == 32)) 

269 self.assertTrue(heavyFp.getMaskArray().dtype == afwImage.MaskPixel) 

270 

271 def testDot(self): 

272 """Test HeavyFootprint::dot""" 

273 size = 20, 20 

274 for xOffset, yOffset in [(0, 0), (0, 3), (3, 0), (2, 2)]: 

275 mi1 = afwImage.MaskedImageF(*size) 

276 mi2 = afwImage.MaskedImageF(*size) 

277 mi1.set(0) 

278 mi2.set(0) 

279 

280 spanList1 = [] 

281 spanList2 = [] 

282 for y, x0, x1 in [(5, 3, 7), 

283 (6, 3, 4), 

284 (6, 6, 7), 

285 (7, 3, 7), ]: 

286 spanList1.append(afwGeom.Span(y, x0, x1)) 

287 spanList2.append(afwGeom.Span(y + yOffset, x0 + xOffset, 

288 x1 + xOffset)) 

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

290 value = (x + y, 0, 1.0) 

291 mi1[x, y, afwImage.LOCAL] = value 

292 mi2[x + xOffset, y + yOffset, afwImage.LOCAL] = value 

293 

294 fp1 = afwDetect.Footprint(afwGeom.SpanSet(spanList1)) 

295 fp2 = afwDetect.Footprint(afwGeom.SpanSet(spanList2)) 

296 

297 hfp1 = afwDetect.makeHeavyFootprint(fp1, mi1) 

298 hfp2 = afwDetect.makeHeavyFootprint(fp2, mi2) 

299 

300 dot = np.vdot(mi1.getImage().getArray(), mi2.getImage().getArray()) 

301 self.assertEqual(hfp1.dot(hfp2), dot) 

302 self.assertEqual(hfp2.dot(hfp1), dot) 

303 

304 def testAddSubtract(self): 

305 """Test that we can add and subtract a HeavyFootprint.""" 

306 fs = afwDetect.FootprintSet(self.mi, afwDetect.Threshold(1)) 

307 

308 fs.makeHeavy(self.mi) 

309 

310 bbox = lsst.geom.BoxI(lsst.geom.PointI(9, 1), lsst.geom.ExtentI(7, 4)) 

311 compImage = self.mi.Factory(self.mi, bbox, afwImage.LOCAL, True) 

312 compImage.set((10, 0x0, 0)) 

313 

314 blankImage = compImage.clone() 

315 blankImage.set((0, 0x0, 0)) 

316 

317 testImage = compImage.clone() 

318 

319 for foot in fs.getFootprints(): 

320 # Add via addTo 

321 foot.addTo(testImage.image) 

322 

323 # Add by using a temporary image and insert 

324 foot.insert(blankImage.image) 

325 inserted = blankImage.image.array > 0 

326 compImage.image.array[inserted] += blankImage.image.array[inserted] 

327 

328 np.testing.assert_array_almost_equal(testImage.image.array, 

329 compImage.image.array) 

330 

331 # Subtract via subtractFrom 

332 foot.subtractFrom(testImage.image) 

333 

334 compImage.image.array[inserted] -= blankImage.image.array[inserted] 

335 

336 np.testing.assert_array_almost_equal(testImage.image.array, 

337 compImage.image.array) 

338 

339 blankImage.set((0, 0x0, 0)) 

340 

341 

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

343 pass 

344 

345 

346def setup_module(module): 

347 lsst.utils.tests.init() 

348 

349 

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

351 lsst.utils.tests.init() 

352 unittest.main()