Coverage for tests/test_copyGoodPixels.py: 19%
134 statements
« prev ^ index » next coverage.py v7.5.0, created at 2024-05-02 03:33 -0700
« prev ^ index » next coverage.py v7.5.0, created at 2024-05-02 03:33 -0700
1#
2# LSST Data Management System
3# Copyright 2008, 2009, 2010 LSST Corporation.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <http://www.lsstcorp.org/LegalNotices/>.
21#
23"""Test lsst.coadd.utils.copyGoodPixels
24"""
25import unittest
27import numpy as np
29import lsst.utils.tests
30import lsst.geom as geom
31import lsst.afw.image as afwImage
32import lsst.coadd.utils as coaddUtils
33from lsst.log import Log
35try:
36 display
37except NameError:
38 display = False
40Log.getLogger("coadd.utils").setLevel(Log.INFO)
43def referenceCopyGoodPixelsImage(destImage, srcImage):
44 """Reference implementation of lsst.coadd.utils.copyGoodPixels for Images
46 Unlike lsst.coadd.utils.copyGoodPixels this one does not update the input destImage,
47 but instead returns the new version
49 Inputs:
50 - destImage: source image before adding srcImage (a MaskedImage)
51 - srcImage: masked image to add to destImage (a MaskedImage)
52 - badPixelMask: mask of bad pixels to ignore (an int)
54 Returns:
55 - destImage: new destImage
56 - numGoodPix: number of good pixels
57 """
58 destImage = destImage.Factory(destImage, True) # make deep copy
60 overlapBBox = destImage.getBBox()
61 overlapBBox.clip(srcImage.getBBox())
63 if overlapBBox.isEmpty():
64 return (destImage, 0)
66 destImageView = destImage.Factory(destImage, overlapBBox, afwImage.PARENT, False)
67 destImageArray = destImageView.array
69 srcImageView = srcImage.Factory(srcImage, overlapBBox, afwImage.PARENT, False)
70 srcImageArray = srcImageView.array
72 isBadArray = np.isnan(srcImageArray)
74 destImageArray[:] = np.where(isBadArray, destImageArray, srcImageArray)
75 numGoodPix = np.sum(np.logical_not(isBadArray))
76 return destImage, numGoodPix
79def referenceCopyGoodPixelsMaskedImage(destImage, srcImage, badPixelMask):
80 """Reference implementation of lsst.coadd.utils.copyGoodPixels for MaskedImages
82 Unlike lsst.coadd.utils.copyGoodPixels this one does not update the input destImage,
83 but instead returns an updated copy
85 @param[in] destImage: source image before adding srcImage (a MaskedImage)
86 @param[in] srcImage: masked image to add to destImage (a MaskedImage)
87 @param[in] badPixelMask: mask of bad pixels to ignore (an int)
89 Returns:
90 - destImage: new destImage
91 - numGoodPix: number of good pixels
92 """
93 destImage = destImage.Factory(destImage, True) # make deep copy
95 overlapBBox = destImage.getBBox()
96 overlapBBox.clip(srcImage.getBBox())
98 if overlapBBox.isEmpty():
99 return (destImage, 0)
101 destImageView = destImage.Factory(destImage, overlapBBox, afwImage.PARENT, False)
102 srcImageView = srcImage.Factory(srcImage, overlapBBox, afwImage.PARENT, False)
104 isBadArray = (srcImageView.mask.array & badPixelMask) != 0
106 destImageView.image.array = np.where(isBadArray, destImageView.image.array, srcImageView.image.array)
107 destImageView.mask.array = np.where(isBadArray, destImageView.mask.array, srcImageView.mask.array)
108 destImageView.variance.array = np.where(isBadArray,
109 destImageView.variance.array,
110 srcImageView.variance.array)
112 numGoodPix = np.sum(np.logical_not(isBadArray))
113 return destImage, numGoodPix
116MaxMask = 0xFFFF
119class CopyGoodPixelsTestCase(lsst.utils.tests.TestCase):
120 """A test case for copyGoodPixels
121 """
123 def getSolidMaskedImage(self, bbox, val, badMask=0):
124 afwDim = bbox.getDimensions()
125 npShape = (afwDim[1], afwDim[0])
127 np.random.seed(0)
128 maskedImage = afwImage.MaskedImageF(bbox)
129 maskedImage.image.array[:] = val
130 maskedImage.variance.array[:] = val * 0.5
131 maskedImage.mask.array[:, 0:npShape[1]/2] = 0
132 maskedImage.mask.array[:, npShape[1]/2:] = badMask
133 return maskedImage
135 def getRandomMaskedImage(self, bbox, excludeMask=0):
136 """Get a randomly generated masked image
137 """
138 if excludeMask > MaxMask:
139 raise RuntimeError("excludeMask = %s > %s = MaxMask" % (excludeMask, MaxMask))
141 afwDim = bbox.getDimensions()
142 npShape = (afwDim[1], afwDim[0])
144 np.random.seed(0)
145 maskedImage = afwImage.MaskedImageF(bbox)
146 maskedImage.image.array[:] = np.random.normal(5000, 5000, npShape)
147 maskedImage.variance.array[:] = np.random.normal(3000, 3000, npShape)
148 maskedImage.mask.array[:] = np.logical_and(np.random.randint(0, 8, npShape), ~excludeMask)
149 return maskedImage
151 def getRandomImage(self, bbox, nanSigma=0):
152 """Get a randomly generated image
153 """
154 afwDim = bbox.getDimensions()
155 npShape = (afwDim[1], afwDim[0])
157 np.random.seed(0)
158 image = afwImage.ImageF(bbox)
159 imageArray = image.array
160 imageArray[:] = np.random.normal(5000, 5000, npShape)
161 if nanSigma > 0:
162 # add NaNs at nanSigma above mean of a test array
163 nanTest = np.random.normal(0, 1, npShape)
164 imageArray[:] = np.where(nanTest > nanSigma, np.nan, imageArray)
165 return image
167 def basicMaskedImageTest(self, srcImage, destImage, badMask):
168 refDestImage, refNumGoodPix = referenceCopyGoodPixelsMaskedImage(destImage, srcImage, badMask)
169 numGoodPix = coaddUtils.copyGoodPixels(destImage, srcImage, badMask)
171 self.assertEqual(numGoodPix, refNumGoodPix)
173 msg = "masked image != reference masked image"
174 try:
175 self.assertMaskedImagesAlmostEqual(destImage, refDestImage, msg=msg)
176 except Exception:
177 destImage.writeFits("destMaskedImage.fits")
178 refDestImage.writeFits("refDestMaskedImage.fits")
179 raise
181 def basicImageTest(self, srcImage, destImage):
182 refDestImage, refNumGoodPix = referenceCopyGoodPixelsImage(destImage, srcImage)
183 numGoodPix = coaddUtils.copyGoodPixels(destImage, srcImage)
185 msg = "image != reference image"
186 try:
187 self.assertImagesAlmostEqual(destImage, refDestImage, msg=msg)
188 except Exception:
189 destImage.writeFits("destImage.fits")
190 refDestImage.writeFits("refDestImage.fits")
191 raise
193 self.assertEqual(numGoodPix, refNumGoodPix)
195 def testMaskedImage(self):
196 """Test image version of copyGoodPixels"""
197 srcBBox = geom.Box2I(geom.Point2I(2, 17), geom.Point2I(100, 101))
198 destBBox = geom.Box2I(geom.Point2I(13, 4), geom.Point2I(95, 130))
199 destXY0 = destBBox.getMin()
201 srcImage = self.getRandomMaskedImage(srcBBox)
202 for badMask in (0, 3, MaxMask):
203 destImage = self.getRandomMaskedImage(destBBox, excludeMask=badMask)
204 destBBox = destImage.getBBox()
205 self.basicMaskedImageTest(srcImage, destImage, badMask)
207 for bboxStart in (destXY0, (50, 51)):
208 for bboxDim in ((25, 36), (200, 200)):
209 destViewBox = geom.Box2I(geom.Point2I(*bboxStart), geom.Extent2I(*bboxDim))
210 destViewBox.clip(destBBox)
211 destView = destImage.Factory(destImage, destViewBox, afwImage.PARENT, False)
212 self.basicMaskedImageTest(srcImage, destView, badMask)
214 def testImage(self):
215 """Test image version of copyGoodPixels"""
216 srcBBox = geom.Box2I(geom.Point2I(2, 17), geom.Point2I(100, 101))
217 destBBox = geom.Box2I(geom.Point2I(13, 4), geom.Point2I(95, 130))
218 destXY0 = destBBox.getMin()
220 srcImage = self.getRandomImage(srcBBox)
221 for nanSigma in (0, 0.7, 2.0):
222 destImage = self.getRandomImage(destBBox, nanSigma=nanSigma)
223 destBBox = destImage.getBBox()
224 self.basicImageTest(srcImage, destImage)
226 for bboxStart in (destXY0, (50, 51)):
227 for bboxDim in ((25, 36), (200, 200)):
228 destViewBox = geom.Box2I(geom.Point2I(*bboxStart), geom.Extent2I(*bboxDim))
229 destViewBox.clip(destBBox)
230 destView = destImage.Factory(destImage, destViewBox, afwImage.PARENT, False)
231 self.basicImageTest(srcImage, destView)
234class MemoryTester(lsst.utils.tests.MemoryTestCase):
235 pass
238def setup_module(module):
239 lsst.utils.tests.init()
242if __name__ == "__main__": 242 ↛ 243line 242 didn't jump to line 243, because the condition on line 242 was never true
243 lsst.utils.tests.init()
244 unittest.main()