Exemple #1
0
    def __init__(self, sigma):
        if self._erf is None:
            try:
                from scipy.special import erf
                self.__class__._erf = erf
            except (ValueError, ImportError):
                raise ImportError("Gaussian PSF model requires scipy.")
        x_0 = 0
        y_0 = 0
        amplitude = 1
        constraints = {'fixed': {'x_0': True, 'y_0': True, 'sigma': True}}
        super(GaussianPSF, self).__init__(param_dim=1,
                                          sigma=sigma,
                                          x_0=x_0,
                                          y_0=y_0,
                                          amplitude=amplitude,
                                          **constraints)

        # Default size is 8 * sigma
        self.shape = (int(8 * sigma) + 1, int(8 * sigma) + 1)
        self.fitter = fitting.NonLinearLSQFitter()

        # Fix position per default
        self.x_0.fixed = True
        self.y_0.fixed = True
Exemple #2
0
def gaussian_fit(x, y, order=0, **p0):
    """ Fit a Gaussian + polynomial to the data.

        Parameters
        ----------
        x : array_like
        y : array_like
        order : int (optional)
            The order of the Polynomial model. Defaults to constant (order=0).
        **p0
            Initial conditions for the model fit.

    """
    if len(x) != len(y):
        raise ValueError("x and y must have the sample shape!")

    # TODO: when astropy.modeling allows combining models, fix this
    if order > 0:
        raise NotImplementedError()

    #g = custom_model_1d(_gaussian_constant_model)
    g = GaussianPolynomial()
    default_p0 = dict(b=min(y),
                      m=0.,
                      log10_amp=np.log10(max(y)),
                      stddev=0.5,
                      mean=float(np.mean(x)))

    for k, v in default_p0.items():
        setattr(g, k, p0.get(k, v))

    fit = fitting.NonLinearLSQFitter(g)
    fit(x, y)

    return g
def plotStatistcs(data):
    """
    Plot statistics of the background pixels. Assumes that the input contains only
    the background pixel values as a 1D array.

    :return: None
    """
    #search for best bandwidth
    # print 'searching for the best KDE bandwidth'
    # grid = GridSearchCV(KernelDensity(),
    #                     {'bandwidth': np.linspace(0.1, 1.0, 15)}, n_jobs=-1,
    #                     cv=20) # 20-fold cross-validation
    # grid.fit(data.copy())
    # print grid.best_params_
    #derive KDE
    print 'deriving KDE'
    x_grid = np.linspace(data.min(), data.max(), 200)
    #pdf = kde_sklearn(data.copy(), x_grid, bandwidth=grid.best_params_['bandwidth'])
    #pdf = kde_sklearn(data.copy(), x_grid)
    pdf = kde_statsmodels_u(data.copy().astype(np.float64), x_grid, bandwidth=1.5)

    #plot data
    fig, axarr = plt.subplots(1, 2, sharey=True)
    ax1 = axarr[0]
    ax2 = axarr[1]
    fig.subplots_adjust(wspace=0)

    ax1.set_title('Background Pixels')
    ax2.set_title('Models')

    d = ax1.hist(data, bins=np.linspace(data.min(), data.max()), normed=True, alpha=0.7)
    ax1.plot(x_grid, pdf, 'r-', label='Gaussian KDE')

    # Gaussian fit
    x = [0.5 * (d[1][i] + d[1][i+1]) for i in xrange(len(d[1])-1)]
    y = d[0]
    g_init = models.Gaussian1D(amplitude=1., mean=np.mean(data), stddev=np.std(data))
    f2 = fitting.NonLinearLSQFitter()
    g = f2(g_init, x, y)

    ax2.plot(x, g(x), 'b-', label='Gaussian Fit')
    ax2.plot(x_grid, pdf, 'r-', label='Gaussian KDE', alpha=0.7)

    ax1.set_ylabel('PDF')

    ax1.set_xticks(ax1.get_xticks()[:-1])
    ax2.set_xticks(ax2.get_xticks()[1:])

    plt.legend(shadow=True, fancybox=True)
    plt.savefig('backgroundStatistics.pdf')
    plt.close()
Exemple #4
0
    def make_normalized_flat(self, overwrite=False):
        """ Make a normalized Flat frame by fitting and dividing out
            the flat lamp spectrum.

            TODO: right now, this just fits a 1D polynomial. could do
                  a 2D fit to the image instead...

            Parameters
            ----------
            overwrite : bool (optional)
        """

        # TODO: I can't get this 2D fit to work...
        # x, y = np.mgrid[:shp[0], :shp[1]]
        # p = models.Polynomial2DModel(degree=13)
        # fit = fitting.LinearLSQFitter(p)
        # fit(x, y, master_flat)
        # smooth_flat = p(x,y)

        cache_file = os.path.join(self.redux_path, "normalized_flat.fits")

        if os.path.exists(cache_file) and overwrite:
            os.remove(cache_file)

        if not os.path.exists(cache_file):
            # collapse the flat to 1D, fit a polynomial
            master_flat_1d = np.median(self.master_flat, axis=1)
            p = models.Polynomial1DModel(degree=15)
            fit = fitting.NonLinearLSQFitter(p)
            pix = np.arange(len(master_flat_1d))
            fit(pix, master_flat_1d)
            smooth_flat = p(pix)

            # normalize the flat
            n_flat = self.master_flat / smooth_flat[:, np.newaxis]
            hdu = fits.PrimaryHDU(n_flat)
            hdu.writeto(cache_file)
        else:
            n_flat = fits.getdata(cache_file)

        return n_flat
Exemple #5
0
    def __init__(self, prf_array, normalize=True, subsampling=1):

        # Array shape and dimension check
        if subsampling == 1:
            if prf_array.ndim == 2:
                prf_array = np.array([[prf_array]])
        if prf_array.ndim != 4:
            raise TypeError('Array must have 4 dimensions.')
        if prf_array.shape[:2] != (subsampling, subsampling):
            raise TypeError('Incompatible subsampling and array size')
        if np.isnan(prf_array).any():
            raise Exception("Array contains NaN values. Can't create PRF.")

        # Normalize if requested
        if normalize:
            for i in range(prf_array.shape[0]):
                for j in range(prf_array.shape[1]):
                    prf_array[i, j] /= prf_array[i, j].sum()

        # Set PRF asttributes
        self._prf_array = prf_array
        self.subsampling = subsampling

        constraints = {'fixed': {'x_0': True, 'y_0': True}}
        x_0 = 0
        y_0 = 0
        amplitude = 1
        super(DiscretePRF, self).__init__(param_dim=1,
                                          x_0=x_0,
                                          y_0=y_0,
                                          amplitude=amplitude,
                                          **constraints)
        self.linear = True
        self.fitter = fitting.NonLinearLSQFitter()

        # Fix position per default
        self.x_0.fixed = True
        self.y_0.fixed = True
Exemple #6
0
def plotPRNU(data,
             xmin=700,
             xmax=1700,
             ymin=3500,
             ymax=4500,
             order=3,
             smooth=3.):
    """
    Generate and plot maps of PRNU, ratios of PRNU maps, and show the PRNU as a function of wavelength.
    """
    number_of_subplots = math.ceil(len(data.keys()) / 2.)

    plt.figure(figsize=(8, 13))
    plt.subplots_adjust(wspace=0.05,
                        hspace=0.15,
                        left=0.01,
                        right=0.99,
                        top=0.95,
                        bottom=0.05)

    #loop over data from shortest wavelength to the longest
    w = []
    prnu = []
    dat = {}
    for i, wave in enumerate(sorted(data.keys())):

        tmp = data[wave][ymin:ymax, xmin:xmax]
        tmp /= np.median(tmp)

        #meshgrid representing data
        x, y = np.mgrid[:tmp.shape[1], :tmp.shape[0]]

        #fit a polynomial 2d surface to remove the illumination profile
        p_init = models.Polynomial2D(degree=order)
        f = fitting.NonLinearLSQFitter()
        p = f(p_init, x, y, tmp)

        #normalize data
        tmp /= p(x, y)

        print tmp.max(), tmp.min()

        #sigma clipped std to reject dead pixels etc.
        prn = np.std(sigma_clip(tmp, 6.)) * 100.

        print 'PRNU:', prn, 'per cent at lambda =', wave, 'nm'
        w.append(int(wave))
        prnu.append(prn)

        if int(wave) > 750 and int(wave) < 850:
            reference = tmp.copy()
        dat[wave] = tmp.copy()

        #Gaussian smooth to enhance structures for plotting
        tmp = gaussian_filter(tmp, smooth)

        ax = plt.subplot(number_of_subplots, 2, i + 1)
        ax.imshow(tmp,
                  interpolation='none',
                  origin='lower',
                  vmin=0.995,
                  vmax=1.003)

        ax.set_title(r'$\lambda =$ ' + str(int(wave)) + 'nm')

        plt.axis('off')

        #write to file
        fileIO.writeFITS(tmp, str(int(wave)) + '.fits', int=False)

    plt.savefig('PRNUmaps.png')
    plt.close()

    #ratio images
    plt.figure(figsize=(8, 13))
    plt.subplots_adjust(wspace=0.05,
                        hspace=0.15,
                        left=0.01,
                        right=0.99,
                        top=0.95,
                        bottom=0.05)

    for i, wave in enumerate(sorted(dat.keys())):
        tmp = dat[wave]

        #divide by the reference
        tmp /= reference

        #Gaussian smooth to enhance structures for plotting
        tmp = gaussian_filter(tmp, smooth)

        ax = plt.subplot(number_of_subplots, 2, i + 1)
        ax.imshow(tmp,
                  interpolation='none',
                  origin='lower',
                  vmin=0.995,
                  vmax=1.003)

        ax.set_title(r'$\lambda =$ ' + str(int(wave)) + 'nm')

        plt.axis('off')

    plt.savefig('PRNURationmaps.png')
    plt.close()
Exemple #7
0
def plotWavelengthDependency(data,
                             xmin=700,
                             xmax=1700,
                             ymin=3500,
                             ymax=4500,
                             order=3,
                             samples=10):

    #loop over data from shortest wavelength to the longest
    dat = {}
    for i, wave in enumerate(sorted(data.keys())):

        tmp = data[wave][ymin:ymax, xmin:xmax]
        tmp /= np.median(tmp)

        #meshgrid representing data
        x, y = np.mgrid[:tmp.shape[1], :tmp.shape[0]]

        #fit a polynomial 2d surface to remove the illumination profile
        p_init = models.Polynomial2D(degree=order)
        f = fitting.NonLinearLSQFitter()
        p = f(p_init, x, y, tmp)

        #normalize data
        tmp /= p(x, y)

        #select sub regions to calculate the PRNU in
        prnu = []
        ydim, xdim = tmp.shape
        ylen = ydim / samples
        xlen = xdim / samples
        for a in range(samples):
            for b in range(samples):
                area = tmp[a * ylen:(a + 1) * ylen, b * xlen:(b + 1) * xlen]
                prn = np.std(sigma_clip(area, 6.)) * 100.
                prnu.append(prn)

        dat[int(wave)] = prnu

    #calculate the mean for each wavelength and std
    w = []
    mean = []
    std = []
    for wave in sorted(dat.keys()):
        m = np.mean(dat[wave])
        s = np.std(dat[wave])
        w.append(wave)
        mean.append(m)
        std.append(s)
        print wave, m, s

    #polynomial fit to PRNU datra
    z2 = np.polyfit(w, mean, 2)
    p2 = np.poly1d(z2)
    z3 = np.polyfit(w, mean, 3)
    p3 = np.poly1d(z3)
    x = np.linspace(500, 950)

    #wavelength dependency plot
    plt.title('Wavelength Dependency of the PRNU')
    plt.plot(x, p2(x), 'b-', label='2nd order fit')
    plt.plot(x, p3(x), 'g--', label='3rd order fit')
    plt.errorbar(w,
                 mean,
                 yerr=3 * np.asarray(std),
                 c='r',
                 fmt='o',
                 label='data, $3\sigma$ errors')
    plt.xlabel(r'Wavelength $\lambda$ [nm]')
    plt.ylabel(r'PRNU $[\%]$')
    plt.xlim(500, 950)
    plt.ylim(0.4, 0.8)
    plt.legend(shadow=True, fancybox=True, scatterpoints=1, numpoints=1)
    plt.savefig('PRNUwave.pdf')
    plt.close()
Exemple #8
0
def normaliseFlat(data, output, order=5, mask=True, method='boxcar'):
    """
    Normalise each quadrant separately. If limit set use to to generate a mask.
    """
    #split to quadrants
    Q0 = data[7:2052, 57:2098].copy()
    Q2 = data[2543:4592, 57:2098].copy()
    Q1 = data[7:2052, 2505:4545].copy()
    Q3 = data[2543:4592, 2505:4545].copy()
    Qs = [Q0, Q1, Q2, Q3]

    res = []
    for tmp in Qs:
        if mask:
            print 'Using masked 2D arrays (not applied in spline fitting)...'
            # median = np.median(tmp)
            # msk = (tmp > median*0.88) & (tmp < 40000.)
            # #note the inversion of the mask before applying, as for numpy masked arrays True means masking
            # #while in my selection above True means good data
            # t = np.ma.MaskedArray(tmp, mask=~msk)
            t = sigma_clip(
                tmp, sig=3.
            )  #this can be used to generate automatically a masked array
        else:
            print 'No 2D masking applied...'
            t = tmp.copy()

        if method is 'surface':
            print 'Fitting a surface to model the illumination profile'
            #meshgrid representing data
            x, y = np.mgrid[:t.shape[0], :t.shape[1]]

            #fit a polynomial 2d surface to remove the illumination profile
            p_init = models.Polynomial2D(degree=order)
            f = fitting.NonLinearLSQFitter()
            p = f(p_init, x, y, t)

            #normalize data and save it to res list
            tmp /= p(x, y)

        elif method is 'boxcar':
            size = 15  #this is very small, so will probably smooth out some actual PRNU, but needed to remove dust specs
            print 'Using a boxcar smoothed image to model the illumination profile'
            #will have to convert masked array to NaN array as convolve does not support masks
            t = t.filled(np.nan)
            box_2D_kernel = Box2DKernel(size)
            if size > 50:
                model = convolve_fft(t, box_2D_kernel)
            else:
                model = convolve(t, box_2D_kernel)  #faster for small kernels
            tmp /= model

        elif method is 'spline':
            spacing = 27
            print 'Fitting 1D splines to each row to model the illumination profile'

            for i, line in enumerate(tmp):
                #Initializes the instance with dummy xnodes
                Spline = splineFitting.SplineFitting([
                    0,
                ])

                #filter dead pixels from the data
                y = line.copy()
                median = np.median(y)
                y = y[
                    y > median *
                    0.92]  #this is pretty aggressive masking, but needed because of no dead pixel map
                x = np.arange(len(y))

                #Median filter the data
                medianFiltered = signal.medfilt(y, 25)

                #Spline nodes and initial guess for y positions from median filtered
                xnods = np.arange(0, len(y), spacing)
                ynods = medianFiltered[xnods]
                #Updates dummy xnodes in Spline instance with real deal
                Spline.xnodes = xnods

                #Do the fitting
                fittedYnodes, success = Spline.doFit(ynods, x, y)

                #normalize the line with the fit
                tmp[i, :] /= Spline.fitfunc(np.arange(len(line)), fittedYnodes)

        else:
            print 'No fitting method selected, will exit...'
            sys.exit(-9)

        res.append(tmp)
        print np.mean(tmp), np.median(tmp), np.std(tmp)

    #save out
    out = np.zeros_like(data)
    out[7:2052, 57:2098] = res[0]
    out[7:2052, 2505:4545] = res[1]
    out[2543:4592, 57:2098] = res[2]
    out[2543:4592, 2505:4545] = res[3]

    fileIO.writeFITS(out, output + 'FlatField%s.fits' % (method), int=False)

    return out