Hide keyboard shortcuts

Hot-keys 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

1# 

2# LSST Data Management System 

3# 

4# Copyright 2008-2016 AURA/LSST. 

5# 

6# This product includes software developed by the 

7# LSST Project (http://www.lsst.org/). 

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 LSST License Statement and 

20# the GNU General Public License along with this program. If not, 

21# see <https://www.lsstcorp.org/LegalNotices/>. 

22# 

23import unittest 

24import numpy as np 

25from functools import reduce 

26 

27import lsst.utils.tests 

28import lsst.afw.detection as afwDet 

29import lsst.geom as geom 

30import lsst.afw.image as afwImage 

31from lsst.log import Log 

32from lsst.meas.deblender.baseline import deblend 

33import lsst.meas.algorithms as measAlg 

34 

35doPlot = False 

36if doPlot: 36 ↛ 37line 36 didn't jump to line 37, because the condition on line 36 was never true

37 import matplotlib 

38 matplotlib.use('Agg') 

39 import pylab as plt 

40 import os.path 

41 plotpat = os.path.join(os.path.dirname(__file__), 'stray%i.png') 

42 print('Writing plots to', plotpat) 

43else: 

44 print('"doPlot" not set -- not making plots. To enable plots, edit', __file__) 

45 

46# Lower the level to Log.DEBUG to see debug messages 

47Log.getLogger('meas.deblender.symmetrizeFootprint').setLevel(Log.INFO) 

48 

49 

50def imExt(img): 

51 bbox = img.getBBox() 

52 return [bbox.getMinX(), bbox.getMaxX(), 

53 bbox.getMinY(), bbox.getMaxY()] 

54 

55 

56def doubleGaussianPsf(W, H, fwhm1, fwhm2, a2): 

57 return measAlg.DoubleGaussianPsf(W, H, fwhm1, fwhm2, a2) 

58 

59 

60def gaussianPsf(W, H, fwhm): 

61 return measAlg.DoubleGaussianPsf(W, H, fwhm) 

62 

63 

64class StrayFluxTestCase(lsst.utils.tests.TestCase): 

65 

66 def test1(self): 

67 ''' 

68 A simple example: three overlapping blobs (detected as 1 

69 footprint with three peaks). We artificially omit one of the 

70 peaks, meaning that its flux is "stray". Assert that the 

71 stray flux assigned to the other two peaks accounts for all 

72 the flux in the parent. 

73 ''' 

74 H, W = 100, 100 

75 

76 fpbb = geom.Box2I(geom.Point2I(0, 0), 

77 geom.Point2I(W-1, H-1)) 

78 

79 afwimg = afwImage.MaskedImageF(fpbb) 

80 imgbb = afwimg.getBBox() 

81 img = afwimg.getImage().getArray() 

82 

83 var = afwimg.getVariance().getArray() 

84 var[:, :] = 1. 

85 

86 blob_fwhm = 10. 

87 blob_psf = doubleGaussianPsf(99, 99, blob_fwhm, 3.*blob_fwhm, 0.03) 

88 

89 fakepsf_fwhm = 3. 

90 fakepsf = gaussianPsf(11, 11, fakepsf_fwhm) 

91 

92 blobimgs = [] 

93 x = 75. 

94 XY = [(x, 35.), (x, 65.), (50., 50.)] 

95 flux = 1e6 

96 for x, y in XY: 

97 bim = blob_psf.computeImage(geom.Point2D(x, y)) 

98 bbb = bim.getBBox() 

99 bbb.clip(imgbb) 

100 

101 bim = bim.Factory(bim, bbb) 

102 bim2 = bim.getArray() 

103 

104 blobimg = np.zeros_like(img) 

105 blobimg[bbb.getMinY():bbb.getMaxY()+1, 

106 bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 

107 blobimgs.append(blobimg) 

108 

109 img[bbb.getMinY():bbb.getMaxY()+1, 

110 bbb.getMinX():bbb.getMaxX()+1] += flux * bim2 

111 

112 # Run the detection code to get a ~ realistic footprint 

113 thresh = afwDet.createThreshold(5., 'value', True) 

114 fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1) 

115 fps = fpSet.getFootprints() 

116 print('found', len(fps), 'footprints') 

117 pks2 = [] 

118 for fp in fps: 

119 print('peaks:', len(fp.getPeaks())) 

120 for pk in fp.getPeaks(): 

121 print(' ', pk.getIx(), pk.getIy()) 

122 pks2.append((pk.getIx(), pk.getIy())) 

123 

124 # The first peak in this list is the one we want to omit. 

125 fp0 = fps[0] 

126 fakefp = afwDet.Footprint(fp0.getSpans(), fp0.getBBox()) 

127 for pk in fp0.getPeaks()[1:]: 

128 fakefp.getPeaks().append(pk) 

129 

130 ima = dict(interpolation='nearest', origin='lower', cmap='gray', 

131 vmin=0, vmax=1e3) 

132 

133 if doPlot: 

134 plt.figure(figsize=(12, 6)) 

135 

136 plt.clf() 

137 plt.suptitle('strayFlux.py: test1 input') 

138 plt.subplot(2, 2, 1) 

139 plt.title('Image') 

140 plt.imshow(img, **ima) 

141 ax = plt.axis() 

142 plt.plot([x for x, y in XY], [y for x, y in XY], 'r.') 

143 plt.axis(ax) 

144 for i, (b, (x, y)) in enumerate(zip(blobimgs, XY)): 

145 plt.subplot(2, 2, 2+i) 

146 plt.title('Blob %i' % i) 

147 plt.imshow(b, **ima) 

148 ax = plt.axis() 

149 plt.plot(x, y, 'r.') 

150 plt.axis(ax) 

151 plt.savefig(plotpat % 1) 

152 

153 # Change verbose to False to quiet down the meas_deblender.baseline logger 

154 deb = deblend(fakefp, afwimg, fakepsf, fakepsf_fwhm, verbose=True) 

155 parent_img = afwImage.ImageF(fpbb) 

156 fakefp.spans.copyImage(afwimg.getImage(), parent_img) 

157 

158 if doPlot: 

159 def myimshow(*args, **kwargs): 

160 plt.imshow(*args, **kwargs) 

161 plt.xticks([]) 

162 plt.yticks([]) 

163 plt.axis(imExt(afwimg)) 

164 

165 plt.clf() 

166 plt.suptitle('strayFlux.py: test1 results') 

167 # R,C = 3,5 

168 R, C = 3, 4 

169 plt.subplot(R, C, (2*C) + 1) 

170 plt.title('Image') 

171 myimshow(img, **ima) 

172 ax = plt.axis() 

173 plt.plot([x for x, y in XY], [y for x, y in XY], 'r.') 

174 plt.axis(ax) 

175 

176 plt.subplot(R, C, (2*C) + 2) 

177 plt.title('Parent footprint') 

178 myimshow(parent_img.getArray(), **ima) 

179 ax = plt.axis() 

180 plt.plot([pk.getIx() for pk in fakefp.getPeaks()], 

181 [pk.getIy() for pk in fakefp.getPeaks()], 'r.') 

182 plt.axis(ax) 

183 

184 sumimg = None 

185 for i, dpk in enumerate(deb.peaks): 

186 plt.subplot(R, C, i*C + 1) 

187 plt.title('ch%i symm' % i) 

188 symm = dpk.templateImage 

189 myimshow(symm.getArray(), extent=imExt(symm), **ima) 

190 

191 plt.subplot(R, C, i*C + 2) 

192 plt.title('ch%i portion' % i) 

193 port = dpk.fluxPortion.getImage() 

194 myimshow(port.getArray(), extent=imExt(port), **ima) 

195 

196 himg = afwImage.ImageF(fpbb) 

197 heavy = dpk.getFluxPortion(strayFlux=False) 

198 heavy.insert(himg) 

199 

200 # plt.subplot(R, C, i*C + 3) 

201 # plt.title('ch%i heavy' % i) 

202 # myimshow(himg.getArray(), **ima) 

203 # ax = plt.axis() 

204 # plt.plot([x for x,y in XY], [y for x,y in XY], 'r.') 

205 # plt.axis(ax) 

206 

207 simg = afwImage.ImageF(fpbb) 

208 dpk.strayFlux.insert(simg) 

209 

210 plt.subplot(R, C, i*C + 3) 

211 plt.title('ch%i stray' % i) 

212 myimshow(simg.getArray(), **ima) 

213 ax = plt.axis() 

214 plt.plot([x for x, y in XY], [y for x, y in XY], 'r.') 

215 plt.axis(ax) 

216 

217 himg2 = afwImage.ImageF(fpbb) 

218 heavy = dpk.getFluxPortion(strayFlux=True) 

219 heavy.insert(himg2) 

220 

221 if sumimg is None: 

222 sumimg = himg2.getArray().copy() 

223 else: 

224 sumimg += himg2.getArray() 

225 

226 plt.subplot(R, C, i*C + 4) 

227 myimshow(himg2.getArray(), **ima) 

228 plt.title('ch%i total' % i) 

229 ax = plt.axis() 

230 plt.plot([x for x, y in XY], [y for x, y in XY], 'r.') 

231 plt.axis(ax) 

232 

233 plt.subplot(R, C, (2*C) + C) 

234 myimshow(sumimg, **ima) 

235 ax = plt.axis() 

236 plt.plot([x for x, y in XY], [y for x, y in XY], 'r.') 

237 plt.axis(ax) 

238 plt.title('Sum of deblends') 

239 

240 plt.savefig(plotpat % 2) 

241 

242 # Compute the sum-of-children image 

243 sumimg = None 

244 for i, dpk in enumerate(deb.deblendedParents[0].peaks): 

245 himg2 = afwImage.ImageF(fpbb) 

246 dpk.getFluxPortion().insert(himg2) 

247 if sumimg is None: 

248 sumimg = himg2.getArray().copy() 

249 else: 

250 sumimg += himg2.getArray() 

251 

252 # Sum of children ~= Original image inside footprint (parent_img) 

253 

254 absdiff = np.max(np.abs(sumimg - parent_img.getArray())) 

255 print('Max abs diff:', absdiff) 

256 imgmax = parent_img.getArray().max() 

257 print('Img max:', imgmax) 

258 self.assertLess(absdiff, imgmax*1e-6) 

259 

260 def test2(self): 

261 ''' 

262 A 1-d example, to test the stray-flux assignment. 

263 ''' 

264 H, W = 1, 100 

265 

266 fpbb = geom.Box2I(geom.Point2I(0, 0), 

267 geom.Point2I(W-1, H-1)) 

268 afwimg = afwImage.MaskedImageF(fpbb) 

269 img = afwimg.getImage().getArray() 

270 

271 var = afwimg.getVariance().getArray() 

272 var[:, :] = 1. 

273 

274 y = 0 

275 img[y, 1:-1] = 10. 

276 

277 img[0, 1] = 20. 

278 img[0, -2] = 20. 

279 

280 fakepsf_fwhm = 1. 

281 fakepsf = gaussianPsf(1, 1, fakepsf_fwhm) 

282 

283 # Run the detection code to get a ~ realistic footprint 

284 thresh = afwDet.createThreshold(5., 'value', True) 

285 fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1) 

286 fps = fpSet.getFootprints() 

287 self.assertEqual(len(fps), 1) 

288 fp = fps[0] 

289 

290 # WORKAROUND: the detection alg produces ONE peak, at (1,0), 

291 # rather than two. 

292 self.assertEqual(len(fp.getPeaks()), 1) 

293 fp.addPeak(W-2, y, float("NaN")) 

294 # print 'Added peak; peaks:', len(fp.getPeaks()) 

295 # for pk in fp.getPeaks(): 

296 # print ' ', pk.getFx(), pk.getFy() 

297 

298 # Change verbose to False to quiet down the meas_deblender.baseline logger 

299 deb = deblend(fp, afwimg, fakepsf, fakepsf_fwhm, verbose=True, 

300 fitPsfs=False, ) 

301 

302 if doPlot: 

303 XX = np.arange(W+1).repeat(2)[1:-1] 

304 

305 plt.clf() 

306 p1 = plt.plot(XX, img[y, :].repeat(2), 'g-', lw=3, alpha=0.3) 

307 

308 for i, dpk in enumerate(deb.peaks): 

309 print(dpk) 

310 port = dpk.fluxPortion.getImage() 

311 bb = port.getBBox() 

312 YY = np.zeros(XX.shape) 

313 YY[bb.getMinX()*2: (bb.getMaxX()+1)*2] = port.getArray()[0, :].repeat(2) 

314 p2 = plt.plot(XX, YY, 'r-') 

315 

316 simg = afwImage.ImageF(fpbb) 

317 dpk.strayFlux.insert(simg) 

318 p3 = plt.plot(XX, simg.getArray()[y, :].repeat(2), 'b-') 

319 

320 plt.legend((p1[0], p2[0], p3[0]), 

321 ('Parent Flux', 'Child portion', 'Child stray flux')) 

322 plt.ylim(-2, 22) 

323 plt.savefig(plotpat % 3) 

324 

325 strays = [] 

326 for i, dpk in enumerate(deb.deblendedParents[0].peaks): 

327 simg = afwImage.ImageF(fpbb) 

328 dpk.strayFlux.insert(simg) 

329 strays.append(simg.getArray()) 

330 

331 ssum = reduce(np.add, strays) 

332 

333 starget = np.zeros(W) 

334 starget[2:-2] = 10. 

335 

336 self.assertFloatsEqual(ssum, starget) 

337 

338 X = np.arange(W) 

339 dx1 = X - 1. 

340 dx2 = X - (W-2) 

341 f1 = (1. / (1. + dx1**2)) 

342 f2 = (1. / (1. + dx2**2)) 

343 strayclip = 0.001 

344 fsum = f1 + f2 

345 f1[f1 < strayclip * fsum] = 0. 

346 f2[f2 < strayclip * fsum] = 0. 

347 

348 s1 = f1 / (f1+f2) * 10. 

349 s2 = f2 / (f1+f2) * 10. 

350 

351 s1[:2] = 0. 

352 s2[-2:] = 0. 

353 

354 if doPlot: 

355 p4 = plt.plot(XX, s1.repeat(2), 'm-') 

356 plt.plot(XX, s2.repeat(2), 'm-') 

357 

358 plt.legend((p1[0], p2[0], p3[0], p4[0]), 

359 ('Parent Flux', 'Child portion', 'Child stray flux', 

360 'Expected stray flux')) 

361 plt.ylim(-2, 22) 

362 plt.savefig(plotpat % 4) 

363 

364 # test abs diff 

365 d = np.max(np.abs(s1 - strays[0])) 

366 self.assertLess(d, 1e-6) 

367 d = np.max(np.abs(s2 - strays[1])) 

368 self.assertLess(d, 1e-6) 

369 

370 # test relative diff 

371 self.assertLess(np.max(np.abs(s1 - strays[0])/np.maximum(1e-3, s1)), 1e-6) 

372 self.assertLess(np.max(np.abs(s2 - strays[1])/np.maximum(1e-3, s2)), 1e-6) 

373 

374 

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

376 pass 

377 

378 

379def setup_module(module): 

380 lsst.utils.tests.init() 

381 

382 

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

384 lsst.utils.tests.init() 

385 unittest.main()