Coverage for tests/test_copyGoodPixels.py: 18%
139 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-10 02:23 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-10 02:23 -0800
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.getArray()
69 srcImageView = srcImage.Factory(srcImage, overlapBBox, afwImage.PARENT, False)
70 srcImageArray = srcImageView.getArray()
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 destImageArrayList = destImageView.getArrays()
104 srcImageView = srcImage.Factory(srcImage, overlapBBox, afwImage.PARENT, False)
105 srcImageArrayList = srcImageView.getArrays()
107 isBadArray = (srcImageArrayList[1] & badPixelMask) != 0
109 for ind in range(3):
110 destImageView = destImageArrayList[ind]
111 srcImageView = srcImageArrayList[ind]
112 destImageView[:] = np.where(isBadArray, destImageView, srcImageView)
113 numGoodPix = np.sum(np.logical_not(isBadArray))
114 return destImage, numGoodPix
117MaxMask = 0xFFFF
120class CopyGoodPixelsTestCase(lsst.utils.tests.TestCase):
121 """A test case for copyGoodPixels
122 """
124 def getSolidMaskedImage(self, bbox, val, badMask=0):
125 afwDim = bbox.getDimensions()
126 npShape = (afwDim[1], afwDim[0])
128 np.random.seed(0)
129 maskedImage = afwImage.MaskedImageF(bbox)
130 imageArrays = maskedImage.getArrays()
131 imageArrays[0][:] = val
132 imageArrays[2][:] = val * 0.5
133 imageArrays[1][:, 0:npShape[1]/2] = 0
134 imageArrays[1][:, npShape[1]/2:] = badMask
135 return maskedImage
137 def getRandomMaskedImage(self, bbox, excludeMask=0):
138 """Get a randomly generated masked image
139 """
140 if excludeMask > MaxMask:
141 raise RuntimeError("excludeMask = %s > %s = MaxMask" % (excludeMask, MaxMask))
143 afwDim = bbox.getDimensions()
144 npShape = (afwDim[1], afwDim[0])
146 np.random.seed(0)
147 maskedImage = afwImage.MaskedImageF(bbox)
148 imageArrays = maskedImage.getArrays()
149 imageArrays[0][:] = np.random.normal(5000, 5000, npShape) # image
150 imageArrays[2][:] = np.random.normal(3000, 3000, npShape) # variance
151 imageArrays[1][:] = np.logical_and(np.random.randint(0, 8, npShape), ~excludeMask)
152 return maskedImage
154 def getRandomImage(self, bbox, nanSigma=0):
155 """Get a randomly generated image
156 """
157 afwDim = bbox.getDimensions()
158 npShape = (afwDim[1], afwDim[0])
160 np.random.seed(0)
161 image = afwImage.ImageF(bbox)
162 imageArray = image.getArray()
163 imageArray[:] = np.random.normal(5000, 5000, npShape)
164 if nanSigma > 0:
165 # add NaNs at nanSigma above mean of a test array
166 nanTest = np.random.normal(0, 1, npShape)
167 imageArray[:] = np.where(nanTest > nanSigma, np.nan, imageArray)
168 return image
170 def basicMaskedImageTest(self, srcImage, destImage, badMask):
171 refDestImage, refNumGoodPix = referenceCopyGoodPixelsMaskedImage(destImage, srcImage, badMask)
172 numGoodPix = coaddUtils.copyGoodPixels(destImage, srcImage, badMask)
174 self.assertEqual(numGoodPix, refNumGoodPix)
176 msg = "masked image != reference masked image"
177 try:
178 self.assertMaskedImagesAlmostEqual(destImage, refDestImage, msg=msg)
179 except Exception:
180 destImage.writeFits("destMaskedImage.fits")
181 refDestImage.writeFits("refDestMaskedImage.fits")
182 raise
184 def basicImageTest(self, srcImage, destImage):
185 refDestImage, refNumGoodPix = referenceCopyGoodPixelsImage(destImage, srcImage)
186 numGoodPix = coaddUtils.copyGoodPixels(destImage, srcImage)
188 msg = "image != reference image"
189 try:
190 self.assertImagesAlmostEqual(destImage, refDestImage, msg=msg)
191 except Exception:
192 destImage.writeFits("destImage.fits")
193 refDestImage.writeFits("refDestImage.fits")
194 raise
196 self.assertEqual(numGoodPix, refNumGoodPix)
198 def testMaskedImage(self):
199 """Test image version of copyGoodPixels"""
200 srcBBox = geom.Box2I(geom.Point2I(2, 17), geom.Point2I(100, 101))
201 destBBox = geom.Box2I(geom.Point2I(13, 4), geom.Point2I(95, 130))
202 destXY0 = destBBox.getMin()
204 srcImage = self.getRandomMaskedImage(srcBBox)
205 for badMask in (0, 3, MaxMask):
206 destImage = self.getRandomMaskedImage(destBBox, excludeMask=badMask)
207 destBBox = destImage.getBBox()
208 self.basicMaskedImageTest(srcImage, destImage, badMask)
210 for bboxStart in (destXY0, (50, 51)):
211 for bboxDim in ((25, 36), (200, 200)):
212 destViewBox = geom.Box2I(geom.Point2I(*bboxStart), geom.Extent2I(*bboxDim))
213 destViewBox.clip(destBBox)
214 destView = destImage.Factory(destImage, destViewBox, afwImage.PARENT, False)
215 self.basicMaskedImageTest(srcImage, destView, badMask)
217 def testImage(self):
218 """Test image version of copyGoodPixels"""
219 srcBBox = geom.Box2I(geom.Point2I(2, 17), geom.Point2I(100, 101))
220 destBBox = geom.Box2I(geom.Point2I(13, 4), geom.Point2I(95, 130))
221 destXY0 = destBBox.getMin()
223 srcImage = self.getRandomImage(srcBBox)
224 for nanSigma in (0, 0.7, 2.0):
225 destImage = self.getRandomImage(destBBox, nanSigma=nanSigma)
226 destBBox = destImage.getBBox()
227 self.basicImageTest(srcImage, destImage)
229 for bboxStart in (destXY0, (50, 51)):
230 for bboxDim in ((25, 36), (200, 200)):
231 destViewBox = geom.Box2I(geom.Point2I(*bboxStart), geom.Extent2I(*bboxDim))
232 destViewBox.clip(destBBox)
233 destView = destImage.Factory(destImage, destViewBox, afwImage.PARENT, False)
234 self.basicImageTest(srcImage, destView)
237class MemoryTester(lsst.utils.tests.MemoryTestCase):
238 pass
241def setup_module(module):
242 lsst.utils.tests.init()
245if __name__ == "__main__": 245 ↛ 246line 245 didn't jump to line 246, because the condition on line 245 was never true
246 lsst.utils.tests.init()
247 unittest.main()