Ejemplo n.º 1
0
    def buildNoisePadImage(self, noise_pad_size, noise_pad, rng):
        """A helper function that builds the `pad_image` from the given `noise_pad` specification.
        """
        # Make it with the same dtype as the image
        pad_image = galsim.Image(noise_pad_size,
                                 noise_pad_size,
                                 dtype=self.image.dtype)

        # Figure out what kind of noise to apply to the image
        if isinstance(noise_pad, float):
            noise = galsim.GaussianNoise(rng, sigma=np.sqrt(noise_pad))
        elif isinstance(noise_pad,
                        galsim.correlatednoise._BaseCorrelatedNoise):
            noise = noise_pad.copy(rng=rng)
        elif isinstance(noise_pad, galsim.Image):
            noise = galsim.CorrelatedNoise(noise_pad, rng)
        elif self.use_cache and noise_pad in InterpolatedImage._cache_noise_pad:
            noise = InterpolatedImage._cache_noise_pad[noise_pad]
            if rng:
                # Make sure that we are using a specified RNG by resetting that in this cached
                # CorrelatedNoise instance, otherwise preserve the cached RNG
                noise = noise.copy(rng=rng)
        elif isinstance(noise_pad, str):
            noise = galsim.CorrelatedNoise(galsim.fits.read(noise_pad), rng)
            if self.use_cache:
                InterpolatedImage._cache_noise_pad[noise_pad] = noise
        else:
            raise ValueError(
                "Input noise_pad must be a float/int, a CorrelatedNoise, Image, or filename "
                + "containing an image to use to make a CorrelatedNoise!")
        # Add the noise
        pad_image.addNoise(noise)

        return pad_image
Ejemplo n.º 2
0
def test_corr_padding_cf():
    """Test for correlated noise padding of InterpolatedImage."""
    import time
    t1 = time.time()

    imgfile = 'fits_files/blankimg.fits'
    orig_nx = 147
    orig_ny = 124
    orig_seed = 151241
    rng = galsim.BaseDeviate(orig_seed)

    # Make an ImageCorrFunc
    cf = galsim.CorrelatedNoise(rng, galsim.fits.read(imgfile))

    # first, make the base image
    orig_img = galsim.ImageF(orig_nx, orig_ny, scale=1.)
    gal = galsim.Gaussian(sigma=2.5, flux=100.)
    gal.drawImage(orig_img, method='no_pixel')

    for iter in range(n_iter):
        # make it into an InterpolatedImage padded with cf
        int_im = galsim.InterpolatedImage(orig_img, noise_pad=cf)
        
        # do it again with a particular seed
        int_im = galsim.InterpolatedImage(orig_img, rng = galsim.GaussianDeviate(orig_seed),
                                          noise_pad = cf)

        # repeat
        int_im = galsim.InterpolatedImage(orig_img, rng = galsim.GaussianDeviate(orig_seed),
                                          noise_pad = cf)

    t2 = time.time()
    print('time for %s = %.2f'%(funcname(),t2-t1))
Ejemplo n.º 3
0
 def check_symm_noise(noise_image, msg):
     # A helper funciton to see if a noise image has 4-fold symmetric noise.
     im2 = noise_image.copy()
     # Clear out any wcs to make the test simpler
     im2.wcs = galsim.PixelScale(1.)
     noise = galsim.CorrelatedNoise(im2)
     cf = noise.drawImage(galsim.Image(bounds=galsim.BoundsI(-1,1,-1,1), scale=1))
     # First check the variance
     print('variance: ',cf(0,0), noise.getVariance())
     np.testing.assert_almost_equal(cf(0,0)/noise.getVariance(), 1.0, decimal=VAR_NDECIMAL,
                                    err_msg=msg + ':: noise variance is wrong.')
     cf_plus = np.array([ cf(1,0), cf(-1,0), cf(0,1), cf(0,-1) ])
     cf_cross = np.array([ cf(1,1), cf(-1,-1), cf(-1,1), cf(1,-1) ])
     print('plus pattern: ',cf_plus)
     print('diff relative to dc: ',(cf_plus-np.mean(cf_plus))/cf(0,0))
     print('cross pattern: ',cf_cross)
     print('diff relative to dc: ',(cf_cross-np.mean(cf_cross))/cf(0,0))
     # For now, don't make these asserts.  Just print whether they will pass or fail.
     if True:
         if np.all(np.abs((cf_plus-np.mean(cf_plus))/cf(0,0)) < 0.01):
             print('plus test passes')
         else:
             print('*** FAIL ***')
             print(msg + ': plus pattern is not constant')
         if np.all(np.abs((cf_cross-np.mean(cf_cross))/cf(0,0)) < 0.01):
             print('cross test passes')
         else:
             print('*** FAIL ***')
             print(msg + ': cross pattern is not constant')
     else:
         np.testing.assert_almost_equal((cf_plus-np.mean(cf_plus))/cf(0,0), 0.0, decimal=2,
                                        err_msg=msg + ': plus pattern is not constant')
         np.testing.assert_almost_equal((cf_cross-np.mean(cf_cross))/cf(0,0), 0.0, decimal=2,
                                        err_msg=msg + ': cross pattern is not constant')
Ejemplo n.º 4
0
    def buildNoisePadImage(self, pad_factor, noise_pad, rng):
        """A helper function that builds the pad_image from the given noise_pad specification.
        """
        import numpy as np
        if pad_factor <= 0.:
            pad_factor = galsim._galsim.getDefaultPadFactor()
        padded_size = int(np.ceil(np.max(self.orig_image.array.shape) * pad_factor))
        if isinstance(self.orig_image, galsim.BaseImageF):
            pad_image = galsim.ImageF(padded_size, padded_size)
        if isinstance(self.orig_image, galsim.BaseImageD):
            pad_image = galsim.ImageD(padded_size, padded_size)

        # Figure out what kind of noise to apply to the image
        if isinstance(noise_pad, float):
            noise = galsim.GaussianNoise(rng, sigma = np.sqrt(noise_pad))
        elif isinstance(noise_pad, galsim.correlatednoise._BaseCorrelatedNoise):
            noise = noise_pad.copy()
            if rng: # Let a user supplied RNG take precedence over that in user CN
                noise.setRNG(rng)
        elif isinstance(noise_pad,galsim.BaseImageF) or isinstance(noise_pad,galsim.BaseImageD):
            noise = galsim.CorrelatedNoise(rng, noise_pad)
        elif self.use_cache and noise_pad in InterpolatedImage._cache_noise_pad:
            noise = InterpolatedImage._cache_noise_pad[noise_pad]
            if rng:
                # Make sure that we are using a specified RNG by resetting that in this cached
                # CorrelatedNoise instance, otherwise preserve the cached RNG
                noise.setRNG(rng)
        elif isinstance(noise_pad, str):
            noise = galsim.CorrelatedNoise(rng, galsim.fits.read(noise_pad))
            if self.use_cache: 
                InterpolatedImage._cache_noise_pad[noise_pad] = noise
        else:
            raise ValueError(
                "Input noise_pad must be a float/int, a CorrelatedNoise, Image, or filename "+
                "containing an image to use to make a CorrelatedNoise!")
        pad_image.addNoise(noise)

        return pad_image
Ejemplo n.º 5
0
 def check_noise(noise_image, noise, msg):
     # A helper function to check that the current noise in the image is properly described
     # by the given CorrelatedNoise object
     noise2 = galsim.CorrelatedNoise(noise_image)
     print('noise = ',noise)
     print('noise2 = ',noise2)
     np.testing.assert_almost_equal(noise.getVariance(), noise2.getVariance(),
                                    decimal=CHECKNOISE_NDECIMAL,
                                    err_msg=msg + ': variance does not match.')
     cf_im1 = galsim.Image(8,8, wcs=noise_image.wcs)
     cf_im2 = cf_im1.copy()
     noise.drawImage(image=cf_im1)
     noise2.drawImage(image=cf_im2)
     np.testing.assert_almost_equal(cf_im1.array, cf_im2.array,
                                    decimal=CHECKNOISE_NDECIMAL,
                                    err_msg=msg + ': image of cf does not match.')
Ejemplo n.º 6
0
def make_cf(args):
    bls = Table.read(args.blank_file, format='ascii.basic')
    for f, filt in enumerate(args.filter_names):
        print "Making Correlation function for ", filt
        q, = np.where(bls['FILTER'] == filt)
        bl = q[0]
        xmin, xmax = bls['XMIN'][bl], bls['XMAX'][bl]
        ymin, ymax = bls['YMIN'][bl], bls['YMAX'][bl]
        hdu = pyfits.open(bls['FILE'][bl])
        bl_dat = hdu[0].data[ymin:ymax, xmin:xmax]
        hdu.close()
        rng = galsim.BaseDeviate(123456)
        img = galsim.Image(bl_dat)
        cn = galsim.CorrelatedNoise(img, rng=rng, scale=0.03)
        image = galsim.ImageD(80, 80, scale=0.03)
        cf = cn.drawImage(image)
        name = args.out_path + args.out_name.replace('filter',
                                                     args.file_filter_name[f])
        print "Savings fits file at ", name
        pyfits.writeto(name, cf.array, clobber=True)
Ejemplo n.º 7
0
    print "Unpadded convolved image bounds = " + str(convimage1.bounds)
    convimage3_padded = galsim.ImageD(
        int(largeim_size * size_factor) + 32,
        int(largeim_size * size_factor) + 32)
    # Set the scales of convimage2 & 3 to be 0.18 so that addNoise() works correctly
    convimage2.scale = 0.18
    convimage3_padded.scale = 0.18
    print "Padded convolved image bounds = " + str(convimage3_padded.bounds)
    print ""

    # We draw, calculate a correlation function for the resulting field, and repeat to get an
    # average over nsum_test trials
    cimobj.draw(convimage1, dx=0.18, normalization='sb')
    cn_test1 = galsim.CorrelatedNoise(gd,
                                      convimage1,
                                      dx=0.18,
                                      correct_periodicity=False,
                                      subtract_mean=True,
                                      correct_sample_bias_prototype=False)
    testim1 = galsim.ImageD(smallim_size, smallim_size)
    cn_test1.draw(testim1, dx=0.18)

    convimage2.addNoise(
        conv_cn
    )  # Now we make a comparison by simply adding noise from conv_cn
    cn_test2 = galsim.CorrelatedNoise(gd,
                                      convimage2,
                                      dx=0.18,
                                      correct_periodicity=False,
                                      subtract_mean=True,
                                      correct_sample_bias_prototype=False)
    testim2 = galsim.ImageD(smallim_size, smallim_size)
Ejemplo n.º 8
0
cn2 = galsim.getCOSMOSNoise(ud, CFIMFILE_UNS, dx_cosmos=1.)

testim1 = galsim.ImageD(7, 7)
testim2 = galsim.ImageD(7, 7)
var1 = 0.
var2 = 0.

noisearrays = cPickle.load(open(NOISEIMFILE, 'rb'))
for noisearray, i in zip(noisearrays, range(len(noisearrays))):
    noise1 = galsim.ImageViewD((noisearray.copy()).astype(np.float64), scale=1.)
    noise2 = galsim.ImageViewD((noisearray.copy()).astype(np.float64), scale=1.)
    cn1.applyWhiteningTo(noise1)
    cn2.applyWhiteningTo(noise2)
    var1 += noise1.array.var()
    var2 += noise2.array.var()
    cntest1 = galsim.CorrelatedNoise(ud, noise1)
    cntest2 = galsim.CorrelatedNoise(ud, noise2)
    cntest1.draw(testim1, dx=1., add_to_image=True)
    cntest2.draw(testim2, dx=1., add_to_image=True)
    print "Done "+str(i + 1)+"/"+str(len(noisearrays))

testim1 /= len(noisearrays)
testim2 /= len(noisearrays)
var1 /= len(noisearrays)
var2 /= len(noisearrays)

print var1, var2

delx = np.arange(7) - 3.

import matplotlib.pyplot as plt
Ejemplo n.º 9
0
A simple script used to quickly generate plots for the discussion of which interpolant should be
used to describe correlation functions.  See the discussion at
https://github.com/GalSim-developers/GalSim/pull/452#discussion-diff-5701561 
"""
import numpy as np
import matplotlib.pyplot as plt
import galsim

CFSIZE=9
UPSAMPLING = 3

rng = galsim.BaseDeviate(752424)
gd = galsim.GaussianNoise(rng)
noise_image = galsim.ImageD(CFSIZE, CFSIZE)
noise_image.addNoise(gd)

cn = galsim.CorrelatedNoise(rng, noise_image, x_interpolant=galsim.Nearest(tol=1.e-4), dx=1.)

test_image = galsim.ImageD(
    2 * UPSAMPLING * CFSIZE, 2 * UPSAMPLING * CFSIZE, scale=1. / float(UPSAMPLING))
cn.applyRotation(30. * galsim.degrees)
cn.draw(test_image)

plt.clf()
plt.pcolor(test_image.array)
plt.colorbar()
plt.savefig('cf_nearest.png')
plt.show()

Ejemplo n.º 10
0
    def __init__(self,
                 real_galaxy_catalog,
                 index=None,
                 id=None,
                 random=False,
                 rng=None,
                 x_interpolant=None,
                 k_interpolant=None,
                 flux=None,
                 pad_factor=0,
                 noise_pad=False,
                 pad_image=None,
                 use_cache=True,
                 gsparams=None):

        import pyfits
        import numpy as np

        # Code block below will be for galaxy selection; not all are currently implemented.  Each
        # option must return an index within the real_galaxy_catalog.
        if index is not None:
            if id is not None or random is True:
                raise AttributeError(
                    'Too many methods for selecting a galaxy!')
            use_index = index
        elif id is not None:
            if random is True:
                raise AttributeError(
                    'Too many methods for selecting a galaxy!')
            use_index = real_galaxy_catalog._get_index_for_id(id)
        elif random is True:
            if rng is None:
                uniform_deviate = galsim.UniformDeviate()
            elif isinstance(rng, galsim.BaseDeviate):
                uniform_deviate = galsim.UniformDeviate(rng)
            else:
                raise TypeError(
                    "The rng provided to RealGalaxy constructor is not a BaseDeviate"
                )
            use_index = int(real_galaxy_catalog.nobjects * uniform_deviate())
        else:
            raise AttributeError('No method specified for selecting a galaxy!')

        # read in the galaxy, PSF images; for now, rely on pyfits to make I/O errors. Should
        # consider exporting this code into fits.py in some function that takes a filename and HDU,
        # and returns an ImageView

        gal_image = real_galaxy_catalog.getGal(use_index)
        PSF_image = real_galaxy_catalog.getPSF(use_index)

        # choose proper interpolant
        if x_interpolant is None:
            lan5 = galsim.Lanczos(5, conserve_flux=True, tol=1.e-4)
            self.x_interpolant = galsim.InterpolantXY(lan5)
        else:
            self.x_interpolant = galsim.utilities.convert_interpolant_to_2d(
                x_interpolant)
        if k_interpolant is None:
            self.k_interpolant = galsim.InterpolantXY(
                galsim.Quintic(tol=1.e-4))
        else:
            self.k_interpolant = galsim.utilities.convert_interpolant_to_2d(
                k_interpolant)

        # read in data about galaxy from FITS binary table; store as normal attributes of RealGalaxy

        # save any other relevant information as instance attributes
        self.catalog_file = real_galaxy_catalog.file_name
        self.index = use_index
        self.pixel_scale = float(real_galaxy_catalog.pixel_scale[use_index])

        # handle padding by an image
        specify_size = False
        padded_size = gal_image.getPaddedSize(pad_factor)
        if pad_image is not None:
            specify_size = True
            if isinstance(pad_image, str):
                pad_image = galsim.fits.read(pad_image)
            if (not isinstance(pad_image, galsim.BaseImageF)
                    and not isinstance(pad_image, galsim.BaseImageD)):
                raise ValueError(
                    "Supplied pad_image is not one of the allowed types!")
            # If an image was supplied directly or from a file, check its size:
            #    Cannot use if too small.
            #    Use to define the final image size otherwise.
            deltax = ((1 + pad_image.getXMax() - pad_image.getXMin()) -
                      (1 + gal_image.getXMax() - gal_image.getXMin()))
            deltay = ((1 + pad_image.getYMax() - pad_image.getYMin()) -
                      (1 + gal_image.getYMax() - gal_image.getYMin()))
            if deltax < 0 or deltay < 0:
                raise RuntimeError("Image supplied for padding is too small!")
            if pad_factor != 1. and pad_factor != 0.:
                import warnings
                msg = "Warning: ignoring specified pad_factor because user also specified\n"
                msg += "         an image to use directly for the padding."
                warnings.warn(msg)
        else:
            if isinstance(gal_image, galsim.BaseImageF):
                pad_image = galsim.ImageF(padded_size, padded_size)
            if isinstance(gal_image, galsim.BaseImageD):
                pad_image = galsim.ImageD(padded_size, padded_size)

        # Set up the GaussianDeviate if not provided one, or check that the user-provided one
        # is of a valid type.  Note if random was selected, we can use that uniform_deviate safely.
        if random is True:
            gaussian_deviate = galsim.GaussianDeviate(uniform_deviate)
        else:
            if rng is None:
                gaussian_deviate = galsim.GaussianDeviate()
            elif isinstance(rng, galsim.BaseDeviate):
                # Even if it's already a GaussianDeviate, we still want to make a new Gaussian
                # deviate that would generate the same sequence, because later we change the sigma
                # and we don't want to change it for the original one that was passed in.  So don't
                # distinguish between GaussianDeviate and the other BaseDeviates here.
                gaussian_deviate = galsim.GaussianDeviate(rng)
            else:
                raise TypeError(
                    "rng provided to RealGalaxy constructor is not a BaseDeviate"
                )

        # handle noise-padding options
        try:
            noise_pad = galsim.config.value._GetBoolValue(noise_pad, '')
        except:
            pass
        if noise_pad:
            self.pad_variance = float(real_galaxy_catalog.variance[use_index])

            # Check, is it "True" or something else?  If True, we use Gaussian uncorrelated noise
            # using the stored variance in the catalog.  Otherwise, if it's a CorrelatedNoise we use
            # it directly; if it's an Image of some sort we use it to make a CorrelatedNoise; if
            # it's a string, we read in the image from file and make a CorrelatedNoise.
            if type(noise_pad) is not bool:
                if isinstance(noise_pad,
                              galsim.correlatednoise._BaseCorrelatedNoise):
                    cn = noise_pad.copy()
                    if rng:  # Let user supplied RNG take precedence over that in user CN
                        cn.setRNG(gaussian_deviate)
                    # This small patch may have different overall variance, so rescale while
                    # preserving the correlation structure by default
                    cn.setVariance(self.pad_variance)
                elif (isinstance(noise_pad, galsim.BaseImageF)
                      or isinstance(noise_pad, galsim.BaseImageD)):
                    cn = galsim.CorrelatedNoise(gaussian_deviate, noise_pad)
                elif use_cache and noise_pad in RealGalaxy._cache_noise_pad:
                    cn = RealGalaxy._cache_noise_pad[noise_pad]
                    # Make sure that we are using the desired RNG by resetting that in this cached
                    # CorrelatedNoise instance
                    if rng:
                        cn.setRNG(gaussian_deviate)
                    # This small patch may have different overall variance, so rescale while
                    # preserving the correlation structure
                    cn.setVariance(self.pad_variance)
                elif isinstance(noise_pad, str):
                    tmp_img = galsim.fits.read(noise_pad)
                    cn = galsim.CorrelatedNoise(gaussian_deviate, tmp_img)
                    if use_cache:
                        RealGalaxy._cache_noise_pad[noise_pad] = cn
                    # This small patch may have different overall variance, so rescale while
                    # preserving the correlation structure
                    cn.setVariance(self.pad_variance)
                else:
                    raise RuntimeError(
                        "noise_pad must be either a bool, CorrelatedNoise, Image, "
                        + "or a filename for reading in an Image")

            # Set the GaussianDeviate sigma
            gaussian_deviate.setSigma(np.sqrt(self.pad_variance))

            # populate padding image with noise field
            if type(noise_pad) is bool:
                pad_image.addNoise(galsim.DeviateNoise(gaussian_deviate))
            else:
                pad_image.addNoise(cn)
        else:
            self.pad_variance = 0.

        # Now we have to check: was the padding determined using pad_factor?  Or by passing in an
        # image for padding?  Treat these cases differently:
        # (1) If the former, then we can simply have the C++ handle the padding process.
        # (2) If the latter, then we have to do the padding ourselves, and pass the resulting image
        # to the C++ with pad_factor explicitly set to 1.
        if specify_size is False:
            # Make the SBInterpolatedImage out of the image.
            self.original_image = galsim.SBInterpolatedImage(
                gal_image,
                xInterp=self.x_interpolant,
                kInterp=self.k_interpolant,
                dx=self.pixel_scale,
                pad_factor=pad_factor,
                pad_image=pad_image,
                gsparams=gsparams)
        else:
            # Leave the original image as-is.  Instead, we shift around the image to be used for
            # padding.  Find out how much x and y margin there should be on lower end:
            x_marg = int(np.round(0.5 * deltax))
            y_marg = int(np.round(0.5 * deltay))
            # Now reset the pad_image to contain the original image in an even way
            pad_image = pad_image.view()
            pad_image.setScale(self.pixel_scale)
            pad_image.setOrigin(gal_image.getXMin() - x_marg,
                                gal_image.getYMin() - y_marg)
            # Set the central values of pad_image to be equal to the input image
            pad_image[gal_image.bounds] = gal_image
            self.original_image = galsim.SBInterpolatedImage(
                pad_image,
                xInterp=self.x_interpolant,
                kInterp=self.k_interpolant,
                dx=self.pixel_scale,
                pad_factor=1.,
                gsparams=gsparams)

        # also make the original PSF image, with far less fanfare: we don't need to pad with
        # anything interesting.
        self.original_PSF = galsim.SBInterpolatedImage(
            PSF_image,
            xInterp=self.x_interpolant,
            kInterp=self.k_interpolant,
            dx=self.pixel_scale,
            gsparams=gsparams)

        # recalculate Fourier-space attributes rather than using overly-conservative defaults
        self.original_image.calculateStepK()
        self.original_image.calculateMaxK()
        self.original_PSF.calculateStepK()
        self.original_PSF.calculateMaxK()

        if flux != None:
            self.original_image.setFlux(flux)
            self.original_image.__class__ = galsim.SBTransform  # correctly reflect SBProfile change
        self.original_PSF.setFlux(1.0)
        self.original_PSF.__class__ = galsim.SBTransform  # correctly reflect SBProfile change

        # Calculate the PSF "deconvolution" kernel
        psf_inv = galsim.SBDeconvolve(self.original_PSF, gsparams=gsparams)
        # Initialize the SBProfile attribute
        GSObject.__init__(
            self,
            galsim.SBConvolve([self.original_image, psf_inv],
                              gsparams=gsparams))
Ejemplo n.º 11
0
    print "Unpadded convolved image bounds = " + str(convimage1.bounds)
    convimage3_padded = galsim.ImageD(
        int(largeim_size * size_factor) + 32,
        int(largeim_size * size_factor) + 32)
    # Set the scales of convimage2 & 3 to be 0.18 so that addNoise() works correctly
    convimage2.scale = 0.18
    convimage3_padded.scale = 0.18
    print "Padded convolved image bounds = " + str(convimage3_padded.bounds)
    print ""

    # We draw, calculate a correlation function for the resulting field, and repeat to get an
    # average over nsum_test trials
    cimobj.draw(convimage1, dx=0.18, normalization='sb')
    cn_test1 = galsim.CorrelatedNoise(convimage1,
                                      gd,
                                      dx=0.18,
                                      correct_periodicity=False,
                                      subtract_mean=True)
    testim1 = galsim.ImageD(smallim_size, smallim_size)
    cn_test1.draw(testim1, dx=0.18)

    convimage2.addNoise(
        conv_cn
    )  # Now we make a comparison by simply adding noise from conv_cn
    cn_test2 = galsim.CorrelatedNoise(convimage2,
                                      gd,
                                      dx=0.18,
                                      correct_periodicity=False,
                                      subtract_mean=True)
    testim2 = galsim.ImageD(smallim_size, smallim_size)
    cn_test2.draw(testim2, dx=0.18)
Ejemplo n.º 12
0
def test_corr_padding():
    """Test for correlated noise padding of InterpolatedImage."""
    import time
    t1 = time.time()

    # Set up some defaults for tests.
    decimal_precise=4
    decimal_coarse=2
    imgfile = 'fits_files/blankimg.fits'
    orig_nx = 187
    orig_ny = 164
    big_nx = 319
    big_ny = 322
    orig_seed = 151241

    # Read in some small image of a noise field from HST.
    # Rescale it to have a decently large amplitude for the purpose of doing these tests.
    im = 1.e2*galsim.fits.read(imgfile)
    # Make a CorrrlatedNoise out of it.
    cn = galsim.CorrelatedNoise(im, galsim.BaseDeviate(orig_seed))

    # first, make a noise image
    orig_img = galsim.ImageF(orig_nx, orig_ny, scale=1.)
    orig_img.addNoise(cn)

    # make it into an InterpolatedImage with some zero-padding
    # (note that default is zero-padding, by factors of several)
    int_im = galsim.InterpolatedImage(orig_img)
    # draw into a larger image
    big_img = galsim.ImageF(big_nx, big_ny)
    int_im.draw(big_img, scale=1.)
    # check that variance is diluted by expected amount - should be exact, so check precisely!
    big_var_expected = np.var(orig_img.array)*float(orig_nx*orig_ny)/(big_nx*big_ny)
    np.testing.assert_almost_equal(np.var(big_img.array), big_var_expected, decimal=decimal_precise,
        err_msg='Variance not diluted by expected amount when zero-padding')

    # make it into an InterpolatedImage with noise-padding
    int_im = galsim.InterpolatedImage(orig_img, rng = galsim.GaussianDeviate(orig_seed),
                                      noise_pad = im, noise_pad_size = max(big_nx,big_ny))

    # draw into a larger image
    big_img = galsim.ImageF(big_nx, big_ny)
    int_im.draw(big_img, scale=1.)
    # check that variance is same as original - here, we cannot be too precise because the padded
    # region is not huge and the comparison will be, well, noisy.
    np.testing.assert_almost_equal(np.var(big_img.array), np.var(orig_img.array),
        decimal=decimal_coarse,
        err_msg='Variance not correct after padding image with correlated noise')

    # check that if we pass in a RNG, it is actually used to pad with the same noise field
    # basically, redo all of the above steps and draw into a new image, make sure it's the same as
    # previous.
    int_im = galsim.InterpolatedImage(
        orig_img, rng=galsim.GaussianDeviate(orig_seed), noise_pad=cn,
        noise_pad_size = max(big_nx,big_ny))
    big_img_2 = galsim.ImageF(big_nx, big_ny)
    int_im.draw(big_img_2, scale=1.)
    np.testing.assert_array_almost_equal(big_img_2.array, big_img.array, decimal=decimal_precise,
        err_msg='Cannot reproduce correlated noise-padded image with same choice of seed')

    # Finally, check inputs:
    # what if we give it a screwy way of defining the image padding?
    try:
        np.testing.assert_raises(ValueError,galsim.InterpolatedImage,orig_img,noise_pad=-1.)
    except ImportError:
        print 'The assert_raises tests require nose'
    # also, check that whether we give it a string, image, or cn, it gives the same noise field
    # (given the same random seed)
    infile = 'fits_files/blankimg.fits'
    inimg = galsim.fits.read(infile)
    incf = galsim.CorrelatedNoise(inimg, galsim.GaussianDeviate()) # input RNG will be ignored below
    int_im2 = galsim.InterpolatedImage(orig_img, rng=galsim.GaussianDeviate(orig_seed),
                                       noise_pad=inimg, noise_pad_size = max(big_nx,big_ny))
    int_im3 = galsim.InterpolatedImage(orig_img, rng=galsim.GaussianDeviate(orig_seed),
                                       noise_pad=incf, noise_pad_size = max(big_nx,big_ny))
    big_img2 = galsim.ImageF(big_nx, big_ny)
    big_img3 = galsim.ImageF(big_nx, big_ny)
    int_im2.draw(big_img2, scale=1.)
    int_im3.draw(big_img3, scale=1.)
    np.testing.assert_equal(big_img2.array, big_img3.array,
                            err_msg='Diff ways of specifying correlated noise give diff answers')

    t2 = time.time()
    print 'time for %s = %.2f'%(funcname(),t2-t1)
Ejemplo n.º 13
0
# function that is NPIX by NPIX

if not os.path.isfile(
        CFIMFILE
):  # If the CFIMFILE already exists skip straight through to the plots
    # Read in the pickled images
    noiseims = cPickle.load(open(NOISEIMFILE, 'rb'))
    # Loop through the images and sum the correlation functions
    hst_ncf = None
    bd = galsim.BaseDeviate(12345)  # Seed is basically unimportant here
    for noiseim in noiseims:
        noiseim = noiseim.astype(np.float64)
        if hst_ncf is None:
            # Initialize the HST noise correlation function using the first image
            hst_ncf = galsim.CorrelatedNoise(bd,
                                             galsim.ImageViewD(noiseim),
                                             correct_periodicity=True,
                                             subtract_mean=SUBTRACT_MEAN)
        else:
            hst_ncf += galsim.CorrelatedNoise(bd,
                                              galsim.ImageViewD(noiseim),
                                              correct_periodicity=True,
                                              subtract_mean=SUBTRACT_MEAN)
    hst_ncf /= float(len(noiseims))
    # Draw and plot an output image of the resulting correlation function
    cfimage = galsim.ImageD(NPIX, NPIX)
    hst_ncf.draw(cfimage, dx=1.)
    # Save this to the output filename specified in the script header
    cfimage.write(CFIMFILE)
else:
    cfimage = galsim.fits.read(CFIMFILE)
Ejemplo n.º 14
0
failed1 = 0
failed2 = 0
failed3 = 0
failed4 = 0
failed5 = 0
failed6 = 0
failed7 = 0

TESTSTART = 25
TESTEND = 125

for dim in range(TESTSTART, TESTEND):
    noise_array = np.random.randn(dim, dim)
    noise_image = galsim.ImageViewD(noise_array)
    cn1 = galsim.CorrelatedNoise(rng, noise_image)
    cn2 = galsim.CorrelatedNoise(rng, noise_image, correct_periodicity=False)
    # First try with (default), then without, periodicity correction
    test_image1.setZero()
    try:
        cn1.applyTo(test_image1)
    except RuntimeError:
        failed1 += 1
    test_image2.setZero()
    try:
        cn2.applyTo(test_image2)
    except RuntimeError:
        failed2 += 1
    # Then try calculating the PS by hand, in the same manner as the CorrelatedNoise internals
    noiseft = np.fft.fft2(noise_array)
    ps = np.abs(noiseft)**2
Ejemplo n.º 15
0
def test_metacal_tracking():
    """Test that the noise tracking works for the metacal use case involving deconvolution and
    reconvolution by almost the same PSF.

    This test is similar to the above test_uncorrelated_noise_tracking, except the modifications
    are based on what is done for the metacal procedure.
    """
    import math

    def check_noise(noise_image, noise, msg):
        # A helper function to check that the current noise in the image is properly described
        # by the given CorrelatedNoise object
        noise2 = galsim.CorrelatedNoise(noise_image)
        print('noise = ', noise)
        print('noise2 = ', noise2)
        np.testing.assert_almost_equal(noise.getVariance(),
                                       noise2.getVariance(),
                                       decimal=CHECKNOISE_NDECIMAL,
                                       err_msg=msg +
                                       ': variance does not match.')
        cf_im1 = galsim.Image(8, 8, wcs=noise_image.wcs)
        cf_im2 = cf_im1.copy()
        noise.drawImage(image=cf_im1)
        noise2.drawImage(image=cf_im2)
        np.testing.assert_almost_equal(cf_im1.array,
                                       cf_im2.array,
                                       decimal=CHECKNOISE_NDECIMAL,
                                       err_msg=msg +
                                       ': image of cf does not match.')

    def check_symm_noise(noise_image, msg):
        # A helper funciton to see if a noise image has 4-fold symmetric noise.
        im2 = noise_image.copy()
        # Clear out any wcs to make the test simpler
        im2.wcs = galsim.PixelScale(1.)
        noise = galsim.CorrelatedNoise(im2)
        cf = noise.drawImage(
            galsim.Image(bounds=galsim.BoundsI(-1, 1, -1, 1), scale=1))
        # First check the variance
        print('variance: ', cf(0, 0), noise.getVariance())
        np.testing.assert_almost_equal(cf(0, 0) / noise.getVariance(),
                                       1.0,
                                       decimal=VAR_NDECIMAL,
                                       err_msg=msg +
                                       ':: noise variance is wrong.')
        cf_plus = np.array([cf(1, 0), cf(-1, 0), cf(0, 1), cf(0, -1)])
        cf_cross = np.array([cf(1, 1), cf(-1, -1), cf(-1, 1), cf(1, -1)])
        print('plus pattern: ', cf_plus)
        print('diff relative to dc: ', (cf_plus - np.mean(cf_plus)) / cf(0, 0))
        print('cross pattern: ', cf_cross)
        print('diff relative to dc: ',
              (cf_cross - np.mean(cf_cross)) / cf(0, 0))
        # For now, don't make these asserts.  Just print whether they will pass or fail.
        if True:
            if np.all(np.abs((cf_plus - np.mean(cf_plus)) / cf(0, 0)) < 0.01):
                print('plus test passes')
            else:
                print('*** FAIL ***')
                print(msg + ': plus pattern is not constant')
            if np.all(
                    np.abs((cf_cross - np.mean(cf_cross)) / cf(0, 0)) < 0.01):
                print('cross test passes')
            else:
                print('*** FAIL ***')
                print(msg + ': cross pattern is not constant')
        else:
            np.testing.assert_almost_equal(
                (cf_plus - np.mean(cf_plus)) / cf(0, 0),
                0.0,
                decimal=2,
                err_msg=msg + ': plus pattern is not constant')
            np.testing.assert_almost_equal(
                (cf_cross - np.mean(cf_cross)) / cf(0, 0),
                0.0,
                decimal=2,
                err_msg=msg + ': cross pattern is not constant')

    seed = 1234567  # For use as a unit test, we need a specific seed
    #seed = 0  # During testing, it's useful to see how numbers flop around to know if
    # something is systematic or random.
    rng = galsim.BaseDeviate(seed)

    noise_var = 1.3
    im_size = 1024
    dg = 0.1  # This is bigger than metacal would use, but it makes the test easier.

    # Use a non-trivial wcs...
    #wcs = galsim.JacobianWCS(0.26, 0.04, -0.04, -0.26)  # Rotation + flip.  No shear.
    wcs = galsim.JacobianWCS(0.26, 0.03, 0.08, -0.21)  # Fully complex
    #dudx =  0.12*0.26
    #dudy =  1.10*0.26
    #dvdx = -0.915*0.26
    #dvdy = -0.04*0.26
    #wcs = galsim.JacobianWCS(dudx, dudy, dvdx, dvdy)  # Even more extreme

    # And an asymmetric PSF
    #orig_psf = galsim.Gaussian(fwhm=0.9).shear(g1=0.05, g2=0.03)
    # This one is small enough not to be fully Nyquist sampled, which makes things harder.
    orig_psf = galsim.Gaussian(fwhm=0.7).shear(g1=0.05, g2=0.03)

    # pixel is the pixel in world coords
    pixel = wcs.toWorld(galsim.Pixel(scale=1))
    pixel_inv = galsim.Deconvolve(pixel)

    psf_image = orig_psf.drawImage(nx=im_size, ny=im_size, wcs=wcs)

    # Metacal only has access to the PSF as an image, so use this from here on.
    psf = galsim.InterpolatedImage(psf_image)
    psf_nopix = galsim.Convolve([psf, pixel_inv])
    psf_inv = galsim.Deconvolve(psf)

    # Not what is done currently, but using a smoother target PSF helps make sure the
    # zeros in the deconvolved PSF get adequately zeroed out.
    def get_target_psf(psf):
        dk = 0.1  # The resolution in k space for the KImage
        small_kval = 1.e-2  # Find the k where the given psf hits this kvalue
        smaller_kval = 3.e-3  # Target PSF will have this kvalue at the same k

        kim = psf.drawKImage(scale=dk)
        karr_r = kim.real.array
        # Find the smallest r where the kval < small_kval
        nk = karr_r.shape[0]
        kx, ky = np.meshgrid(np.arange(-nk / 2, nk / 2),
                             np.arange(-nk / 2, nk / 2))
        ksq = (kx**2 + ky**2) * dk**2
        ksq_max = np.min(ksq[karr_r < small_kval * psf.flux])

        # We take our target PSF to be the (round) Gaussian that is even smaller at this ksq
        # exp(-0.5 * ksq_max * sigma_sq) = smaller_kval
        sigma_sq = -2. * np.log(smaller_kval) / ksq_max
        return galsim.Gaussian(sigma=np.sqrt(sigma_sq))

    # The target PSF dilates the part without the pixel, but reconvolve by the real pixel.
    #psf_target_nopix = psf_nopix.dilate(1. + 2.*dg)
    #psf_target_nopix = orig_psf.dilate(1. + 4.*dg)
    psf_target_nopix = get_target_psf(psf_nopix.shear(g1=dg))
    print('PSF target HLR = ', psf_target_nopix.calculateHLR())
    print('PSF target FWHM = ', psf_target_nopix.calculateFWHM())
    psf_target = galsim.Convolve([psf_target_nopix, pixel])

    # Make an image of pure (white) Gaussian noise
    # Normally, there would be a galaxy in this image, but for the tests, we just have noise.
    obs_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
    obs_image.addNoise(
        galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))

    # The noise on this image should be describable as an UncorrelatedNoise object:
    noise = galsim.UncorrelatedNoise(variance=noise_var, wcs=wcs)
    check_noise(obs_image, noise, 'initial UncorrelatedNoise model is wrong')

    # Make an InterpolatedImage profile to use for manipulating this image
    # We can get away with no padding here, since our image is so large, but normally, you would
    # probably want to pad this with noise padding.
    ii = galsim.InterpolatedImage(obs_image, pad_factor=1)
    ii.noise = noise

    # If we draw it back, the attached noise attribute should still be correct
    check_noise(ii.drawImage(obs_image.copy(), method='no_pixel'), ii.noise,
                'noise model is wrong for InterpolatedImage')

    # Here is the metacal process for which we want to understand the noise.
    # We'll try a few different methods.
    shear = galsim.Shear(g1=dg)
    sheared_obj = galsim.Convolve(ii, psf_inv).shear(shear)
    final_obj = galsim.Convolve(psf_target, sheared_obj)
    final_image = final_obj.drawImage(obs_image.copy(), method='no_pixel')

    try:
        check_symm_noise(final_image, 'Initial image')
        #didnt_fail = True
        # This bit doesn't work while we are not actually raising exceptions in check_symm_noise
        # So we expect to see **FAIL** text at this point.
        print(
            'The above tests are expected to **FAIL**.  This is not a problem.'
        )
        didnt_fail = False
    except AssertionError as e:
        print('As expected initial image fails symmetric noise test:')
        print(e)
        didnt_fail = False
    if didnt_fail:
        assert False, 'Initial image was expected to fail symmetric noise test, but passed.'

    if True:
        print('\n\nStrategy 1:')
        # Strategy 1: Use the noise attribute attached to ii and use it to either whiten or
        #             symmetrize the noise in the final image.
        # Note: The check_noise tests fail.  I think because the convolve and deconvolve impose
        #       a maxk = that of the psf.  Which is too small for an accurate rendering of the
        #       correlation function (here just an autocorrelation of a Pixel.
        # The whiten tests kind of work, but they add a lot of extra noise.  Much more than
        # strategy 4 below.  So the level of correlation remaining is pretty well below the
        # dc variance.  Symmetrize doesn't add much noise, but the residual correlation is about
        # the same, which means it doesn't pass the test relative to the lower dc variance.

        # First, deconvolve and reconvolve by the same PSF:
        test_obj = galsim.Convolve([ii, psf, psf_inv])
        # This fails...
        if False:
            check_noise(
                test_obj.drawImage(obs_image.copy(),
                                   method='no_pixel'), test_obj.noise,
                'noise model is wrong after convolve/deconvolve by psf')

        # Now use a slightly dilated PSF for the reconvolution:
        test_obj = galsim.Convolve([ii, psf_target, psf_inv])
        if False:
            check_noise(
                test_obj.drawImage(obs_image.copy(), method='no_pixel'),
                test_obj.noise, 'noise model is wrong for dilated target psf')

        # Finally, include the shear step.  This was done above with sheared_obj, final_obj.
        if False:
            check_noise(final_image, final_obj.noise,
                        'noise model is wrong when including small shear')

        # If we whiten using this noise model, we should get back to white noise.
        t3 = time.time()
        final_image2 = final_image.copy()  # Don't clobber the original
        final_var = final_image2.whitenNoise(final_obj.noise)
        t4 = time.time()
        print('Noise tracking method with whiten: final_var = ', final_var)
        print('Check: direct variance = ', np.var(final_image2.array))
        check_symm_noise(final_image2, 'noise whitening does not work')
        print('Time for noise tracking with whiten = ', t4 - t3)

        # Using symmetrizeNoise should add less noise, but also work.
        t3 = time.time()
        final_image2 = final_image.copy()
        final_var = final_image2.symmetrizeNoise(final_obj.noise)
        t4 = time.time()
        print('Noise tracking method with symmetrize: final_var = ', final_var)
        print('Check: direct variance = ', np.var(final_image2.array))
        check_symm_noise(final_image2, 'noise symmetrizing does not work')
        print('Time for noise tracking with symmetrize = ', t4 - t3)

    if True:
        print('\n\nStrategy 2:')
        # Strategy 2: Don't trust the noise tracking. Track a noise image through the same process
        #             and then measure the noise from that image.  Use it to either whiten or
        #             symmetrize the noise in the final image.
        # Note: This method doesn't work any better.  The added noise for whitening is even more
        # than strategy 1.  And the remaining correlations are still similarly significant for the
        # symmetrize version.  A little smaller than strategy 1, but not enough to pass our tests.

        # Make another noise image, since we don't actually have access to a pure noise image
        # for real objects.  But we should be able to estimate the variance in the image.
        t3 = time.time()
        noise_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        noise_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        noise_ii = galsim.InterpolatedImage(noise_image, pad_factor=1)
        sheared_noise_obj = galsim.Convolve(noise_ii, psf_inv).shear(shear)
        final_noise_obj = galsim.Convolve(psf_target, sheared_noise_obj)
        final_noise_image = final_noise_obj.drawImage(obs_image.copy(),
                                                      method='no_pixel')

        # Use this to construct an appropriate CorrelatedNoise object
        noise = galsim.CorrelatedNoise(final_noise_image)
        t4 = time.time()
        final_image2 = final_image.copy()
        final_var = final_image2.whitenNoise(noise)
        t5 = time.time()

        check_noise(
            final_noise_image, noise,
            'noise model is wrong when direct measuring the final noise image')

        print('Direct noise method with whiten: final_var = ', final_var)
        # Neither of these work currently, so maybe a bug in the whitening code?
        # Or possibly in my logic here.
        check_symm_noise(
            final_image2,
            'whitening the noise using direct noise model failed')
        print('Time for direct noise with whitening = ', t5 - t3)

        t6 = time.time()
        final_image2 = final_image.copy()
        final_var = final_image2.symmetrizeNoise(noise)
        t7 = time.time()

        print('Direct noise method with symmetrize: final_var = ', final_var)
        check_symm_noise(
            final_image2,
            'symmetrizing the noise using direct noise model failed')
        print('Time for direct noise with symmetrizing = ', t7 - t6 + t4 - t3)

    if False:
        print('\n\nStrategy 3:')
        # Strategy 3: Make a noise field and do the same operations as we do to the main image
        #             except use the opposite shear value.  Add this noise field to the final
        #             image to get a symmetric noise field.
        # Note: This method works!  But only for square pixels.  However, they may be rotated
        # or flipped. Just not sheared.
        # Update: I think this method won't ever work for non-square pixels.  The reason it works
        # for square pixels is that in that case, it is equivalent to strategy 4.
        t3 = time.time()

        # Make another noise image
        rev_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        rev_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        rev_ii = galsim.InterpolatedImage(rev_image, pad_factor=1)

        rev_sheared_obj = galsim.Convolve(rev_ii, psf_inv).shear(-shear)
        rev_final_obj = galsim.Convolve(psf_target, rev_sheared_obj)
        rev_final_image = rev_final_obj.drawImage(obs_image.copy(),
                                                  method='no_pixel')

        # Add the reverse-sheared noise image to the original image.
        final_image2 = final_image + rev_final_image
        t4 = time.time()

        # The noise variance in the end should be 2x as large as the original
        final_var = np.var(final_image2.array)
        print('Reverse shear method: final_var = ', final_var)
        check_symm_noise(final_image2, 'using reverse shear does not work')
        print('Time for reverse shear method = ', t4 - t3)

    if True:
        print('\n\nStrategy 4:')
        # Strategy 4: Make a noise field and do the same operations as we do to the main image,
        #             then rotate it by 90 degress and add it to the final image.
        # This method works!  Even for an arbitrarily sheared wcs.
        t3 = time.time()

        # Make another noise image
        noise_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        noise_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        noise_ii = galsim.InterpolatedImage(noise_image, pad_factor=1)

        noise_sheared_obj = galsim.Convolve(noise_ii, psf_inv).shear(shear)
        noise_final_obj = galsim.Convolve(psf_target, noise_sheared_obj)
        noise_final_image = noise_final_obj.drawImage(obs_image.copy(),
                                                      method='no_pixel')

        # Rotate the image by 90 degrees
        rot_noise_final_image = galsim.Image(
            np.ascontiguousarray(np.rot90(noise_final_image.array)))

        # Add the rotated noise image to the original image.
        final_image2 = final_image + rot_noise_final_image
        t4 = time.time()

        # The noise variance in the end should be 2x as large as the original
        final_var = np.var(final_image2.array)
        print('Rotate image method: final_var = ', final_var)
        check_symm_noise(final_image2,
                         'using rotated noise image does not work')
        print('Time for rotate image method = ', t4 - t3)

    if False:
        print('\n\nStrategy 5:')
        # Strategy 5: The same as strategy 3, except we target the effective net transformation
        #             done by strategy 4.
        # I think this strategy probably can't work for non-square pixels, because the shear
        # happens before the convolution by the PSF.  And if the wcs is non-square, then the
        # PSF is sheared relative to the pixels.  That shear isn't being accounted for here,
        # so the net result isn't equivalent to rotating by 90 degrees at the end.
        t3 = time.time()

        # Make another noise image
        rev_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        rev_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        rev_ii = galsim.InterpolatedImage(rev_image, pad_factor=1)

        # Find the effective transformation to apply in sky coordinates that matches what
        # you would get by applying the shear in sky coords, going to image coords and then
        # rotating by 90 degrees.
        #
        # If J is the jacobian of the wcs, and S1 is the applied shear, then we want to find
        # S2 such that J^-1 S2 = R90 J^-1 S1
        jac = wcs.jacobian()
        J = jac.getMatrix()
        Jinv = jac.inverse().getMatrix()
        S1 = shear.getMatrix()
        R90 = np.array([[0, -1], [1, 0]])
        S2 = J.dot(R90).dot(Jinv).dot(S1)
        scale, rev_shear, rev_theta, flip = galsim.JacobianWCS(
            *S2.flatten()).getDecomposition()
        # Flip should be False, and scale should be essentially 1.0.
        assert flip == False
        assert abs(scale - 1.) < 1.e-8

        rev_sheared_obj = galsim.Convolve(
            rev_ii, psf_inv).rotate(rev_theta).shear(rev_shear)
        rev_final_obj = galsim.Convolve(psf_target, rev_sheared_obj)
        rev_final_image = rev_final_obj.drawImage(obs_image.copy(),
                                                  method='no_pixel')

        # Add the reverse-sheared noise image to the original image.
        final_image2 = final_image + rev_final_image
        t4 = time.time()

        # The noise variance in the end should be 2x as large as the original
        final_var = np.var(final_image2.array)
        print('Alternate reverse shear method: final_var = ', final_var)
        check_symm_noise(final_image2,
                         'using alternate reverse shear does not work')
        print('Time for alternate reverse shear method = ', t4 - t3)
Ejemplo n.º 16
0
    def __init__(self, image, x_interpolant = None, k_interpolant = None, normalization = 'flux',
                 dx = None, flux = None, pad_factor = 0., noise_pad = 0., rng = None,
                 pad_image = None, calculate_stepk=True, calculate_maxk=True,
                 use_cache=True, use_true_center=True, gsparams=None):

        import numpy as np

        # first try to read the image as a file.  If it's not either a string or a valid
        # pyfits hdu or hdulist, then an exception will be raised, which we ignore and move on.
        try:
            image = galsim.fits.read(image)
        except:
            pass

        # make sure image is really an image and has a float type
        if not isinstance(image, galsim.BaseImageF) and not isinstance(image, galsim.BaseImageD):
            raise ValueError("Supplied image is not an image of floats or doubles!")

        # it must have well-defined bounds, otherwise seg fault in SBInterpolatedImage constructor
        if not image.getBounds().isDefined():
            raise ValueError("Supplied image does not have bounds defined!")

        # check what normalization was specified for the image: is it an image of surface
        # brightness, or flux?
        if not normalization.lower() in ("flux", "f", "surface brightness", "sb"):
            raise ValueError(("Invalid normalization requested: '%s'. Expecting one of 'flux', "+
                              "'f', 'surface brightness', or 'sb'.") % normalization)

        # set up the interpolants if none was provided by user, or check that the user-provided ones
        # are of a valid type
        if x_interpolant is None:
            self.x_interpolant = galsim.InterpolantXY(galsim.Quintic(tol=1e-4))
        else:
            self.x_interpolant = galsim.utilities.convert_interpolant_to_2d(x_interpolant)
        if k_interpolant is None:
            self.k_interpolant = galsim.InterpolantXY(galsim.Quintic(tol=1e-4))
        else:
            self.k_interpolant = galsim.utilities.convert_interpolant_to_2d(k_interpolant)

        # Check for input dx, and check whether Image already has one set.  At the end of this
        # code block, either an exception will have been raised, or the input image will have a
        # valid scale set.
        if dx is None:
            dx = image.scale
            if dx == 0:
                raise ValueError("No information given with Image or keywords about pixel scale!")
        else:
            if type(dx) != float:
                dx = float(dx)
            # Don't change the original image.  Make a new view if we need to set the scale.
            image = image.view()
            image.setScale(dx)
            if dx == 0.0:
                raise ValueError("dx may not be 0.0")

        # Set up the GaussianDeviate if not provided one, or check that the user-provided one is
        # of a valid type.
        if rng is None:
            gaussian_deviate = galsim.GaussianDeviate()
        elif isinstance(rng, galsim.BaseDeviate):
            # Even if it's already a GaussianDeviate, we still want to make a new Gaussian deviate
            # that would generate the same sequence, because later we change the sigma and we don't
            # want to change it for the original one that was passed in.  So don't distinguish
            # between GaussianDeviate and the other BaseDeviates here.
            gaussian_deviate = galsim.GaussianDeviate(rng)
        else:
            raise TypeError("rng provided to InterpolatedImage constructor is not a BaseDeviate")

        # decide about deterministic image padding
        specify_size = False
        padded_size = image.getPaddedSize(pad_factor)
        if pad_image:
            specify_size = True
            if isinstance(pad_image, str):
                pad_image = galsim.fits.read(pad_image)
            if ( not isinstance(pad_image, galsim.BaseImageF) and 
                 not isinstance(pad_image, galsim.BaseImageD) ):
                raise ValueError("Supplied pad_image is not one of the allowed types!")

            # If an image was supplied directly or from a file, check its size:
            #    Cannot use if too small.
            #    Use to define the final image size otherwise.
            deltax = (1+pad_image.getXMax()-pad_image.getXMin())-(1+image.getXMax()-image.getXMin())
            deltay = (1+pad_image.getYMax()-pad_image.getYMin())-(1+image.getYMax()-image.getYMin())
            if deltax < 0 or deltay < 0:
                raise RuntimeError("Image supplied for padding is too small!")
            if pad_factor != 1. and pad_factor != 0.:
                import warnings
                msg =  "Warning: ignoring specified pad_factor because user also specified\n"
                msg += "         an image to use directly for the padding."
                warnings.warn(msg)
        elif noise_pad:
            if isinstance(image, galsim.BaseImageF):
                pad_image = galsim.ImageF(padded_size, padded_size)
            if isinstance(image, galsim.BaseImageD):
                pad_image = galsim.ImageD(padded_size, padded_size)

        # now decide about noise padding
        # First, see if the input is consistent with a float.
        # i.e. it could be an int, or a str that converts to a number.
        try:
            noise_pad = float(noise_pad)
        except:
            pass
        if isinstance(noise_pad, float):
            if noise_pad < 0.:
                raise ValueError("Noise variance cannot be negative!")
            elif noise_pad > 0.:
                # Note: make sure the sigma is properly set to sqrt(noise_pad).
                gaussian_deviate.setSigma(np.sqrt(noise_pad))
                pad_image.addNoise(galsim.DeviateNoise(gaussian_deviate))
        else:
            if isinstance(noise_pad, galsim.correlatednoise._BaseCorrelatedNoise):
                cn = noise_pad.copy()
                if rng: # Let a user supplied RNG take precedence over that in user CN
                    cn.setRNG(gaussian_deviate)
            elif isinstance(noise_pad,galsim.BaseImageF) or isinstance(noise_pad,galsim.BaseImageD):
                cn = galsim.CorrelatedNoise(gaussian_deviate, noise_pad)
            elif use_cache and noise_pad in InterpolatedImage._cache_noise_pad:
                cn = InterpolatedImage._cache_noise_pad[noise_pad]
                if rng:
                    # Make sure that we are using a specified RNG by resetting that in this cached
                    # CorrelatedNoise instance, otherwise preserve the cached RNG
                    cn.setRNG(gaussian_deviate)
            elif isinstance(noise_pad, str):
                cn = galsim.CorrelatedNoise(gaussian_deviate, galsim.fits.read(noise_pad))
                if use_cache: 
                    InterpolatedImage._cache_noise_pad[noise_pad] = cn
            else:
                raise ValueError(
                    "Input noise_pad must be a float/int, a CorrelatedNoise, Image, or filename "+
                    "containing an image to use to make a CorrelatedNoise!")
            pad_image.addNoise(cn)

        # Now we have to check: was the padding determined using pad_factor?  Or by passing in an
        # image for padding?  Treat these cases differently:
        # (1) If the former, then we can simply have the C++ handle the padding process.
        # (2) If the latter, then we have to do the padding ourselves, and pass the resulting image
        # to the C++ with pad_factor explicitly set to 1.
        if specify_size is False:
            # Make the SBInterpolatedImage out of the image.
            sbinterpolatedimage = galsim.SBInterpolatedImage(
                    image, xInterp=self.x_interpolant, kInterp=self.k_interpolant,
                    dx=dx, pad_factor=pad_factor, pad_image=pad_image, gsparams=gsparams)
            self.x_size = padded_size
            self.y_size = padded_size
        else:
            # Leave the original image as-is.  Instead, we shift around the image to be used for
            # padding.  Find out how much x and y margin there should be on lower end:
            x_marg = int(np.round(0.5*deltax))
            y_marg = int(np.round(0.5*deltay))
            # Now reset the pad_image to contain the original image in an even way
            pad_image = pad_image.view()
            pad_image.setScale(dx)
            pad_image.setOrigin(image.getXMin()-x_marg, image.getYMin()-y_marg)
            # Set the central values of pad_image to be equal to the input image
            pad_image[image.bounds] = image
            sbinterpolatedimage = galsim.SBInterpolatedImage(
                    pad_image, xInterp=self.x_interpolant, kInterp=self.k_interpolant,
                    dx=dx, pad_factor=1., gsparams=gsparams)
            self.x_size = 1+pad_image.getXMax()-pad_image.getXMin()
            self.y_size = 1+pad_image.getYMax()-pad_image.getYMin()

        # GalSim cannot automatically know what stepK and maxK are appropriate for the 
        # input image.  So it is usually worth it to do a manual calculation here.
        if calculate_stepk:
            sbinterpolatedimage.calculateStepK()
        if calculate_maxk:
            sbinterpolatedimage.calculateMaxK()

        # If the user specified a flux, then set to that flux value.
        if flux != None:
            if type(flux) != flux:
                flux = float(flux)
            sbinterpolatedimage.setFlux(flux)
        # If the user specified a flux normalization for the input Image, then since
        # SBInterpolatedImage works in terms of surface brightness, have to rescale the values to
        # get proper normalization.
        elif flux is None and normalization.lower() in ['flux','f'] and dx != 1.:
            sbinterpolatedimage.scaleFlux(1./(dx**2))
        # If the input Image normalization is 'sb' then since that is the SBInterpolated default
        # assumption, no rescaling is needed.

        # Initialize the SBProfile
        GSObject.__init__(self, sbinterpolatedimage)

        # Fix the center to be in the right place.
        # Note the minus sign in front of image.scale, since we want to fix the center in the 
        # opposite sense of what the draw function does.
        if use_true_center:
            prof = self._fix_center(image, -image.scale)
            GSObject.__init__(self, prof.SBProfile)