Coverage for tests/test_interpImageTask.py: 22%
95 statements
« prev ^ index » next coverage.py v6.4.1, created at 2022-06-28 11:21 +0000
« prev ^ index » next coverage.py v6.4.1, created at 2022-06-28 11:21 +0000
1# This file is part of pipe_tasks.
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/>.
22"""
23Tests for bad pixel interpolation task
25Run with:
26 python test_interpImageTask.py
27or
28 pytest test_interpImageTask.py
29"""
30import unittest
32import numpy as np
34import lsst.utils.tests
35import lsst.geom
36import lsst.afw.image as afwImage
37import lsst.pex.config as pexConfig
38import lsst.ip.isr as ipIsr
39from lsst.pipe.tasks.interpImage import InterpImageTask
41try:
42 display
43except NameError:
44 display = False
45else:
46 import lsst.afw.display as afwDisplay
47 afwDisplay.setDefaultMaskTransparency(75)
50class InterpolationTestCase(lsst.utils.tests.TestCase):
51 """A test case for interpolation.
52 """
54 def setUp(self):
55 self.FWHM = 5
57 def testEdge(self):
58 """Test that we can interpolate to the edge.
59 """
60 mi = afwImage.MaskedImageF(80, 30)
61 ima = mi.getImage().getArray()
62 #
63 # We'll set the BAD bit in pixels we wish to interpolate over
64 #
65 pixelPlane = "BAD"
66 badBit = afwImage.Mask.getPlaneBitMask(pixelPlane)
67 #
68 # Set bad columns near left and right sides of image
69 #
70 nBadCol = 10
71 mi.set((0, 0x0, 0))
73 np.random.seed(666)
74 ima[:] = np.random.uniform(-1, 1, ima.shape)
76 mi[0:nBadCol, :, afwImage.LOCAL] = (10, badBit, 0) # Bad left edge
77 # With another bad set of columns next to bad left edge
78 mi[-nBadCol:, :, afwImage.LOCAL] = (10, badBit, 0)
79 mi[nBadCol + 1:nBadCol + 4, 0:10, afwImage.LOCAL] = (100, badBit, 0) # Bad right edge
80 # more bad of columns next to bad right edge
81 mi[-nBadCol - 4:-nBadCol - 1, 0:10, afwImage.LOCAL] = (100, badBit, 0)
83 defectList = ipIsr.Defects.fromMask(mi, pixelPlane)
85 if display:
86 afwDisplay.Display(frame=0).mtv(mi, title=self._testMethodName + ": image")
88 def validateInterp(miInterp, useFallbackValueAtEdge, fallbackValue):
89 imaInterp = miInterp.getImage().getArray()
90 if display:
91 afwDisplay.Display(frame=1).mtv(miInterp, title=self._testMethodName + ": interp image")
92 self.assertGreater(np.min(imaInterp), min(-2, 2*fallbackValue))
93 self.assertGreater(max(2, 2*fallbackValue), np.max(imaInterp))
94 val0 = np.mean(miInterp.image[1:2, :, afwImage.LOCAL].array, dtype=float)
95 if useFallbackValueAtEdge:
96 self.assertAlmostEqual(val0, fallbackValue, 6)
97 else:
98 self.assertNotEqual(val0, 0)
100 for useFallbackValueAtEdge in (False, True):
101 miInterp = mi.clone()
102 config = InterpImageTask.ConfigClass()
103 config.useFallbackValueAtEdge = useFallbackValueAtEdge
104 interpTask = InterpImageTask(config)
106 if useFallbackValueAtEdge:
107 config.fallbackUserValue = -1.0
108 # choiceField fallbackValueType cannot be None if useFallbackValueAtEdge is True
109 config.fallbackValueType = None
110 self.assertRaises(NotImplementedError, interpTask._setFallbackValue, miInterp)
111 # make sure an invalid fallbackValueType raises a pexConfig.FieldValidationError
112 with self.assertRaises(pexConfig.FieldValidationError):
113 config.fallbackValueType = "NOTUSED"
114 # make sure ValueError is raised if both a planeName and defects list are provided
115 self.assertRaises(ValueError, interpTask.run, miInterp, defects=defectList,
116 planeName=pixelPlane, fwhmPixels=self.FWHM)
118 for fallbackValueType in ("USER", "MEAN", "MEDIAN", "MEANCLIP"):
119 for negativeFallbackAllowed in (True, False):
120 config.negativeFallbackAllowed = negativeFallbackAllowed
121 config.fallbackValueType = fallbackValueType
122 # Should raise if negative not allowed, but USER supplied negative value
123 if not negativeFallbackAllowed and fallbackValueType == "USER":
124 self.assertRaises(ValueError, config.validate)
126 interpTask = InterpImageTask(config)
127 fallbackValue = interpTask._setFallbackValue(mi)
128 #
129 # Time to interpolate
130 #
131 miInterp = mi.clone()
132 interpTask.run(miInterp, planeName=pixelPlane, fwhmPixels=self.FWHM)
133 validateInterp(miInterp, useFallbackValueAtEdge, fallbackValue)
134 miInterp = mi.clone()
135 interpTask.run(miInterp, defects=defectList)
136 validateInterp(miInterp, useFallbackValueAtEdge, fallbackValue)
137 else:
138 #
139 # Time to interpolate
140 #
141 miInterp = mi.clone()
142 interpTask.run(miInterp, planeName=pixelPlane, fwhmPixels=self.FWHM)
143 validateInterp(miInterp, useFallbackValueAtEdge, 0)
145 def testTranspose(self):
146 """Test transposition before interpolation
148 Interpolate over a bad row (not a bad column).
149 """
150 box = lsst.geom.Box2I(lsst.geom.Point2I(12345, 6789), lsst.geom.Extent2I(123, 45))
151 value = 123.45
152 bad = "BAD"
153 image = afwImage.MaskedImageF(box)
154 image.image.set(value)
155 image.mask.set(0)
157 badRow = box.getHeight()//2
158 image.image.array[badRow] = 10*value
159 image.mask.array[badRow] = image.mask.getPlaneBitMask(bad)
161 config = InterpImageTask.ConfigClass()
162 config.transpose = True
163 task = InterpImageTask(config)
164 task.run(image, planeName=bad, fwhmPixels=self.FWHM)
165 self.assertFloatsEqual(image.image.array, value)
168def setup_module(module):
169 lsst.utils.tests.init()
172class MatchMemoryTestCase(lsst.utils.tests.MemoryTestCase):
173 pass
176if __name__ == "__main__": 176 ↛ 177line 176 didn't jump to line 177, because the condition on line 176 was never true
177 lsst.utils.tests.init()
178 unittest.main()