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# This file is part of meas_algorithms. 

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 

22import os 

23import unittest 

24import math 

25import numpy as np 

26 

27import lsst.geom 

28import lsst.afw.image as afwImage 

29import lsst.meas.algorithms as algorithms 

30import lsst.utils.tests 

31from lsst.daf.base import PropertyList 

32 

33try: 

34 type(display) 

35except NameError: 

36 display = False 

37else: 

38 import lsst.afw.display as afwDisplay 

39 afwDisplay.setDefaultMaskTransparency(75) 

40 

41# Determine if we have afwdata 

42try: 

43 afwdataDir = lsst.utils.getPackageDir('afwdata') 

44except Exception: 

45 afwdataDir = None 

46 

47TESTDIR = os.path.abspath(os.path.dirname(__file__)) 

48 

49 

50class DefectsTestCase(lsst.utils.tests.TestCase): 

51 """Tests for collections of Defect.""" 

52 

53 def assertMetadata(self, first, second): 

54 """Compare the metadata associated with Defects""" 

55 

56 # Must strip out DATE metadata before comparison 

57 meta1 = first.getMetadata() 

58 meta2 = second.getMetadata() 

59 for d in (meta1, meta2): 

60 for k in ("DATE", "CALIB_CREATION_DATE", "CALIB_CREATION_TIME"): 

61 if k in d: 

62 del d[k] 

63 

64 self.assertEqual(meta1, meta2) 

65 meta1["NEW"] = "additional header" 

66 self.assertNotEqual(first.getMetadata(), second.getMetadata()) 

67 del meta1["NEW"] 

68 

69 def test_defects(self): 

70 defects = algorithms.Defects() 

71 

72 defects.append(algorithms.Defect(lsst.geom.Box2I(lsst.geom.Point2I(5, 6), 

73 lsst.geom.Point2I(41, 50)))) 

74 

75 defects.append(lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

76 lsst.geom.Point2I(4, 5))) 

77 defects.append(lsst.geom.Point2I(10, 12)) 

78 defects.append(afwImage.DefectBase(lsst.geom.Box2I(lsst.geom.Point2I(100, 200), 

79 lsst.geom.Extent2I(5, 5)))) 

80 self.assertEqual(len(defects), 4) 

81 

82 for d in defects: 

83 self.assertIsInstance(d, algorithms.Defect) 

84 

85 # Transposition 

86 transposed = defects.transpose() 

87 self.assertEqual(len(transposed), len(defects)) 

88 self.assertEqual(transposed[0].getBBox(), 

89 lsst.geom.Box2I(lsst.geom.Point2I(6, 5), 

90 lsst.geom.Extent2I(45, 37))) 

91 

92 # Serialization round trip 

93 meta = PropertyList() 

94 meta["TESTHDR"] = "testing" 

95 defects.setMetadata(meta) 

96 

97 table = defects.toFitsRegionTable() 

98 defects2 = algorithms.Defects.fromTable(table) 

99 self.assertEqual(defects2, defects) 

100 

101 # via FITS 

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

103 defects.writeFits(tmpFile) 

104 defects2 = algorithms.Defects.readFits(tmpFile) 

105 

106 # Equality tests the bounding boxes so metadata is tested separately. 

107 self.assertEqual(defects2, defects) 

108 self.assertMetadata(defects2, defects) 

109 

110 # via text file 

111 with lsst.utils.tests.getTempFilePath(".ecsv") as tmpFile: 

112 defects.writeText(tmpFile) 

113 defects2 = algorithms.Defects.readText(tmpFile) 

114 

115 # Equality tests the bounding boxes so metadata is tested separately. 

116 self.assertEqual(defects2, defects) 

117 self.assertMetadata(defects2, defects) 

118 

119 # Check bad values 

120 with self.assertRaises(ValueError): 

121 defects.append(lsst.geom.Box2D(lsst.geom.Point2D(0., 0.), 

122 lsst.geom.Point2D(3.1, 3.1))) 

123 with self.assertRaises(ValueError): 

124 defects.append("defect") 

125 

126 def testAstropyRegion(self): 

127 """Read a FITS region file created by Astropy regions.""" 

128 

129 with self.assertLogs(): 

130 defects = algorithms.Defects.readFits(os.path.join(TESTDIR, "data", "fits_region.fits")) 

131 

132 # Should be able to read 3 regions from the file 

133 self.assertEqual(len(defects), 3) 

134 

135 def testLsstTextfile(self): 

136 """Read legacy LSST text file format""" 

137 with lsst.utils.tests.getTempFilePath(".txt") as tmpFile: 

138 with open(tmpFile, "w") as fh: 

139 print("""# X0 Y0 width height 

140 996 0 56 24 

141 0 4156 2048 20 

142 0 0 17 4176 

143 1998 4035 50 141 

144 1023 0 2 4176 

145 2027 0 21 4176 

146 0 4047 37 129 

147# Some rows without fixed column widths 

14814 20 2000 50 

14910 10 10 10 

150""", file=fh) 

151 

152 defects = algorithms.Defects.readLsstDefectsFile(tmpFile) 

153 

154 self.assertEqual(len(defects), 9) 

155 self.assertEqual(defects[3].getBBox(), lsst.geom.Box2I(lsst.geom.Point2I(1998, 4035), 

156 lsst.geom.Extent2I(50, 141))) 

157 

158 

159class InterpolationTestCase(lsst.utils.tests.TestCase): 

160 """A test case for interpolation.""" 

161 

162 def setUp(self): 

163 self.FWHM = 5 

164 self.psf = algorithms.DoubleGaussianPsf(15, 15, self.FWHM/(2*math.sqrt(2*math.log(2)))) 

165 maskedImageFile = os.path.join(afwdataDir, "CFHT", "D4", "cal-53535-i-797722_1.fits") 

166 

167 self.mi = afwImage.MaskedImageF(maskedImageFile) 

168 if False: # use sub-image? 

169 self.mi = self.mi.Factory(self.mi, afwImage.BBox(afwImage.PointI(760, 20), 256, 256)) 

170 self.mi.getMask().addMaskPlane("INTERP") 

171 

172 measAlgorithmsDir = lsst.utils.getPackageDir('meas_algorithms') 

173 self.badPixels = algorithms.Defects.readText(os.path.join(measAlgorithmsDir, 

174 "policy", "BadPixels.ecsv")) 

175 

176 def tearDown(self): 

177 del self.mi 

178 del self.psf 

179 del self.badPixels 

180 

181 @unittest.skipUnless(afwdataDir, "afwdata not available") 

182 def testDetection(self): 

183 """Test Interp algorithms.""" 

184 

185 if display: 

186 frame = 0 

187 afwDisplay.Display(frame=frame).mtv(self.mi, title=self._testMethodName + ": Original") 

188 

189 algorithms.interpolateOverDefects(self.mi, self.psf, self.badPixels) 

190 

191 if display: 

192 frame += 1 

193 afwDisplay.Display(frame=frame).mtv(self.mi, title=self._testMethodName + ": Interpolated") 

194 frame += 1 

195 afwDisplay.Display(frame=frame).mtv(self.mi.getVariance(), 

196 title=self._testMethodName + ": Variance") 

197 

198 @unittest.skipUnless(afwdataDir, "afwdata not available") 

199 def test818(self): 

200 """A test case for #818; the full test is in /lsst/DC3root/ticketFiles/818""" 

201 

202 badPixels = [] 

203 defects = [((82, 663), 6, 8), 

204 ((83, 659), 9, 6), 

205 ((85, 660), 10, 11), 

206 ((87, 669), 3, 3), 

207 ] 

208 

209 for xy0, width, height in defects: 

210 x0, y0 = xy0 

211 bbox = lsst.geom.BoxI(lsst.geom.PointI(x0, y0), lsst.geom.ExtentI(width, height)) 

212 badPixels.append(algorithms.Defect(bbox)) 

213 

214 mi = afwImage.MaskedImageF(517, 800) 

215 

216 algorithms.interpolateOverDefects(mi, self.psf, badPixels) 

217 

218 @unittest.skipUnless(afwdataDir, "afwdata not available") 

219 def test1295(self): 

220 """A test case for #1295 (failure to interpolate over groups of defects.""" 

221 im = afwImage.ImageF(lsst.geom.ExtentI(100, 100)) 

222 mi = afwImage.makeMaskedImage(im) 

223 mi.set(100) 

224 flat = afwImage.ImageF(im.getDimensions()) 

225 flat.set(1) 

226 flat[50:51, :, afwImage.LOCAL] = 0.0 

227 flat[55:56, :, afwImage.LOCAL] = 0.0 

228 flat[58:59, :, afwImage.LOCAL] = 0.0 

229 flat[51:60, 51:, afwImage.LOCAL] = 0.0 

230 

231 mi /= flat 

232 

233 if display: 

234 afwDisplay.Display(frame=0).mtv(mi, title=self._testMethodName + ": Raw") 

235 

236 defectList = algorithms.Defects() 

237 bbox = lsst.geom.BoxI(lsst.geom.PointI(50, 0), lsst.geom.ExtentI(1, 100)) 

238 defectList.append(algorithms.Defect(bbox)) 

239 bbox = lsst.geom.BoxI(lsst.geom.PointI(55, 0), lsst.geom.ExtentI(1, 100)) 

240 defectList.append(algorithms.Defect(bbox)) 

241 bbox = lsst.geom.BoxI(lsst.geom.PointI(58, 0), lsst.geom.ExtentI(1, 100)) 

242 defectList.append(algorithms.Defect(bbox)) 

243 bbox = lsst.geom.BoxI(lsst.geom.PointI(51, 51), lsst.geom.ExtentI(9, 49)) 

244 defectList.append(algorithms.Defect(bbox)) 

245 

246 psf = algorithms.DoubleGaussianPsf(15, 15, 1./(2*math.sqrt(2*math.log(2)))) 

247 algorithms.interpolateOverDefects(mi, psf, defectList, 50.) 

248 

249 if display: 

250 afwDisplay.Display(frame=1).mtv(mi, title=self._testMethodName + ": Interpolated") 

251 

252 self.assertTrue(np.isfinite(mi.image[56, 51, afwImage.LOCAL])) 

253 

254 @unittest.skipUnless(afwdataDir, "afwdata not available") 

255 def testEdge(self): 

256 """Test that we can interpolate to the edge""" 

257 mi = afwImage.MaskedImageF(80, 30) 

258 

259 ima = mi.getImage().getArray() 

260 # 

261 # Loop over number of bad columns at left or right edge of image 

262 # 

263 for nBadCol in range(0, 20): 

264 mi.set((0, 0x0, 0)) 

265 

266 np.random.seed(666) 

267 ima[:] = np.random.uniform(-1, 1, ima.shape) 

268 

269 defects = [] 

270 

271 if nBadCol > 0: 

272 # 

273 # Bad left edge 

274 # 

275 ima[:, 0:nBadCol] = 10 

276 defects.append(lsst.geom.BoxI(lsst.geom.PointI(0, 0), 

277 lsst.geom.ExtentI(nBadCol, mi.getHeight()))) 

278 # 

279 # With another bad set of columns next to bad left edge 

280 # 

281 ima[:, -nBadCol:] = 10 

282 defects.append(lsst.geom.BoxI(lsst.geom.PointI(mi.getWidth() - nBadCol, 0), 

283 lsst.geom.ExtentI(nBadCol, mi.getHeight()))) 

284 # 

285 # Bad right edge 

286 # 

287 ima[0:10, nBadCol+1:nBadCol+4] = 100 

288 defects.append(lsst.geom.BoxI(lsst.geom.PointI(nBadCol+1, 0), 

289 lsst.geom.ExtentI(3, 10))) 

290 # 

291 # With another bad set of columns next to bad right edge 

292 # 

293 ima[0:10, -nBadCol-4:-nBadCol-1] = 100 

294 defects.append((lsst.geom.BoxI(lsst.geom.PointI(mi.getWidth() - nBadCol - 4, 0), 

295 lsst.geom.ExtentI(3, 10)))) 

296 # 

297 # Test cases that left and right bad patches nearly (or do) coalesce 

298 # 

299 ima[-3:, 0:mi.getWidth()//2-1] = 100 

300 defects.append(lsst.geom.BoxI(lsst.geom.PointI(0, mi.getHeight() - 3), 

301 lsst.geom.ExtentI(mi.getWidth()//2-1, 1))) 

302 

303 ima[-3:, mi.getWidth()//2+1:] = 100 

304 defects.append(lsst.geom.BoxI(lsst.geom.PointI(mi.getWidth()//2 + 1, mi.getHeight() - 3), 

305 lsst.geom.ExtentI(mi.getWidth()//2 - 1, 1))) 

306 

307 ima[-2:, 0:mi.getWidth()//2] = 100 

308 defects.append(lsst.geom.BoxI(lsst.geom.PointI(0, mi.getHeight() - 2), 

309 lsst.geom.ExtentI(mi.getWidth()//2, 1))) 

310 

311 ima[-2:, mi.getWidth()//2+1:] = 100 

312 defects.append(lsst.geom.BoxI(lsst.geom.PointI(mi.getWidth()//2 + 1, mi.getHeight() - 2), 

313 lsst.geom.ExtentI(mi.getWidth()//2 - 1, 1))) 

314 

315 ima[-1:, :] = 100 

316 defects.append(lsst.geom.BoxI(lsst.geom.PointI(0, mi.getHeight() - 1), 

317 lsst.geom.ExtentI(mi.getWidth(), 1))) 

318 

319 # Test fix for HSC-978: long defect stops one pixel shy of the edge (when nBadCol == 0) 

320 ima[13, :-1] = 100 

321 defects.append(lsst.geom.BoxI(lsst.geom.PointI(0, 13), lsst.geom.ExtentI(mi.getWidth() - 1, 1))) 

322 ima[14, 1:] = 100 

323 defects.append(lsst.geom.BoxI(lsst.geom.PointI(1, 14), lsst.geom.ExtentI(mi.getWidth() - 1, 1))) 

324 

325 # 

326 # Build list of defects to interpolate over 

327 # 

328 defectList = algorithms.Defects() 

329 

330 for bbox in defects: 

331 defectList.append(algorithms.Defect(bbox)) 

332 # 

333 # Guess a PSF and do the work 

334 # 

335 if display: 

336 afwDisplay.Display(frame=2).mtv(mi, title=self._testMethodName + ": image") 

337 

338 psf = algorithms.DoubleGaussianPsf(15, 15, 1./(2*math.sqrt(2*math.log(2)))) 

339 algorithms.interpolateOverDefects(mi, psf, defectList, 0, True) 

340 

341 if display: 

342 afwDisplay.Display(frame=3).mtv(mi, title=self._testMethodName + ": image") 

343 

344 self.assertGreater(np.min(ima), -2) 

345 self.assertGreater(2, np.max(ima)) 

346 

347 

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

349 pass 

350 

351 

352def setup_module(module): 

353 lsst.utils.tests.init() 

354 

355 

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

357 lsst.utils.tests.init() 

358 unittest.main()