Coverage for tests/test_interp.py : 16%

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/>.
22import os
23import unittest
24import math
25import numpy as np
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
33try:
34 type(display)
35except NameError:
36 display = False
37else:
38 import lsst.afw.display as afwDisplay
39 afwDisplay.setDefaultMaskTransparency(75)
41# Determine if we have afwdata
42try:
43 afwdataDir = lsst.utils.getPackageDir('afwdata')
44except Exception:
45 afwdataDir = None
47TESTDIR = os.path.abspath(os.path.dirname(__file__))
50class DefectsTestCase(lsst.utils.tests.TestCase):
51 """Tests for collections of Defect."""
53 def assertMetadata(self, first, second):
54 """Compare the metadata associated with Defects"""
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]
64 self.assertEqual(meta1, meta2)
65 meta1["NEW"] = "additional header"
66 self.assertNotEqual(first.getMetadata(), second.getMetadata())
67 del meta1["NEW"]
69 def test_defects(self):
70 defects = algorithms.Defects()
72 defects.append(algorithms.Defect(lsst.geom.Box2I(lsst.geom.Point2I(5, 6),
73 lsst.geom.Point2I(41, 50))))
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)
82 for d in defects:
83 self.assertIsInstance(d, algorithms.Defect)
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)))
92 # Serialization round trip
93 meta = PropertyList()
94 meta["TESTHDR"] = "testing"
95 defects.setMetadata(meta)
97 table = defects.toFitsRegionTable()
98 defects2 = algorithms.Defects.fromTable(table)
99 self.assertEqual(defects2, defects)
101 # via FITS
102 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
103 defects.writeFits(tmpFile)
104 defects2 = algorithms.Defects.readFits(tmpFile)
106 # Equality tests the bounding boxes so metadata is tested separately.
107 self.assertEqual(defects2, defects)
108 self.assertMetadata(defects2, defects)
110 # via text file
111 with lsst.utils.tests.getTempFilePath(".ecsv") as tmpFile:
112 defects.writeText(tmpFile)
113 defects2 = algorithms.Defects.readText(tmpFile)
115 # Equality tests the bounding boxes so metadata is tested separately.
116 self.assertEqual(defects2, defects)
117 self.assertMetadata(defects2, defects)
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")
126 def testAstropyRegion(self):
127 """Read a FITS region file created by Astropy regions."""
129 with self.assertLogs():
130 defects = algorithms.Defects.readFits(os.path.join(TESTDIR, "data", "fits_region.fits"))
132 # Should be able to read 3 regions from the file
133 self.assertEqual(len(defects), 3)
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)
152 defects = algorithms.Defects.readLsstDefectsFile(tmpFile)
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)))
159class InterpolationTestCase(lsst.utils.tests.TestCase):
160 """A test case for interpolation."""
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")
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")
172 measAlgorithmsDir = lsst.utils.getPackageDir('meas_algorithms')
173 self.badPixels = algorithms.Defects.readText(os.path.join(measAlgorithmsDir,
174 "policy", "BadPixels.ecsv"))
176 def tearDown(self):
177 del self.mi
178 del self.psf
179 del self.badPixels
181 @unittest.skipUnless(afwdataDir, "afwdata not available")
182 def testDetection(self):
183 """Test Interp algorithms."""
185 if display:
186 frame = 0
187 afwDisplay.Display(frame=frame).mtv(self.mi, title=self._testMethodName + ": Original")
189 algorithms.interpolateOverDefects(self.mi, self.psf, self.badPixels)
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")
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"""
202 badPixels = []
203 defects = [((82, 663), 6, 8),
204 ((83, 659), 9, 6),
205 ((85, 660), 10, 11),
206 ((87, 669), 3, 3),
207 ]
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))
214 mi = afwImage.MaskedImageF(517, 800)
216 algorithms.interpolateOverDefects(mi, self.psf, badPixels)
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
231 mi /= flat
233 if display:
234 afwDisplay.Display(frame=0).mtv(mi, title=self._testMethodName + ": Raw")
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))
246 psf = algorithms.DoubleGaussianPsf(15, 15, 1./(2*math.sqrt(2*math.log(2))))
247 algorithms.interpolateOverDefects(mi, psf, defectList, 50.)
249 if display:
250 afwDisplay.Display(frame=1).mtv(mi, title=self._testMethodName + ": Interpolated")
252 self.assertTrue(np.isfinite(mi.image[56, 51, afwImage.LOCAL]))
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)
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))
266 np.random.seed(666)
267 ima[:] = np.random.uniform(-1, 1, ima.shape)
269 defects = []
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)))
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)))
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)))
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)))
315 ima[-1:, :] = 100
316 defects.append(lsst.geom.BoxI(lsst.geom.PointI(0, mi.getHeight() - 1),
317 lsst.geom.ExtentI(mi.getWidth(), 1)))
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)))
325 #
326 # Build list of defects to interpolate over
327 #
328 defectList = algorithms.Defects()
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")
338 psf = algorithms.DoubleGaussianPsf(15, 15, 1./(2*math.sqrt(2*math.log(2))))
339 algorithms.interpolateOverDefects(mi, psf, defectList, 0, True)
341 if display:
342 afwDisplay.Display(frame=3).mtv(mi, title=self._testMethodName + ": image")
344 self.assertGreater(np.min(ima), -2)
345 self.assertGreater(2, np.max(ima))
348class TestMemory(lsst.utils.tests.MemoryTestCase):
349 pass
352def setup_module(module):
353 lsst.utils.tests.init()
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()