Coverage for tests/test_copyGoodPixels.py: 18%

139 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-01 02:54 -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# 

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

68 

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

70 srcImageArray = srcImageView.getArray() 

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 destImageArrayList = destImageView.getArrays() 

103 

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

105 srcImageArrayList = srcImageView.getArrays() 

106 

107 isBadArray = (srcImageArrayList[1] & badPixelMask) != 0 

108 

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 

115 

116 

117MaxMask = 0xFFFF 

118 

119 

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

121 """A test case for copyGoodPixels 

122 """ 

123 

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

125 afwDim = bbox.getDimensions() 

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

127 

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 

136 

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

142 

143 afwDim = bbox.getDimensions() 

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

145 

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 

153 

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

155 """Get a randomly generated image 

156 """ 

157 afwDim = bbox.getDimensions() 

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

159 

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 

169 

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

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

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

173 

174 self.assertEqual(numGoodPix, refNumGoodPix) 

175 

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 

183 

184 def basicImageTest(self, srcImage, destImage): 

185 refDestImage, refNumGoodPix = referenceCopyGoodPixelsImage(destImage, srcImage) 

186 numGoodPix = coaddUtils.copyGoodPixels(destImage, srcImage) 

187 

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 

195 

196 self.assertEqual(numGoodPix, refNumGoodPix) 

197 

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

203 

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) 

209 

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) 

216 

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

222 

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) 

228 

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) 

235 

236 

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

238 pass 

239 

240 

241def setup_module(module): 

242 lsst.utils.tests.init() 

243 

244 

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