Coverage for tests/test_copyGoodPixels.py: 19%

134 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-04 11:47 +0000

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# 

22 

23"""Test lsst.coadd.utils.copyGoodPixels 

24""" 

25import unittest 

26 

27import numpy as np 

28 

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 

34 

35try: 

36 display 

37except NameError: 

38 display = False 

39 

40Log.getLogger("coadd.utils").setLevel(Log.INFO) 

41 

42 

43def referenceCopyGoodPixelsImage(destImage, srcImage): 

44 """Reference implementation of lsst.coadd.utils.copyGoodPixels for Images 

45 

46 Unlike lsst.coadd.utils.copyGoodPixels this one does not update the input destImage, 

47 but instead returns the new version 

48 

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) 

53 

54 Returns: 

55 - destImage: new destImage 

56 - numGoodPix: number of good pixels 

57 """ 

58 destImage = destImage.Factory(destImage, True) # make deep copy 

59 

60 overlapBBox = destImage.getBBox() 

61 overlapBBox.clip(srcImage.getBBox()) 

62 

63 if overlapBBox.isEmpty(): 

64 return (destImage, 0) 

65 

66 destImageView = destImage.Factory(destImage, overlapBBox, afwImage.PARENT, False) 

67 destImageArray = destImageView.array 

68 

69 srcImageView = srcImage.Factory(srcImage, overlapBBox, afwImage.PARENT, False) 

70 srcImageArray = srcImageView.array 

71 

72 isBadArray = np.isnan(srcImageArray) 

73 

74 destImageArray[:] = np.where(isBadArray, destImageArray, srcImageArray) 

75 numGoodPix = np.sum(np.logical_not(isBadArray)) 

76 return destImage, numGoodPix 

77 

78 

79def referenceCopyGoodPixelsMaskedImage(destImage, srcImage, badPixelMask): 

80 """Reference implementation of lsst.coadd.utils.copyGoodPixels for MaskedImages 

81 

82 Unlike lsst.coadd.utils.copyGoodPixels this one does not update the input destImage, 

83 but instead returns an updated copy 

84 

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) 

88 

89 Returns: 

90 - destImage: new destImage 

91 - numGoodPix: number of good pixels 

92 """ 

93 destImage = destImage.Factory(destImage, True) # make deep copy 

94 

95 overlapBBox = destImage.getBBox() 

96 overlapBBox.clip(srcImage.getBBox()) 

97 

98 if overlapBBox.isEmpty(): 

99 return (destImage, 0) 

100 

101 destImageView = destImage.Factory(destImage, overlapBBox, afwImage.PARENT, False) 

102 srcImageView = srcImage.Factory(srcImage, overlapBBox, afwImage.PARENT, False) 

103 

104 isBadArray = (srcImageView.mask.array & badPixelMask) != 0 

105 

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) 

111 

112 numGoodPix = np.sum(np.logical_not(isBadArray)) 

113 return destImage, numGoodPix 

114 

115 

116MaxMask = 0xFFFF 

117 

118 

119class CopyGoodPixelsTestCase(lsst.utils.tests.TestCase): 

120 """A test case for copyGoodPixels 

121 """ 

122 

123 def getSolidMaskedImage(self, bbox, val, badMask=0): 

124 afwDim = bbox.getDimensions() 

125 npShape = (afwDim[1], afwDim[0]) 

126 

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 

134 

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)) 

140 

141 afwDim = bbox.getDimensions() 

142 npShape = (afwDim[1], afwDim[0]) 

143 

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 

150 

151 def getRandomImage(self, bbox, nanSigma=0): 

152 """Get a randomly generated image 

153 """ 

154 afwDim = bbox.getDimensions() 

155 npShape = (afwDim[1], afwDim[0]) 

156 

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 

166 

167 def basicMaskedImageTest(self, srcImage, destImage, badMask): 

168 refDestImage, refNumGoodPix = referenceCopyGoodPixelsMaskedImage(destImage, srcImage, badMask) 

169 numGoodPix = coaddUtils.copyGoodPixels(destImage, srcImage, badMask) 

170 

171 self.assertEqual(numGoodPix, refNumGoodPix) 

172 

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 

180 

181 def basicImageTest(self, srcImage, destImage): 

182 refDestImage, refNumGoodPix = referenceCopyGoodPixelsImage(destImage, srcImage) 

183 numGoodPix = coaddUtils.copyGoodPixels(destImage, srcImage) 

184 

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 

192 

193 self.assertEqual(numGoodPix, refNumGoodPix) 

194 

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() 

200 

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) 

206 

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) 

213 

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() 

219 

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) 

225 

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) 

232 

233 

234class MemoryTester(lsst.utils.tests.MemoryTestCase): 

235 pass 

236 

237 

238def setup_module(module): 

239 lsst.utils.tests.init() 

240 

241 

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()