def testTicket1681OffByOne(self): if False: # doesn't seem to actually test anything, and writes b?im.fits im = afwImage.ImageF(40, 40) im.set(5, 6, 100) nx, ny = im.getWidth() // 2, im.getHeight() // 2 print nx, ny bctrl = afwMath.BackgroundControl("LINEAR", nx, ny) bctrl.setStatisticsProperty(afwMath.MEAN) bkd = afwMath.makeBackground(im, bctrl) bim = bkd.getImageF() im.writeFits("im.fits") bim.writeFits("bim.fits")
def testApproximate(self): """Test I/O for BackgroundLists with Approximate""" # approx and interp should be very close, but not the same img = self.getParabolaImage(256, 256) # try regular interpolated image (the default) bgCtrl = afwMath.BackgroundControl(6, 6) bgCtrl.setInterpStyle(afwMath.Interpolate.AKIMA_SPLINE) bgCtrl.setUndersampleStyle(afwMath.REDUCE_INTERP_ORDER) bkgd = afwMath.makeBackground(img, bgCtrl) interpImage = bkgd.getImageF() with lsst.utils.tests.getTempFilePath("_bgi.fits") as bgiFile, \ lsst.utils.tests.getTempFilePath("_bga.fits") as bgaFile: bglInterp = afwMath.BackgroundList() bglInterp.append(bkgd) bglInterp.writeFits(bgiFile) # try an approx background approxStyle = afwMath.ApproximateControl.CHEBYSHEV approxOrder = 2 actrl = afwMath.ApproximateControl(approxStyle, approxOrder) bkgd.getBackgroundControl().setApproximateControl(actrl) approxImage = bkgd.getImageF() bglApprox = afwMath.BackgroundList() bglApprox.append(bkgd) bglApprox.writeFits(bgaFile) # take a difference and make sure the two are very similar interpNp = interpImage.getArray() diff = np.abs(interpNp - approxImage.getArray()) / interpNp # the image and interp/approx parameters are chosen so these limits # will be greater than machine precision for float. The two methods # should be measurably different (so we know we're not just getting the # same thing from the getImage() method. But they should be very close # since they're both doing the same sort of thing. tolSame = 1.0e-3 # should be the same to this order tolDiff = 1.0e-4 # should be different here self.assertLess(diff.max(), tolSame) self.assertGreater(diff.max(), tolDiff) # now see if we can reload them from files and get the same images we wrote interpImage2 = afwMath.BackgroundList().readFits( bgiFile).getImage() approxImage2 = afwMath.BackgroundList().readFits( bgaFile).getImage() idiff = interpImage.getArray() - interpImage2.getArray() adiff = approxImage.getArray() - approxImage2.getArray() self.assertEqual(idiff.max(), 0.0) self.assertEqual(adiff.max(), 0.0)
def testgetPixel(self): """Tests basic functionality of getPixel() method (floats)""" xcen, ycen = 50, 100 bgCtrl = afwMath.BackgroundControl(10, 10) bgCtrl.setNxSample(5) bgCtrl.setNySample(5) bgCtrl.getStatisticsControl().setNumIter(3) bgCtrl.getStatisticsControl().setNumSigmaClip(3) back = afwMath.makeBackground(self.image, bgCtrl) self.assertEqual( afwMath.cast_BackgroundMI(back).getPixel(xcen, ycen), self.val)
def flattenBackground(im, nx=2, ny=2, scale=False): """Fit and subtract an nx*ny background model""" bctrl = afwMath.BackgroundControl(nx, ny) bkgd = afwMath.makeBackground(im, bctrl).getImageF(afwMath.Interpolate.LINEAR) mean = np.mean(bkgd.getArray()) im -= bkgd im += float(mean) if scale: im /= mean
def crossCorrelate(maskedimage1, maskedimage2, maxLag, sigma, binsize): """ Calculate the correlation coefficients. """ sctrl = afwMath.StatisticsControl() sctrl.setNumSigmaClip(sigma) # Diff the images. diff = maskedimage1.clone() diff -= maskedimage2.getImage() # Subtract background. nx = diff.getWidth()//binsize ny = diff.getHeight()//binsize bctrl = afwMath.BackgroundControl(nx, ny, sctrl, afwMath.MEANCLIP) bkgd = afwMath.makeBackground(diff, bctrl) bgImg = bkgd.getImageF(afwMath.Interpolate.CUBIC_SPLINE, afwMath.REDUCE_INTERP_ORDER) diff -= bgImg # Measure the correlations x0, y0 = diff.getXY0() width, height = diff.getDimensions() bbox_extent = lsstGeom.Extent2I(width - maxLag, height - maxLag) bbox = lsstGeom.Box2I(lsstGeom.Point2I(x0, y0), bbox_extent) dim0 = diff[bbox].clone() dim0 -= afwMath.makeStatistics(dim0, afwMath.MEANCLIP, sctrl).getValue() xcorr = np.zeros((maxLag + 1, maxLag + 1), dtype=np.float64) xcorr_err = np.zeros((maxLag + 1, maxLag + 1), dtype=np.float64) for xlag in range(maxLag + 1): for ylag in range(maxLag + 1): bbox_lag = lsstGeom.Box2I(lsstGeom.Point2I(x0 + xlag, y0 + ylag), bbox_extent) dim_xy = diff[bbox_lag].clone() dim_xy -= afwMath.makeStatistics(dim_xy, afwMath.MEANCLIP, sctrl).getValue() dim_xy *= dim0 xcorr[xlag, ylag] = afwMath.makeStatistics( dim_xy, afwMath.MEANCLIP, sctrl).getValue() dim_xy_array = dim_xy.getImage().getArray().flatten()/xcorr[0][0] N = len(dim_xy_array.flatten()) if xlag != 0 and ylag != 0: f = (1+xcorr[xlag, ylag]/xcorr[0][0]) / \ (1-xcorr[xlag, ylag]/xcorr[0][0]) xcorr_err[xlag, ylag] = ( np.std(dim_xy_array)/np.sqrt(N))*np.sqrt(f) else: xcorr_err[xlag, ylag] = 0 return xcorr, xcorr_err
def get_fp_pixels(ccd, amp, nsig=4, bg_reg=(10, 10), npix_range=(5, 20)): """ Return a numpy record array with rows of the 9 pixel values around the peaks of Fe55 clusters. The footprint threshold is nsig*stdevclip + median, bg_reg is the NxM local background region, and the number of pixels per footprint is restricted to be within npix_range. """ # Background subtraction using a background image based on the # local background levels. bg_ctrl = afwMath.BackgroundControl(bg_reg[0], bg_reg[1], ccd.stat_ctrl) image = ccd[amp] image -= afwMath.makeBackground(ccd[amp], bg_ctrl).getImageF() # Set the footprint threshold. stats = afwMath.makeStatistics(image, afwMath.MEDIAN | afwMath.STDEVCLIP, ccd.stat_ctrl) threshold = afwDetect.Threshold(nsig * stats.getValue(afwMath.STDEVCLIP) + stats.getValue(afwMath.MEDIAN)) # Gather the data for the record array object. This includes the # amplifier number, the coordinates of the peak pixel (x0, y0), # the 3x3 pixels centered on (x0, y0), and the sum of ADU values # over the footprint. imarr = image.getImage().getArray() data = [] for fp in afwDetect.FootprintSet(image, threshold).getFootprints(): if fp.getArea() < npix_range[0] or npix_range[1] < fp.getArea(): continue # Get peak coordinates and p0-p8 values peaks = [pk for pk in fp.getPeaks()] if len(peaks) > 1: continue x0, y0 = peaks[0].getIx(), peaks[0].getIy() row = [amp, x0, y0] + list(imarr[y0 - 1:y0 + 2, x0 - 1:x0 + 2].flatten()) if len(row) != 12: # Skip if there are too few p0-p8 values (e.g., cluster is # on the imaging section edge). continue # Sum over pixels in the footprint. dn_sum = 0 spans = fp.getSpans() for span in spans: y = span.getY() for x in range(span.getX0(), span.getX1() + 1): dn_sum += imarr[y][x] row.append(dn_sum) data.append(row) names = 'amp x y'.split() + ['p%i' % i for i in range(9)] + ['DN_sum'] return np.rec.array(data, names=names)
def simpleBackground(image): binsize = 128 nx = int(image.getWidth() / binsize) + 1 ny = int(image.getHeight() / binsize) + 1 bctrl = afwMath.BackgroundControl(nx, ny) bkgd = afwMath.makeBackground(image, bctrl) statsImage = afwMath.cast_BackgroundMI(bkgd).getStatsImage() image -= bkgd.getImageF(afwMath.Interpolate.NATURAL_SPLINE) return bkgd
def testTicket1781(self): """Test an unusual-sized image""" nx = 526 ny = 154 parabimg = self.getParabolaImage(nx, ny) bctrl = afwMath.BackgroundControl(afwMath.Interpolate.CUBIC_SPLINE) bctrl.setNxSample(16) bctrl.setNySample(4) bctrl.getStatisticsControl().setNumSigmaClip(10.0) bctrl.getStatisticsControl().setNumIter(1) afwMath.makeBackground(parabimg, bctrl)
def testBackgroundTestImages(self): imginfolist = [] #imginfolist.append( ["v1_i1_g_m400_s20_f.fits", 400.05551471441612] ) # cooked to known value #imginfolist.append( ["v1_i1_g_m400_s20_f.fits", 400.00295902395123] ) # cooked to known value #imginfolist.append( ["v1_i1_g_m400_s20_f.fits", 400.08468385712251] ) # cooked to known value #imginfolist.append( ["v1_i1_g_m400_s20_f.fits", 400.00305806663295] ) # cooked to known value #imginfolist.append( ["v1_i1_g_m400_s20_f.fits", 400.0035102188698] ) # cooked to known value imginfolist.append( ["v1_i1_g_m400_s20_f.fits", 399.9912966583894] ) # cooked to known value #imgfiles.append("v1_i1_g_m400_s20_u16.fits") #imgfiles.append("v1_i2_g_m400_s20_f.fits" #imgfiles.append("v1_i2_g_m400_s20_u16.fits") #imgfiles.append("v2_i1_p_m9_f.fits") #imgfiles.append("v2_i1_p_m9_u16.fits") #imgfiles.append("v2_i2_p_m9_f.fits") #imgfiles.append("v2_i2_p_m9_u16.fits") for imginfo in imginfolist: imgfile, centerValue = imginfo imgPath = os.path.join(AfwdataDir, "Statistics", imgfile) # get the image and header dimg = afwImage.DecoratedImageF(imgPath) img = dimg.getImage() fitsHdr = dimg.getMetadata() # the FITS header # get the True values of the mean and stdev reqMean = fitsHdr.getAsDouble("MEANREQ") reqStdev = fitsHdr.getAsDouble("SIGREQ") naxis1 = img.getWidth() naxis2 = img.getHeight() # create a background control object bctrl = afwMath.BackgroundControl(afwMath.Interpolate.AKIMA_SPLINE) bctrl.setNxSample(5) bctrl.setNySample(5) # run the background constructor and call the getPixel() and getImage() functions. backobj = afwMath.makeBackground(img, bctrl) pixPerSubimage = img.getWidth()*img.getHeight()/(bctrl.getNxSample()*bctrl.getNySample()) stdevInterp = reqStdev/math.sqrt(pixPerSubimage) # test getPixel() testval = afwMath.cast_BackgroundMI(backobj).getPixel(naxis1//2, naxis2//2) self.assertAlmostEqual(testval/centerValue, 1, places=7) self.assertTrue( abs(testval - reqMean) < 2*stdevInterp ) # test getImage() by checking the center pixel bimg = backobj.getImageF() testImgval = bimg.get(naxis1//2, naxis2//2) self.assertTrue( abs(testImgval - reqMean) < 2*stdevInterp )
def getBackground(image, backgroundConfig, nx=0, ny=0, algorithm=None): """ Make a new Exposure which is exposure - background """ backgroundConfig.validate() if not nx: nx = image.getWidth() // backgroundConfig.binSize + 1 if not ny: ny = image.getHeight() // backgroundConfig.binSize + 1 displayBackground = lsstDebug.Info(__name__).displayBackground if displayBackground: import itertools ds9.mtv(image, frame=1) xPosts = numpy.rint( numpy.linspace(0, image.getWidth() + 1, num=nx, endpoint=True)) yPosts = numpy.rint( numpy.linspace(0, image.getHeight() + 1, num=ny, endpoint=True)) with ds9.Buffering(): for (xMin, xMax), (yMin, yMax) in itertools.product( zip(xPosts[:-1], xPosts[1:]), zip(yPosts[:-1], yPosts[1:])): ds9.line([(xMin, yMin), (xMin, yMax), (xMax, yMax), (xMax, yMin), (xMin, yMin)], frame=1) sctrl = afwMath.StatisticsControl() sctrl.setAndMask( reduce(lambda x, y: x | image.getMask().getPlaneBitMask(y), backgroundConfig.ignoredPixelMask, 0x0)) sctrl.setNanSafe(backgroundConfig.isNanSafe) pl = pexLogging.Debug("meas.utils.sourceDetection.getBackground") pl.debug( 3, "Ignoring mask planes: %s" % ", ".join(backgroundConfig.ignoredPixelMask)) if not algorithm: algorithm = backgroundConfig.algorithm bctrl = afwMath.BackgroundControl(algorithm, nx, ny, backgroundConfig.undersampleStyle, sctrl, backgroundConfig.statisticsProperty) if backgroundConfig.useApprox: actrl = afwMath.ApproximateControl( afwMath.ApproximateControl.CHEBYSHEV, backgroundConfig.approxOrder) bctrl.setApproximateControl(actrl) return afwMath.makeBackground(image, bctrl)
def testTicket987(self): """This code used to abort; so the test is that it doesn't""" imagePath = os.path.join(AfwdataDir, "DC3a-Sim", "sci", "v5-e0", "v5-e0-c011-a00.sci.fits") mimg = afwImage.MaskedImageF(imagePath) binsize = 512 nx = int(mimg.getWidth() / binsize) + 1 ny = int(mimg.getHeight() / binsize) + 1 bctrl = afwMath.BackgroundControl(nx, ny) image = mimg.getImage() backobj = afwMath.makeBackground(image, bctrl) # note: by default undersampleStyle is THROW_EXCEPTION image -= backobj.getImageF("NATURAL_SPLINE", "REDUCE_INTERP_ORDER")
def testBackgroundListIO(self): """Test I/O for BackgroundLists""" bgCtrl = afwMath.BackgroundControl(10, 10) interpStyle = afwMath.Interpolate.AKIMA_SPLINE undersampleStyle = afwMath.REDUCE_INTERP_ORDER approxOrderX = 6 approxOrderY = 6 im = self.image.Factory(self.image, self.image.getBBox(afwImage.PARENT)) arr = im.getArray() arr += numpy.random.normal(size=(im.getHeight(), im.getWidth())) for astyle in afwMath.ApproximateControl.UNKNOWN, afwMath.ApproximateControl.CHEBYSHEV: actrl = afwMath.ApproximateControl(astyle, approxOrderX) bgCtrl.setApproximateControl(actrl) backgroundList = afwMath.BackgroundList() backImage = afwImage.ImageF(im.getDimensions()) for i in range(2): bkgd = afwMath.makeBackground(im, bgCtrl) if i == 0: # no need to call getImage backgroundList.append((bkgd, interpStyle, undersampleStyle, astyle, approxOrderX, approxOrderY)) else: backgroundList.append( bkgd) # Relies on having called getImage; deprecated backImage += bkgd.getImageF(interpStyle, undersampleStyle) fileName = "backgroundList.fits" try: backgroundList.writeFits(fileName) backgrounds = afwMath.BackgroundList.readFits(fileName) finally: if os.path.exists(fileName): os.unlink(fileName) img = backgrounds.getImage() # # Check that the read-back image is identical to that generated from the backgroundList # round-tripped to disk # backImage -= img self.assertEqual(np.min(backImage.getArray()), 0.0) self.assertEqual(np.max(backImage.getArray()), 0.0)
def testAdjustLevel(self): """Test that we can adjust a background level """ sky = 100 im = afwImage.ImageF(40, 40); im.set(sky); nx, ny = im.getWidth()//2, im.getHeight()//2 bctrl = afwMath.BackgroundControl("LINEAR", nx, ny) bkd = afwMath.makeBackground(im, bctrl) self.assertEqual(afwMath.makeStatistics(bkd.getImageF(), afwMath.MEAN).getValue(), sky) delta = 123 bkd += delta self.assertEqual(afwMath.makeStatistics(bkd.getImageF(), afwMath.MEAN).getValue(), sky + delta) bkd -= delta self.assertEqual(afwMath.makeStatistics(bkd.getImageF(), afwMath.MEAN).getValue(), sky)
def testBadPatch(self): """Test that a large bad patch of an image doesn't cause an absolute failure""" initialValue = 20 mi = afwImage.MaskedImageF(500, 200) mi.set((initialValue, 0x0, 1.0)) im = mi.getImage() im[0:200, :] = np.nan del im msk = mi.getMask() badBits = msk.getPlaneBitMask( ['EDGE', 'DETECTED', 'DETECTED_NEGATIVE']) msk[0:400, :] |= badBits del msk if display: ds9.mtv(mi, frame=0) sctrl = afwMath.StatisticsControl() sctrl.setAndMask(badBits) nx, ny = 17, 17 bctrl = afwMath.BackgroundControl(nx, ny, sctrl, afwMath.MEANCLIP) bkgd = afwMath.makeBackground(mi, bctrl) statsImage = afwMath.cast_BackgroundMI(bkgd).getStatsImage() if display: ds9.mtv(statsImage, frame=1) # the test is that this doesn't fail if the bug (#2297) is fixed bkgdImage = bkgd.getImageF(afwMath.Interpolate.NATURAL_SPLINE, afwMath.REDUCE_INTERP_ORDER) self.assertEqual(np.mean(bkgdImage[0:100, 0:100].getArray()), initialValue) if display: ds9.mtv(bkgdImage, frame=2) # # Check that we can fix the NaNs in the statsImage # sim = statsImage.getImage().getArray() sim[np.isnan(sim)] = initialValue # replace NaN by initialValue bkgdImage = bkgd.getImageF(afwMath.Interpolate.NATURAL_SPLINE, afwMath.REDUCE_INTERP_ORDER) self.assertAlmostEqual( np.mean(bkgdImage[0:100, 0:100].getArray(), dtype=np.float64), initialValue)
def testOddSize(self): ''' Test for ticket #1781 -- without it, in oddly-sized images there is a chunk of pixels on the right/bottom that do not go into the fit and are extrapolated. After this ticket, the subimage boundaries are spread more evenly so the last pixels get fit as well. This slightly strange test case checks that the interpolant is close to the function at the end. I could not think of an interpolant that would fit exactly, so this just puts a limit on the errors. ''' W, H = 2, 99 image = afwImage.ImageF(afwGeom.Extent2I(W, H)) bgCtrl = afwMath.BackgroundControl(afwMath.Interpolate.LINEAR) bgCtrl.setNxSample(2) NY = 10 bgCtrl.setNySample(NY) for y in range(H): for x in range(W): B = 89 if y < B: image.set(x, y, y) else: image.set(x, y, B + (y - B) * -1.) #0.5) bobj = afwMath.makeBackground(image, bgCtrl) back = bobj.getImageD() for iy, by in zip([image.get(0, y) for y in range(H)], [back.get(0, y) for y in range(H)]): self.assertTrue(abs(iy - by) < 5) if False: import matplotlib matplotlib.use('Agg') import pylab as plt plt.clf() IY = [image.get(0, y) for y in range(H)] BY = [back.get(0, y) for y in range(H)] for iy, by in zip(IY, BY): print 'diff', iy - by b = np.linspace(0, H - 1, NY + 1) plt.plot(IY, 'b-', lw=3, alpha=0.5) plt.plot(BY, 'r-') for y in b: plt.axvline(y) plt.savefig('bg.png')
def testTicket1781(self): # make an unusual-sized image nx = 526 ny = 154 parabimg = self.getParabolaImage(nx, ny) bctrl = afwMath.BackgroundControl(afwMath.Interpolate.CUBIC_SPLINE) bctrl.setNxSample(16) bctrl.setNySample(4) bctrl.getStatisticsControl().setNumSigmaClip(10.0) bctrl.getStatisticsControl().setNumIter(1) backobj = afwMath.makeBackground(parabimg, bctrl) if False: parabimg.writeFits('in.fits') backobj.getImageF().writeFits('out.fits')
def testUndersample(self): """Test how the program handles nx,ny being too small for requested interp style.""" # make an image nx = 64 ny = 64 img = afwImage.ImageF(afwGeom.Extent2I(nx, ny)) # make a background control object bctrl = afwMath.BackgroundControl(10, 10) bctrl.setInterpStyle(afwMath.Interpolate.CUBIC_SPLINE) bctrl.setNxSample(3) bctrl.setNySample(3) if False: # INCREASE_NXNYSAMPLE is no longer supported post #2074 bctrl.setNxSample(2) bctrl.setNySample(2) # see if it adjusts the nx,ny values up to 3x3 bctrl.setUndersampleStyle(afwMath.INCREASE_NXNYSAMPLE) backobj = afwMath.makeBackground(img, bctrl) self.assertEqual(backobj.getBackgroundControl().getNxSample(), 3) self.assertEqual(backobj.getBackgroundControl().getNySample(), 3) # put nx,ny back to 2 and see if it adjusts the interp style down to linear bctrl.setNxSample(2) bctrl.setNySample(2) bctrl.setUndersampleStyle("REDUCE_INTERP_ORDER") backobj = afwMath.makeBackground(img, bctrl) backobj.getImageF( ) # Need to interpolate background to discover what we actually needed self.assertEqual(backobj.getAsUsedInterpStyle(), afwMath.Interpolate.LINEAR) # put interp style back up to cspline and see if it throws an exception bctrl.setUndersampleStyle("THROW_EXCEPTION") def tst(img, bctrl): backobj = afwMath.makeBackground(img, bctrl) backobj.getImageF( "CUBIC_SPLINE" ) # only now do we see that we have too few points utilsTests.assertRaisesLsstCpp( self, lsst.pex.exceptions.InvalidParameterException, tst, img, bctrl)
def testBackgroundListIO(self): """Test I/O for BackgroundLists""" bgCtrl = afwMath.BackgroundControl(10, 10) interpStyle = afwMath.Interpolate.AKIMA_SPLINE undersampleStyle = afwMath.REDUCE_INTERP_ORDER approxOrderX = 6 approxOrderY = 6 approxWeighting = True im = self.image.Factory(self.image, self.image.getBBox()) arr = im.getArray() arr += np.random.normal(size=(im.getHeight(), im.getWidth())) for astyle in afwMath.ApproximateControl.UNKNOWN, afwMath.ApproximateControl.CHEBYSHEV: actrl = afwMath.ApproximateControl(astyle, approxOrderX) bgCtrl.setApproximateControl(actrl) backgroundList = afwMath.BackgroundList() backImage = afwImage.ImageF(im.getDimensions()) for i in range(2): bkgd = afwMath.makeBackground(im, bgCtrl) if i == 0: # no need to call getImage backgroundList.append( (bkgd, interpStyle, undersampleStyle, astyle, approxOrderX, approxOrderY, approxWeighting)) else: # Relies on having called getImage; deprecated with self.assertWarns(FutureWarning): backgroundList.append(bkgd) backImage += bkgd.getImageF(interpStyle, undersampleStyle) with lsst.utils.tests.getTempFilePath(".fits") as fileName: backgroundList.writeFits(fileName) backgrounds = afwMath.BackgroundList.readFits(fileName) img = backgrounds.getImage() # Check that the read-back image is identical to that generated from the backgroundList # round-tripped to disk backImage -= img self.assertEqual(np.min(backImage.getArray()), 0.0) self.assertEqual(np.max(backImage.getArray()), 0.0)
def testBadAreaFailsSpline(self): """Check that a NaN in the stats image doesn't cause spline interpolation to fail (#2734)""" image = afwImage.ImageF(15, 9) for y in range(image.getHeight()): for x in range(image.getWidth()): # n.b. linear, which is what the interpolation will fall back # to image[x, y, afwImage.LOCAL] = 1 + 2 * y # Set the right corner to NaN. This will mean that we have too few # points for a spline interpolator binSize = 3 image[-binSize:, -binSize:, afwImage.LOCAL] = np.nan nx = image.getWidth() // binSize ny = image.getHeight() // binSize sctrl = afwMath.StatisticsControl() bctrl = afwMath.BackgroundControl(nx, ny, sctrl, afwMath.MEANCLIP) bkgd = afwMath.makeBackground(image, bctrl) if debugMode: afwDisplay.Display(frame=0).mtv(image, title=self._testMethodName + " image") afwDisplay.Display(frame=1).mtv(bkgd.getStatsImage(), title=self._testMethodName + " bkgd StatsImage") # Should throw if we don't permit REDUCE_INTERP_ORDER self.assertRaises(lsst.pex.exceptions.OutOfRangeError, bkgd.getImageF, afwMath.Interpolate.NATURAL_SPLINE) # The interpolation should fall back to linear for the right part of the image # where the NaNs don't permit spline interpolation (n.b. this happens # to be exact) bkgdImage = bkgd.getImageF(afwMath.Interpolate.NATURAL_SPLINE, afwMath.REDUCE_INTERP_ORDER) if debugMode: afwDisplay.Display(frame=2).mtv(bkgdImage, title=self._testMethodName + " bkgdImage") image -= bkgdImage self.assertEqual( afwMath.makeStatistics(image, afwMath.MEAN).getValue(), 0.0)
def getProcessedImageArray(ccd, amp, nx=10, ny=10): """ Subtract afwMath local background model from an de-biased and trimmed image segment and return the underlying ndarray. """ # Define extent of local background region bg_ctrl = afwMath.BackgroundControl(nx, ny, ccd.stat_ctrl) image = ccd.unbiased_and_trimmed_image(amp) try: bg = afwMath.makeBackground(image, bg_ctrl) bg_image = bg.getImageF() image -= bg.getImageF() except pexExcept.OutOfRangeError, eObj: # Stack fails to derive a local background image so rely on # bias subtraction. This produces less reliable results on # real and simulated data. print "TrapFinder.getProcessedImageArray:", eObj print "Skipping local background subtraction for amp", amp
def testBadAreaFailsSpline(self): """Check that a NaN in the stats image doesn't cause spline interpolation to fail (#2734)""" image = afwImage.ImageF(15, 9) for y in range(image.getHeight()): for x in range(image.getWidth()): image.set( x, y, 1 + 2 * y ) # n.b. linear, which is what the interpolation will fall back to # Set the right corner to NaN. This will mean that we have too few points for a spline interpolator binSize = 3 image[-binSize:, -binSize:] = np.nan nx = image.getWidth() // binSize ny = image.getHeight() // binSize sctrl = afwMath.StatisticsControl() bctrl = afwMath.BackgroundControl(nx, ny, sctrl, afwMath.MEANCLIP) bkgd = afwMath.makeBackground(image, bctrl) if display: ds9.mtv(image) ds9.mtv(afwMath.cast_BackgroundMI(bkgd).getStatsImage(), frame=1) # # Should throw if we don't permit REDUCE_INTERP_ORDER # utilsTests.assertRaisesLsstCpp(self, lsst.pex.exceptions.OutOfRangeException, bkgd.getImageF, afwMath.Interpolate.NATURAL_SPLINE) # # The interpolation should fall back to linear for the right part of the image # where the NaNs don't permit spline interpolation (n.b. this happens to be exact) # bkgdImage = bkgd.getImageF(afwMath.Interpolate.NATURAL_SPLINE, afwMath.REDUCE_INTERP_ORDER) if display: ds9.mtv(bkgdImage, frame=2) image -= bkgdImage self.assertEqual( afwMath.makeStatistics(image, afwMath.MEAN).getValue(), 0.0)
def testRamp(self): # make a ramping image (spline should be exact for linear increasing image nx = 512 ny = 512 rampimg = afwImage.ImageD(afwGeom.Extent2I(nx, ny)) dzdx, dzdy, z0 = 0.1, 0.2, 10000.0 for x in range(nx): for y in range(ny): rampimg.set(x, y, dzdx * x + dzdy * y + z0) # check corner, edge, and center pixels bctrl = afwMath.BackgroundControl(10, 10) bctrl.setInterpStyle(afwMath.Interpolate.CUBIC_SPLINE) bctrl.setNxSample(6) bctrl.setNySample(6) bctrl.getStatisticsControl().setNumSigmaClip( 20.0) # something large enough to avoid clipping entirely bctrl.getStatisticsControl().setNumIter(1) backobj = afwMath.makeBackground(rampimg, bctrl) xpixels = [0, nx // 2, nx - 1] ypixels = [0, ny // 2, ny - 1] for xpix in xpixels: for ypix in ypixels: testval = afwMath.cast_BackgroundMI(backobj).getPixel( xpix, ypix) self.assertAlmostEqual(testval / rampimg.get(xpix, ypix), 1, 6) # Test pickle bg = afwMath.cast_BackgroundMI(backobj) new = pickle.loads(pickle.dumps(bg)) self.assertBackgroundEqual(bg, new) # Check creation of sub-image box = afwGeom.Box2I(afwGeom.Point2I(123, 45), afwGeom.Extent2I(45, 123)) bgImage = bg.getImageF("AKIMA_SPLINE") bgSubImage = afwImage.ImageF(bgImage, box) testImage = bg.getImageF(box, "AKIMA_SPLINE") self.assertEqual(testImage.getXY0(), bgSubImage.getXY0()) self.assertEqual(testImage.getDimensions(), bgSubImage.getDimensions()) self.assertTrue(np.all(testImage.getArray() == bgSubImage.getArray()))
def testBackgroundFromStatsImage(self): """Check that we can rebuild a Background from a BackgroundMI.getStatsImage()""" bgCtrl = afwMath.BackgroundControl(10, 10) bkgd = afwMath.makeBackground(self.image, bgCtrl) interpStyle = afwMath.Interpolate.AKIMA_SPLINE undersampleStyle = afwMath.REDUCE_INTERP_ORDER bkgdImage = bkgd.getImageF(interpStyle, undersampleStyle) self.assertEqual(np.mean(bkgdImage.getArray()), self.val) self.assertEqual(interpStyle, bkgd.getAsUsedInterpStyle()) self.assertEqual(undersampleStyle, bkgd.getAsUsedUndersampleStyle()) # OK, we have our background. Make a copy bkgd2 = afwMath.BackgroundMI(self.image.getBBox(), bkgd.getStatsImage()) del bkgd # we should be handling the memory correctly, but let's check bkgdImage2 = bkgd2.getImageF(interpStyle) self.assertEqual(np.mean(bkgdImage2.getArray()), self.val)
def testDetection(self): """Test CR detection""" # # Subtract background # bctrl = afwMath.BackgroundControl(afwMath.Interpolate.NATURAL_SPLINE) bctrl.setNxSample(int(self.mi.getWidth() / 256) + 1) bctrl.setNySample(int(self.mi.getHeight() / 256) + 1) bctrl.getStatisticsControl().setNumSigmaClip(3.0) bctrl.getStatisticsControl().setNumIter(2) im = self.mi.getImage() try: backobj = afwMath.makeBackground(im, bctrl) except Exception, e: print >> sys.stderr, e, bctrl.setInterpStyle(afwMath.Interpolate.CONSTANT) backobj = afwMath.makeBackground(im, bctrl)
def subtractBackground(maskedImage): """Subtract the background from a MaskedImage Note: at present the mask and variance are ignored, but they might used be someday. Returns the background object returned by afwMath.makeBackground. """ bkgControl = afwMath.BackgroundControl(afwMath.Interpolate.NATURAL_SPLINE) bkgControl.setNxSample( int(maskedImage.getWidth() // BackgroundCellSize) + 1) bkgControl.setNySample( int(maskedImage.getHeight() // BackgroundCellSize) + 1) bkgControl.getStatisticsControl().setNumSigmaClip(3) bkgControl.getStatisticsControl().setNumIter(3) image = maskedImage.getImage() bkgObj = afwMath.makeBackground(image, bkgControl) image -= bkgObj.getImageF() return bkgObj
def testBackgroundTestImages(self): """Tests Laher's afwdata/Statistics/*.fits images (doubles)""" imginfolist = [] # cooked to known value imginfolist.append(["v1_i1_g_m400_s20_f.fits", 399.9912966583894]) for imginfo in imginfolist: imgfile, centerValue = imginfo imgPath = os.path.join(AfwdataDir, "Statistics", imgfile) # get the image and header dimg = afwImage.DecoratedImageF(imgPath) img = dimg.getImage() fitsHdr = dimg.getMetadata() # the FITS header # get the True values of the mean and stdev reqMean = fitsHdr.getAsDouble("MEANREQ") reqStdev = fitsHdr.getAsDouble("SIGREQ") naxis1 = img.getWidth() naxis2 = img.getHeight() # create a background control object bctrl = afwMath.BackgroundControl(afwMath.Interpolate.AKIMA_SPLINE) bctrl.setNxSample(5) bctrl.setNySample(5) # run the background constructor and call the getPixel() and # getImage() functions. backobj = afwMath.makeBackground(img, bctrl) pixPerSubimage = img.getWidth()*img.getHeight() / \ (bctrl.getNxSample()*bctrl.getNySample()) stdevInterp = reqStdev/math.sqrt(pixPerSubimage) # test getPixel() testval = backobj.getPixel(naxis1//2, naxis2//2) self.assertAlmostEqual(testval/centerValue, 1, places=7) self.assertLess(abs(testval - reqMean), 2*stdevInterp) # test getImage() by checking the center pixel bimg = backobj.getImageF() testImgval = bimg[naxis1//2, naxis2//2, afwImage.LOCAL] self.assertLess(abs(testImgval - reqMean), 2*stdevInterp)
def testBackgroundList(self): """Test that a BackgroundLists behaves like a list""" bgCtrl = afwMath.BackgroundControl(10, 10) interpStyle = afwMath.Interpolate.AKIMA_SPLINE undersampleStyle = afwMath.REDUCE_INTERP_ORDER approxStyle = afwMath.ApproximateControl.UNKNOWN approxOrderX = 0 approxOrderY = 0 approxWeighting = False backgroundList = afwMath.BackgroundList() for i in range(2): bkgd = afwMath.makeBackground(self.image, bgCtrl) if i == 0: # no need to call getImage backgroundList.append( (bkgd, interpStyle, undersampleStyle, approxStyle, approxOrderX, approxOrderY, approxWeighting)) else: # Relies on having called getImage; deprecated with self.assertWarns(FutureWarning): backgroundList.append(bkgd) def assertBackgroundList(bgl): self.assertEqual(len(bgl), 2) # check that len() works for a in bgl: # check that we can iterate pass self.assertEqual(len(bgl[0]), 7) # check that we can index # check that we always have a tuple (bkgd, interp, under, # approxStyle, orderX, orderY, weighting) self.assertEqual(len(bgl[1]), 7) assertBackgroundList(backgroundList) # Check pickling new = pickle.loads(pickle.dumps(backgroundList)) assertBackgroundList(new) self.assertEqual(len(new), len(backgroundList)) for i, j in zip(new, backgroundList): self.assertBackgroundEqual(i[0], j[0]) self.assertEqual(i[1:], j[1:])
def measureBackground(self, image): """Measure a background model for image This doesn't use a full-featured background model (e.g., no Chebyshev approximation) because we just want the binning behaviour. This will allow us to average the bins later (`averageBackgrounds`). The `BackgroundMI` is wrapped in a `BackgroundList` so it can be pickled and persisted. Parameters ---------- image : `lsst.afw.image.MaskedImage` Image for which to measure background. Returns ------- bgModel : `lsst.afw.math.BackgroundList` Background model. """ stats = afwMath.StatisticsControl() stats.setAndMask(image.getMask().getPlaneBitMask(self.config.background.mask)) stats.setNanSafe(True) ctrl = afwMath.BackgroundControl( self.config.background.algorithm, max(int(image.getWidth()/self.config.background.xBinSize + 0.5), 1), max(int(image.getHeight()/self.config.background.yBinSize + 0.5), 1), "REDUCE_INTERP_ORDER", stats, self.config.background.statistic ) bg = afwMath.makeBackground(image, ctrl) return afwMath.BackgroundList(( bg, afwMath.stringToInterpStyle(self.config.background.algorithm), afwMath.stringToUndersampleStyle("REDUCE_INTERP_ORDER"), afwMath.ApproximateControl.UNKNOWN, 0, 0, False ))
def testBadRows(self): """Test that a bad set of rows in an image doesn't cause a failure""" initialValue = 20 mi = afwImage.MaskedImageF(500, 200) mi.set((initialValue, 0x0, 1.0)) mi.image[:, 0:100] = np.nan badBits = mi.mask.getPlaneBitMask( ['EDGE', 'DETECTED', 'DETECTED_NEGATIVE']) mi.mask[0:400, :] |= badBits if debugMode: afwDisplay.Display(frame=0).mtv(mi, title=self._testMethodName + " image") sctrl = afwMath.StatisticsControl() sctrl.setAndMask(badBits) nx, ny = 17, 17 bctrl = afwMath.BackgroundControl(nx, ny, sctrl, afwMath.MEANCLIP) bkgd = afwMath.makeBackground(mi, bctrl) statsImage = bkgd.getStatsImage() if debugMode: afwDisplay.Display(frame=1).mtv(statsImage, title=self._testMethodName + " bkgd StatsImage") # the test is that this doesn't fail if the bug (#2297) is fixed for frame, interpStyle in enumerate([ afwMath.Interpolate.CONSTANT, afwMath.Interpolate.LINEAR, afwMath.Interpolate.NATURAL_SPLINE, afwMath.Interpolate.AKIMA_SPLINE ], 2): bkgdImage = bkgd.getImageF(interpStyle, afwMath.REDUCE_INTERP_ORDER) self.assertEqual(np.mean(bkgdImage[0:100, 0:100].array), initialValue) if debugMode: afwDisplay.Display(frame=frame).mtv( bkgdImage, title=f"{self._testMethodName} bkgdImage: {interpStyle}")
def testSubImage(self): """Test getImage on a subregion of the full background image Using real image data is a cheap way to get a variable background """ mi = self.getCfhtImage() bctrl = afwMath.BackgroundControl(mi.getWidth()//128, mi.getHeight()//128) backobj = afwMath.makeBackground(mi.getImage(), bctrl) subBBox = afwGeom.Box2I(afwGeom.Point2I(1000, 3000), afwGeom.Extent2I(100, 100)) bgFullImage = backobj.getImageF() self.assertEqual(bgFullImage.getBBox(), mi.getBBox()) subFullArr = afwImage.ImageF(bgFullImage, subBBox).getArray() bgSubImage = backobj.getImageF(subBBox, bctrl.getInterpStyle()) subArr = bgSubImage.getArray() # the pixels happen to be identical but it is safer not to rely on that; close is good enough self.assertTrue(np.allclose(subArr, subFullArr))