Fit and remove the PSF (psfsubtraction.fitpsf)

This is the core of the package.


  • All positions and distances are given in pixels.
  • Positions are given as floats where the unit of pixels is implied.
  • Angles require a Quantity object.

Data with missing or bad values

We often need a template-based PSF subtraction when the central object is very bright, at least much brighter than the companion we want to detect. Thus, we often have pixels in the image that are saturated or bleed columns or other artifacts that should not be used in the fitting. There might also be cosmic-rays or hot pixels on the detector. While it is often possibly to minimize the number of unusable pixels with a clever observing strategy, this package implements mechanisms to deal with bad or missing values.

If any pixel has a bad or missing value, all data (image and PSF base) should be expressed as, where the mask is set to True for bad or missing values.

Most functions in this package accept masked arrays and those that do not will raise an exception when they detected masked pixels.


For the examples below, we will generate some artifical data here (TODO: bundle some real data with the package for use in examples and testing):

>>> from psfsubtraction import data
>>> psfbase, image, image2 = data.gaussian_PSFs()

We can now instanciate a fitter object and use it to remove the PSF from image, looking for what’s left:

>>> from psfsubtraction.fitpsf import fitters
>>> my_fitter = fitters.SimpleSubtraction(psfbase, image)
>>> residual = my_fitter.remove_psf()

Let’s now compare the initial image and the PSF subtracted image (note the different scales on both images):

(Source code, png, hires.png, pdf)


The fitter object

As shown in the example above, the PSF fit is done through a fitter object. This object specifies the algorithm (e.g. is the entire image fitted at once? If not, how are regions split up? How is the fit optimized? What about masked values?).

A fitter is initialized with a (masked) numpy array of PSF bases in the shape (m, n, k) where (n, m) are the dimensions of the images and k is the number of bases:

>>> my_fitter = fitters.SimpleSubtraction(psfbase)

This package comes with a selection of fitters which are listed below in the API docs and Adapt the fitters for your use case shows how to define variants of those or completely new fitters.

Specifying an image for the fitter

In order to do anything useful, a fitter object also needs an (n, m) (masked) numpy array for the image. This can either be set when the fitter object is created:

>>> my_fitter = fitters.SimpleSubtraction(psfbase, image)

or set as an attribute later:

>>> my_fitter.image = image

or be passed as an argument to the remove_psf or fit_psf functions:

>>> fitted_psf = my_fitter.fit_psf(image)

See Two ways to fit several images to the same base for an example where each of these possibilities might be useful.

Specifying parameters for a fitter

In some cases, attributes of the fitter object control the parameters of the fit, e.g. a LOCI fitter splits an image into concentric rings. It has an attribute fitter.sector_radius_n that determines the number of such rings:

>>> my_fitter = fitters.LOCI(psfbase)
>>> my_fitter.sector_radius_n = 5

If a fitter has options, they are listed in the docstring.

Masked data

Not all fitters can deal with bad or missing data. However, all fitters accept masked_array objects as input, provided there are no maked values. This is done so that the same code can be used to read in the data and prepare the arrays for both fitters that treat masked data and those that do not. Most fitters that do not accept masked data will issue a warning or an exception when they encounter a mask.

psfsubtraction.fitpsf Package


all_unmasked(self, region, indpsf) Here we select the maximal region.
allbases(self, region) Return all available bases.
around_region(self, region, indpsf) similar to dilated_region, but exclude all pixels in region itself.
dilated_region(self, region, indpsf) Specify a optimization region that extends around the region.
group_by_basis(self) Group pixels with the same valid bases into one region.
identity(self, region, indpsf) Return a input region as optimization region.
image_at_once(self) Fit whole image at one.
image_unmasked(self) Return the unmasked part of an image.
mask_except_pixel(self, pix) Helper function - make True/False mask that is True at pix
nonmaskedbases(self, region) Return all bases that are not masked in any pixel in region
pixel_by_pixel(self) Each pixel it its own region.
psf_from_projection(self, image1d, psfbase) solve a linear algebra system for the best PSF
sectors(self) Generate a function that generates sector regions
sectors_by_basis(self) Combines sectors and group_by_basis.
wrapper_ignore_all_masked(func) Wrap a optregion function to remove all masked pixels from optregion.
wrapper_optmask(func) Wrap an optregion function to apply an additional global mask.


BasePSFFitter(psfbase[, image]) Base object for PSF fitting.
CepheidSnapshotpaper(*args, **kwargs)
LOCI(psfbase[, image]) LOCI fitter (locally optimized combination of images)
LOCIAllPixelsSubtraction(psfbase[, image]) LOCI fitter that splits LOCI regions according to the available PSF bases.
OptionalAttributeError Problem with optional attribute in the PSF fitter class.
PSFIndexError PSF Index array does not have the right shape or dtype
RegionError Region does not have the right shape or dtype
SimpleSubtraction(psfbase[, image]) Simple examples of PSF fitting.
UseAllPixelsSubtraction(psfbase[, image]) Use all available pixels of the image.

Class Inheritance Diagram

Inheritance diagram of psfsubtraction.fitpsf.fitters.BasePSFFitter, psfsubtraction.fitpsf.fitters.CepheidSnapshotpaper, psfsubtraction.fitpsf.fitters.LOCI, psfsubtraction.fitpsf.fitters.LOCIAllPixelsSubtraction, psfsubtraction.fitpsf.utils.OptionalAttributeError, psfsubtraction.fitpsf.fitters.PSFIndexError, psfsubtraction.fitpsf.fitters.RegionError, psfsubtraction.fitpsf.fitters.SimpleSubtraction, psfsubtraction.fitpsf.fitters.UseAllPixelsSubtraction