Coverage for tests/test_statistics.py : 14%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of afw.
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 Statistics
25Run with:
26 python test_statistics.py
27or
28 pytest test_statistics.py
29"""
31import math
32import os
33import unittest
35import numpy as np
37import lsst.utils.tests
38import lsst.pex.exceptions
39import lsst.geom
40import lsst.afw.image as afwImage
41import lsst.afw.math as afwMath
42import lsst.afw.display as afwDisplay
43import lsst.pex.exceptions as pexExcept
45afwDisplay.setDefaultMaskTransparency(75)
47try:
48 afwdataDir = lsst.utils.getPackageDir("afwdata")
49except pexExcept.NotFoundError:
50 afwdataDir = None
52try:
53 type(display)
54except NameError:
55 display = False
58class StatisticsTestCase(lsst.utils.tests.TestCase):
59 """A test case for Statistics"""
61 clippedVariance3 = 0.9733369 # variance of an N(0, 1) Gaussian clipped at 3 sigma
63 def setUp(self):
64 w, h = 900, 1500
66 mean = 10.5 # requested mean
67 std = 1.0 # and standard deviation
69 self.images = []
70 # ImageI
71 np.random.seed(666)
72 isInt = True
73 image = afwImage.ImageI(lsst.geom.ExtentI(w, h))
74 image.array[:] = np.floor(np.random.normal(mean, std, (h, w)) + 0.5).astype(int)
76 # Note that the mean/median/std may not be quite equal to the requested values
77 self.images.append((image, isInt, np.mean(image.array), np.mean(image.array), np.std(image.array)))
79 # ImageF
80 np.random.seed(666)
81 isInt = False
82 image = afwImage.ImageF(lsst.geom.ExtentI(w, h))
83 image.array[:] = np.random.normal(mean, std, (h, w))
85 # Note that the mean/median/std may not be quite equal to the requested values
86 self.images.append((image, isInt, np.mean(image.array), np.median(image.array), np.std(image.array)))
88 @staticmethod
89 def delta(what, isInt):
90 # Return a tolerance for a test
91 if what == "mean":
92 return 4e-6
93 elif what == "meanclip":
94 return 4e-5
95 elif what == "median":
96 return 0.00022 if isInt else 0.00000075
98 def tearDown(self):
99 del self.images
101 def testDefaultGet(self):
102 """Test that we can get a single statistic without specifying it"""
103 for image, isInt, mean, median, std in self.images:
104 stats = afwMath.makeStatistics(image, afwMath.MEDIAN)
106 self.assertEqual(stats.getValue(), stats.getValue(afwMath.MEDIAN))
107 self.assertEqual(stats.getResult()[0], stats.getResult(afwMath.MEDIAN)[0])
108 #
109 stats = afwMath.makeStatistics(image, afwMath.MEDIAN | afwMath.ERRORS)
111 self.assertEqual(stats.getValue(), stats.getValue(afwMath.MEDIAN))
112 self.assertEqual(stats.getResult(), stats.getResult(afwMath.MEDIAN))
113 self.assertEqual(stats.getError(), stats.getError(afwMath.MEDIAN))
115 def tst():
116 stats.getValue()
117 stats = afwMath.makeStatistics(image, afwMath.MEDIAN | afwMath.MEAN)
118 self.assertRaises(lsst.pex.exceptions.InvalidParameterError, tst)
120 def testStats1(self):
121 for image, isInt, mean, median, std in self.images:
122 stats = afwMath.makeStatistics(image, afwMath.NPOINT | afwMath.STDEV | afwMath.MEAN | afwMath.SUM)
124 self.assertEqual(stats.getValue(afwMath.NPOINT), image.getWidth()*image.getHeight())
125 self.assertEqual(stats.getValue(afwMath.NPOINT)*stats.getValue(afwMath.MEAN),
126 stats.getValue(afwMath.SUM))
128 self.assertAlmostEqual(stats.getValue(afwMath.MEAN), mean, delta=self.delta("mean", isInt))
129 # didn't ask for error, so it's a NaN
130 self.assertTrue(np.isnan(stats.getError(afwMath.MEAN)))
131 self.assertAlmostEqual(stats.getValue(afwMath.STDEV), std, delta=0.000008)
133 def testStats2(self):
134 for image, isInt, mean, median, std in self.images:
135 stats = afwMath.makeStatistics(image, afwMath.STDEV | afwMath.MEAN | afwMath.ERRORS)
136 meanRes = stats.getResult(afwMath.MEAN)
137 sd = stats.getValue(afwMath.STDEV)
139 self.assertAlmostEqual(meanRes[0], mean, delta=self.delta("mean", isInt))
140 self.assertAlmostEqual(meanRes[1], sd/math.sqrt(image.getWidth()*image.getHeight()))
142 def testStats3(self):
143 for image, isInt, mean, median, std in self.images:
144 stats = afwMath.makeStatistics(image, afwMath.NPOINT)
146 def getMean():
147 stats.getValue(afwMath.MEAN)
149 self.assertRaises(lsst.pex.exceptions.InvalidParameterError, getMean)
151 def testStatsZebra(self):
152 """Add 1 to every other row"""
153 for image, isInt, mean, median, std in self.images:
154 image2 = image.clone()
155 #
156 # Add 1 to every other row, so the variance is increased by 1/4
157 #
158 self.assertEqual(image2.getHeight() % 2, 0)
159 width = image2.getWidth()
160 for y in range(1, image2.getHeight(), 2):
161 sim = image2[lsst.geom.Box2I(lsst.geom.Point2I(0, y), lsst.geom.Extent2I(width, 1))]
162 sim += 1
164 if display:
165 afwDisplay.Display(frame=0).mtv(image, "Image 1")
166 afwDisplay.Display(frame=1).mtv(image2, "Image 2 (var inc by 1/4)")
168 stats = afwMath.makeStatistics(image2,
169 afwMath.NPOINT | afwMath.STDEV | afwMath.MEAN | afwMath.ERRORS)
170 meanRes = stats.getResult(afwMath.MEAN)
171 n = stats.getValue(afwMath.NPOINT)
172 sd = stats.getValue(afwMath.STDEV)
174 self.assertAlmostEqual(meanRes[0], mean + 0.5, delta=self.delta("mean", isInt))
175 self.assertAlmostEqual(sd, np.hypot(std, 1/math.sqrt(4.0)*math.sqrt(n/(n - 1))),
176 delta=0.00011)
177 self.assertAlmostEqual(meanRes[1], sd/math.sqrt(image2.getWidth()*image2.getHeight()), 10)
179 meanSquare = afwMath.makeStatistics(image2, afwMath.MEANSQUARE).getValue()
180 self.assertAlmostEqual(meanSquare, 0.5*(mean**2 + (mean + 1)**2) + std**2,
181 delta=0.00025 if isInt else 0.00006)
183 def testStatsStdevclip(self):
184 """Test STDEVCLIP; cf. #611"""
185 for image, isInt, mean, median, std in self.images:
186 image2 = image.clone()
188 stats = afwMath.makeStatistics(image2, afwMath.STDEVCLIP | afwMath.NPOINT | afwMath.SUM)
189 self.assertAlmostEqual(stats.getValue(afwMath.STDEVCLIP), math.sqrt(self.clippedVariance3)*std,
190 delta=0.0015)
191 #
192 # Check we get the correct sum even when clipping
193 #
194 self.assertEqual(
195 stats.getValue(afwMath.NPOINT)*afwMath.makeStatistics(image2, afwMath.MEAN).getValue(),
196 stats.getValue(afwMath.SUM))
198 def testMedian(self):
199 """Test the median code"""
200 for image, isInt, mean, median, std in self.images:
201 med = afwMath.makeStatistics(image, afwMath.MEDIAN).getValue()
202 self.assertAlmostEqual(med, median, delta=self.delta("median", isInt))
204 values = [1.0, 2.0, 3.0, 2.0]
205 self.assertEqual(afwMath.makeStatistics(values, afwMath.MEDIAN).getValue(), 2.0)
207 def testIqrange(self):
208 """Test the inter-quartile range"""
209 for image, isInt, mean, median, std in self.images:
210 iqr = afwMath.makeStatistics(image, afwMath.IQRANGE).getValue()
211 # pretty loose constraint for isInt; probably because the distribution
212 # isn't very Gaussian with the added rounding to integer values
213 self.assertAlmostEqual(iqr, std/0.741301109252802, delta=0.063 if isInt else 0.00011)
215 def testMeanClip(self):
216 """Test the clipped mean"""
218 sctrl = afwMath.StatisticsControl()
219 sctrl.setNumSigmaClip(6)
221 for image, isInt, mean, median, std in self.images:
222 stats = afwMath.makeStatistics(image, afwMath.MEANCLIP | afwMath.NCLIPPED, sctrl)
223 self.assertAlmostEqual(stats.getValue(afwMath.MEANCLIP), mean, delta=self.delta("mean", isInt))
224 self.assertEqual(stats.getValue(afwMath.NCLIPPED), 0)
226 def testVarianceClip(self):
227 """Test the 3-sigma clipped standard deviation and variance"""
228 for image, isInt, mean, median, std in self.images:
229 delta = 0.0006 if isInt else 0.0014
230 stdevClip = afwMath.makeStatistics(image, afwMath.STDEVCLIP).getValue()
231 self.assertAlmostEqual(stdevClip, math.sqrt(self.clippedVariance3)*std, delta=delta)
233 varianceClip = afwMath.makeStatistics(image, afwMath.VARIANCECLIP).getValue()
234 self.assertAlmostEqual(varianceClip, self.clippedVariance3*std**2, delta=2*delta)
236 def _testBadValue(self, badVal):
237 """Test that we can handle an instance of `badVal` in the data correctly
239 Note that we only test ImageF here (as ImageI can't contain a NaN)
240 """
241 mean = self.images[0][1]
242 x, y = 10, 10
243 for useImage in [True, False]:
244 if useImage:
245 image = afwImage.ImageF(100, 100)
246 image.set(mean)
247 image[x, y] = badVal
248 else:
249 image = afwImage.MaskedImageF(100, 100)
250 image.set(mean, 0x0, 1.0)
251 image[x, y] = (badVal, 0x0, 1.0)
253 self.assertEqual(afwMath.makeStatistics(image, afwMath.MAX).getValue(), mean)
254 self.assertEqual(afwMath.makeStatistics(image, afwMath.MEAN).getValue(), mean)
256 sctrl = afwMath.StatisticsControl()
258 sctrl.setNanSafe(False)
259 self.assertFalse(np.isfinite(afwMath.makeStatistics(image, afwMath.MAX, sctrl).getValue()))
260 self.assertFalse(np.isfinite(afwMath.makeStatistics(image, afwMath.MEAN, sctrl).getValue()))
262 def testMaxWithNan(self):
263 """Test that we can handle NaNs correctly"""
264 self._testBadValue(np.nan)
266 def testMaxWithInf(self):
267 """Test that we can handle infinities correctly"""
268 self._testBadValue(np.inf)
270 @unittest.skipIf(afwdataDir is None, "afwdata not setup")
271 def testSampleImageStats(self):
272 """ Compare our results to known values in test data """
274 imgfiles = []
275 imgfiles.append("v1_i1_g_m400_s20_f.fits")
276 imgfiles.append("v1_i1_g_m400_s20_u16.fits")
277 imgfiles.append("v1_i2_g_m400_s20_f.fits")
278 imgfiles.append("v1_i2_g_m400_s20_u16.fits")
279 imgfiles.append("v2_i1_p_m9_f.fits")
280 imgfiles.append("v2_i1_p_m9_u16.fits")
281 imgfiles.append("v2_i2_p_m9_f.fits")
282 imgfiles.append("v2_i2_p_m9_u16.fits")
284 afwdataDir = os.getenv("AFWDATA_DIR")
286 for imgfile in imgfiles:
288 imgPath = os.path.join(afwdataDir, "Statistics", imgfile)
290 # get the image and header
291 dimg = afwImage.DecoratedImageF(imgPath)
292 fitsHdr = dimg.getMetadata()
294 # get the true values of the mean and stdev
295 trueMean = fitsHdr.getAsDouble("MEANCOMP")
296 trueStdev = fitsHdr.getAsDouble("SIGCOMP")
298 # measure the mean and stdev with the Statistics class
299 img = dimg.getImage()
300 statobj = afwMath.makeStatistics(img, afwMath.MEAN | afwMath.STDEV)
301 mean = statobj.getValue(afwMath.MEAN)
302 stdev = statobj.getValue(afwMath.STDEV)
304 # print trueMean, mean, trueStdev, stdev
305 self.assertAlmostEqual(mean, trueMean, 8)
306 self.assertAlmostEqual(stdev, trueStdev, 8)
308 def testStatisticsRamp(self):
309 """ Tests Statistics on a 'ramp' (image with constant gradient) """
311 nx = 101
312 ny = 64
313 img = afwImage.ImageF(lsst.geom.Extent2I(nx, ny))
315 z0 = 10.0
316 dzdx = 1.0
317 mean = z0 + (nx//2)*dzdx
318 stdev = 0.0
319 for y in range(ny):
320 for x in range(nx):
321 z = z0 + dzdx*x
322 img[x, y] = z
323 stdev += (z - mean)*(z - mean)
325 stdev = math.sqrt(stdev/(nx*ny - 1))
327 stats = afwMath.makeStatistics(
328 img, afwMath.NPOINT | afwMath.STDEV | afwMath.MEAN)
329 testmean = stats.getValue(afwMath.MEAN)
330 teststdev = stats.getValue(afwMath.STDEV)
332 self.assertEqual(stats.getValue(afwMath.NPOINT), nx*ny)
333 self.assertEqual(testmean, mean)
334 self.assertAlmostEqual(teststdev, stdev)
336 stats = afwMath.makeStatistics(
337 img, afwMath.STDEV | afwMath.MEAN | afwMath.ERRORS)
338 mean, meanErr = stats.getResult(afwMath.MEAN)
339 sd = stats.getValue(afwMath.STDEV)
341 self.assertEqual(mean, img[nx//2, ny//2])
342 self.assertEqual(meanErr, sd/math.sqrt(img.getWidth()*img.getHeight()))
344 # ===============================================================================
345 # sjb code for percentiles and clipped stats
347 stats = afwMath.makeStatistics(img, afwMath.MEDIAN)
348 self.assertEqual(z0 + dzdx*(nx - 1)/2.0, stats.getValue(afwMath.MEDIAN))
350 stats = afwMath.makeStatistics(img, afwMath.IQRANGE)
351 self.assertEqual(dzdx*(nx - 1)/2.0, stats.getValue(afwMath.IQRANGE))
353 stats = afwMath.makeStatistics(img, afwMath.MEANCLIP)
354 self.assertEqual(z0 + dzdx*(nx - 1)/2.0, stats.getValue(afwMath.MEANCLIP))
356 def testMask(self):
357 mask = afwImage.Mask(lsst.geom.Extent2I(10, 10))
358 mask.set(0x0)
360 mask[1, 1] = 0x10
361 mask[3, 1] = 0x08
362 mask[5, 4] = 0x08
363 mask[4, 5] = 0x02
365 stats = afwMath.makeStatistics(mask, afwMath.SUM | afwMath.NPOINT)
366 self.assertEqual(mask.getWidth()*mask.getHeight(),
367 stats.getValue(afwMath.NPOINT))
368 self.assertEqual(0x1a, stats.getValue(afwMath.SUM))
370 def tst():
371 afwMath.makeStatistics(mask, afwMath.MEAN)
372 self.assertRaises(lsst.pex.exceptions.InvalidParameterError, tst)
374 def testTicket1025(self):
375 """
376 Ticket #1025 reported that the Statistics median was getting '3' as the median of [1,2,3,2]
377 it was caused by an off-by-one error in the implementation
378 """
380 # check the exact example in the ticket
381 values = [1.0, 2.0, 3.0, 2.0]
382 self.assertEqual(afwMath.makeStatistics(values, afwMath.MEDIAN).getValue(), 2)
383 self.assertEqual(afwMath.makeStatistics(sorted(values), afwMath.MEDIAN).getValue(), 2)
385 # check some other possible ways it could show up
386 values = list(range(10))
387 self.assertEqual(afwMath.makeStatistics(values, afwMath.MEDIAN).getValue(), 4.5)
388 values = list(range(11))
389 self.assertEqual(afwMath.makeStatistics(values, afwMath.MEDIAN).getValue(), 5.0)
391 def testTicket1123(self):
392 """
393 Ticket #1123 reported that the Statistics stack routine throws an exception
394 when all pixels in a stack are masked. Returning a NaN pixel in the stack is preferred
395 """
397 mean = self.images[0][1]
399 ctrl = afwMath.StatisticsControl()
400 ctrl.setAndMask(~0x0)
402 mimg = afwImage.MaskedImageF(lsst.geom.Extent2I(10, 10))
403 mimg.set([mean, 0x1, mean])
405 # test the case with no valid pixels ... both mean and stdev should be
406 # nan
407 stat = afwMath.makeStatistics(mimg, afwMath.MEAN | afwMath.STDEV, ctrl)
408 mean = stat.getValue(afwMath.MEAN)
409 stdev = stat.getValue(afwMath.STDEV)
410 self.assertNotEqual(mean, mean) # NaN does not equal itself
411 self.assertNotEqual(stdev, stdev) # NaN does not equal itself
413 # test the case with one valid pixel ... mean is ok, but stdev should
414 # still be nan
415 mimg.getMask()[1, 1] = 0x0
416 stat = afwMath.makeStatistics(mimg, afwMath.MEAN | afwMath.STDEV, ctrl)
417 mean = stat.getValue(afwMath.MEAN)
418 stdev = stat.getValue(afwMath.STDEV)
419 self.assertEqual(mean, mean)
420 self.assertNotEqual(stdev, stdev) # NaN does not equal itself
422 # test the case with two valid pixels ... both mean and stdev are ok
423 mimg.getMask()[1, 2] = 0x0
424 stat = afwMath.makeStatistics(mimg, afwMath.MEAN | afwMath.STDEV, ctrl)
425 mean = stat.getValue(afwMath.MEAN)
426 stdev = stat.getValue(afwMath.STDEV)
427 self.assertEqual(mean, mean)
428 self.assertEqual(stdev, 0.0)
430 def testTicket1125(self):
431 """Ticket 1125 reported that the clipped routines were aborting when called with no valid pixels. """
433 mean = self.images[0][1]
435 mimg = afwImage.MaskedImageF(lsst.geom.Extent2I(10, 10))
436 mimg.set([mean, 0x1, mean])
438 ctrl = afwMath.StatisticsControl()
439 ctrl.setAndMask(~0x0)
441 # test the case with no valid pixels ... try MEANCLIP and STDEVCLIP
442 stat = afwMath.makeStatistics(
443 mimg, afwMath.MEANCLIP | afwMath.STDEVCLIP, ctrl)
444 mean = stat.getValue(afwMath.MEANCLIP)
445 stdev = stat.getValue(afwMath.STDEVCLIP)
446 self.assertNotEqual(mean, mean) # NaN does not equal itself
447 self.assertNotEqual(stdev, stdev) # NaN does not equal itself
449 def testWeightedSum(self):
450 ctrl = afwMath.StatisticsControl()
451 mi = afwImage.MaskedImageF(lsst.geom.Extent2I(10, 10))
452 mi.getImage().set(1.0)
453 mi.getVariance().set(0.1)
455 stats = afwMath.makeStatistics(mi, afwMath.SUM, ctrl)
456 self.assertEqual(stats.getValue(afwMath.SUM), 100.0)
458 ctrl.setWeighted(True)
459 weighted = afwMath.makeStatistics(mi, afwMath.SUM, ctrl)
460 # precision at "4 places" as images are floats
461 # ... variance = 0.1 is stored as 0.100000001
462 self.assertAlmostEqual(weighted.getValue(afwMath.SUM), 1000.0, 4)
464 def testWeightedSum2(self):
465 """Test using a weight image separate from the variance plane"""
466 weight, mean = 0.1, 1.0
468 ctrl = afwMath.StatisticsControl()
469 mi = afwImage.MaskedImageF(lsst.geom.Extent2I(10, 10))
470 npix = 10*10
471 mi.getImage().set(mean)
472 mi.getVariance().set(np.nan)
474 weights = afwImage.ImageF(mi.getDimensions())
475 weights.set(weight)
477 stats = afwMath.makeStatistics(mi, afwMath.SUM, ctrl)
478 self.assertEqual(stats.getValue(afwMath.SUM), mean*npix)
480 weighted = afwMath.makeStatistics(mi, weights, afwMath.SUM, ctrl)
481 # precision at "4 places" as images are floats
482 # ... variance = 0.1 is stored as 0.100000001
483 self.assertAlmostEqual(weighted.getValue(afwMath.SUM), mean*npix*weight, 4)
485 def testErrorsFromVariance(self):
486 """Test that we can estimate the errors from the incoming variances"""
487 weight, mean, variance = 0.1, 1.0, 10.0
489 ctrl = afwMath.StatisticsControl()
490 mi = afwImage.MaskedImageF(lsst.geom.Extent2I(10, 10))
491 npix = 10*10
492 mi.getImage().set(mean)
493 mi.getVariance().set(variance)
495 weights = afwImage.ImageF(mi.getDimensions())
496 weights.set(weight)
498 ctrl.setCalcErrorFromInputVariance(True)
499 weighted = afwMath.makeStatistics(mi, weights,
500 afwMath.MEAN | afwMath.MEANCLIP | afwMath.SUM | afwMath.ERRORS,
501 ctrl)
503 self.assertAlmostEqual(weighted.getValue(afwMath.SUM)/(npix*mean*weight), 1)
504 self.assertAlmostEqual(weighted.getValue(afwMath.MEAN), mean)
505 self.assertAlmostEqual(weighted.getError(afwMath.MEAN)**2, variance/npix)
506 self.assertAlmostEqual(weighted.getError(afwMath.MEANCLIP)**2, variance/npix)
508 def testMeanClipSingleValue(self):
509 """Verify that the clipped mean doesn't not return NaN for a single value."""
510 sctrl = afwMath.StatisticsControl()
511 sctrl.setNumSigmaClip(6)
513 for image, isInt, mean, median, std in self.images:
514 stats = afwMath.makeStatistics(image, afwMath.MEANCLIP | afwMath.NCLIPPED, sctrl)
515 self.assertAlmostEqual(stats.getValue(afwMath.MEANCLIP), mean,
516 delta=self.delta("meanclip", isInt))
517 self.assertEqual(stats.getValue(afwMath.NCLIPPED), 0)
519 # this bug was caused by the iterative nature of the MEANCLIP.
520 # With only one point, the sample variance returns NaN to avoid a divide by zero error
521 # Thus, on the second iteration, the clip width (based on _variance) is NaN and corrupts
522 # all further calculations.
523 img = afwImage.ImageF(lsst.geom.Extent2I(1, 1))
524 img.set(0)
525 stats = afwMath.makeStatistics(img, afwMath.MEANCLIP | afwMath.NCLIPPED)
526 self.assertEqual(stats.getValue(afwMath.MEANCLIP), 0)
527 self.assertEqual(stats.getValue(afwMath.NCLIPPED), 0)
529 def testMismatch(self):
530 """Test that we get an exception when there's a size mismatch"""
531 scale = 5
532 for image, isInt, mean, median, std in self.images:
533 dims = image.getDimensions()
534 mask = afwImage.Mask(dims*scale)
535 mask.set(0xFF)
536 ctrl = afwMath.StatisticsControl()
537 ctrl.setAndMask(0xFF)
538 # If it didn't raise, this would result in a NaN (the image data is
539 # completely masked).
540 self.assertRaises(lsst.pex.exceptions.InvalidParameterError, afwMath.makeStatistics,
541 image, mask, afwMath.MEDIAN, ctrl)
542 subMask = afwImage.Mask(mask, lsst.geom.Box2I(lsst.geom.Point2I(dims*(scale - 1)), dims))
543 subMask.set(0)
544 # Using subMask is successful.
545 self.assertAlmostEqual(afwMath.makeStatistics(image, subMask, afwMath.MEDIAN, ctrl).getValue(),
546 median, delta=self.delta("median", isInt))
548 def testClipping(self):
549 """Test that clipping statistics work
551 Insert a single bad pixel; it should be clipped.
552 """
553 sctrl = afwMath.StatisticsControl()
554 sctrl.setNumSigmaClip(10)
556 for image, isInt, mean, median, std in self.images:
557 nval = 1000*mean
558 if isInt:
559 nval = int(nval)
560 image[0, 0] = nval
562 stats = afwMath.makeStatistics(image, afwMath.MEANCLIP | afwMath.NCLIPPED | afwMath.NPOINT, sctrl)
563 self.assertAlmostEqual(stats.getValue(afwMath.MEANCLIP), mean,
564 delta=self.delta("meanclip", isInt))
565 self.assertEqual(stats.getValue(afwMath.NCLIPPED), 1)
566 self.assertEqual(stats.getValue(afwMath.NPOINT), image.getBBox().getArea())
568 def testNMasked(self):
569 """Test that NMASKED works"""
570 maskVal = 0xBE
571 ctrl = afwMath.StatisticsControl()
572 ctrl.setAndMask(maskVal)
573 for image, isInt, mean, median, std in self.images:
574 mask = afwImage.Mask(image.getBBox())
575 mask.set(0)
576 self.assertEqual(afwMath.makeStatistics(image, mask, afwMath.NMASKED, ctrl).getValue(), 0)
577 mask[1, 1] = maskVal
578 self.assertEqual(afwMath.makeStatistics(image, mask, afwMath.NMASKED, ctrl).getValue(), 1)
581class TestMemory(lsst.utils.tests.MemoryTestCase):
582 pass
585def setup_module(module):
586 lsst.utils.tests.init()
589if __name__ == "__main__": 589 ↛ 590line 589 didn't jump to line 590, because the condition on line 589 was never true
590 lsst.utils.tests.init()
591 unittest.main()