Image cutouts¶
Image cutouts, or postage stamps, are useful for quick visual characterization of the detected transients or artefacts. We have a set of functions inside stdpipe.cutouts sub-module that ease these tasks.
They all work with the cutout structure returned by stdpipe.cutouts.get_cutout() that contains the stamps of requested size around the object from various image planes (science image, template, background map, mask, footprint map, …), as well as some meta-information.
# Create and display the cutouts from an image and its mask
for i,cand in enumerate(candidates):
# Create the cutout from image based on the candidate
cutout = cutouts.get_cutout(image, cand, 20, mask=mask, header=header)
# We may directly download the template image for this cutout
# from HiPS server - same scale and orientation, but different PSF shape!..
cutout['template'] = templates.get_hips_image('PanSTARRS/DR1/r',
header=cutout['header'], get_header=False)
# We do not have difference image, so it will only display original one, template and mask
plots.plot_cutout(cutout, planes=['image', 'template', 'mask'],
qq=[0.5, 99.9], stretch='linear')
plt.show()
# Create and display the cutouts from a full set of image subtraction results
for i,cand in enumerate(candidates):
print('Candidate %d with mag = %.2f +/- %.2f at x/y = %.1f %.1d and RA/Dec = %.4f %.4f' %
(i, cand['mag_calib'], cand['mag_calib_err'], cand['x'], cand['y'], cand['ra'], cand['dec']))
cutout = cutouts.get_cutout(image, cand, 20, mask=mask|tmask, diff=diff, template=tmpl,
convolved=conv, err=ediff, header=header, filename=filename, time=time)
plots.plot_cutout(cutout, ['image', 'template', 'convolved', 'diff', 'mask'],
qq=[0.5, 99.5], stretch='linear')
plt.show()
# Also, store the cutout!
cutouts.write_cutout(cutout, 'candidates/cutout_%03d.fits' % i)
- stdpipe.cutouts.get_cutout(image, candidate, radius, header=None, wcs=None, time=None, filename=None, name=None, **kwargs)[source]
Create a cutout postage stamp from one or more image planes.
The candidate may be a row from
astropy.table.Tableor a dict with at leastxandykeys. The cutout is centered so the object falls inside the central pixel; size is2*ceil(radius) + 1pixels.- Parameters:
- imagendarray
Primary (science) image plane.
- candidatetable row or dict
Object record containing at least
xandypixel coordinates.- radiusfloat
Cutout half-size in pixels.
- headerastropy.io.fits.Header, optional
Header of the original image. Copied and adjusted to represent the cutout WCS; stored as
cutout['header'].- wcsastropy.wcs.WCS, optional
WCS of the original image. Adjusted and stored as
cutout['wcs']. Takes precedence overheaderfor WCS.- timeastropy.time.Time, datetime, or str, optional
Observation timestamp; stored in
cutout['meta']['time'].- filenamestr, optional
Source image filename; stored in
cutout['meta']['filename'].- namestr, optional
Object name; stored in
cutout['meta']['name']. If omitted andcandidatehasra/dec, a J2000 name is constructed.- **kwargs
Additional 2D arrays interpreted as extra image planes (e.g.
mask,diff,template,convolved,err).
- Returns:
- dict
Cutout dictionary with at least:
image— primary image planemask,diff,template, etc. — extra planes if providedheader— adjusted FITS header, if providedwcs— adjusted WCS, if providedmeta— dict with all candidate fields plustime,filename, andname
Saving and loading the cutouts¶
Cutouts may be easily written to multi-extension FITS images, and restored from them later using the following functions:
- stdpipe.cutouts.write_cutout(cutout, filename)[source]
Store a cutout as a multi-extension FITS file.
Each image plane becomes a named FITS extension; metadata is stored as keywords in the primary header.
- Parameters:
- cutoutdict
Cutout structure as returned by
get_cutout().- filenamestr
Output FITS filename.
- stdpipe.cutouts.load_cutout(filename)[source]
Restore a cutout from a multi-extension FITS file.
- Parameters:
- filenamestr
Path to a FITS file written by
write_cutout().
- Returns:
- dict
Cutout structure as returned by
get_cutout().
Plotting the cutouts¶
There is a dedicated plotting routine that helps quickly visualize the information contained in it, including its different image planes - stdpipe.plots.plot_cutout()
- stdpipe.plots.plot_cutout(cutout, planes=['image', 'template', 'diff', 'mask'], fig=None, axs=None, mark_x=None, mark_y=None, mark_r=5.0, mark_r2=None, mark_r3=None, mark_color='red', mark_lw=2, mark_ra=None, mark_dec=None, r0=None, show_title=True, title=None, additional_title=None, **kwargs)[source]
Display image planes from a cutout structure in a single row.
- Parameters:
- cutoutdict
Cutout structure as returned by
stdpipe.cutouts.get_cutout().- planeslist of str, optional
Names of cutout planes to show (in order).
- figmatplotlib.figure.Figure, optional
Figure to draw into; a new figure is created if not provided.
- axslist of matplotlib.axes.Axes, optional
Axes to draw into; must be the same length as
planes.- mark_xfloat, optional
X coordinate (in cutout pixels) of the circular overlay mark.
- mark_yfloat, optional
Y coordinate (in cutout pixels) of the circular overlay mark.
- mark_rfloat, optional
Radius of the overlay mark in pixels.
- mark_r2float, optional
Radius of a secondary dashed overlay circle.
- mark_r3float, optional
Radius of a tertiary dashed overlay circle.
- mark_colorcolor, optional
Color of the overlay mark.
- mark_lwfloat, optional
Line width of the overlay mark.
- mark_rafloat, optional
RA of the overlay mark; overrides
mark_x/mark_y.- mark_decfloat, optional
Dec of the overlay mark; overrides
mark_x/mark_y.- r0float, optional
Gaussian smoothing sigma applied to
image,template, anddiffplanes.- show_titlebool, optional
If True (default), display a title above the cutout row.
- titlestr, optional
Title text. Auto-generated from cutout metadata if not provided.
- additional_titlestr, optional
Text appended to the auto-generated title.
- **kwargs
Additional keyword arguments passed to
imshow()for each plane.
Cutout-level rejection of subtraction artefacts¶
The difference image often contains the characteristic artefacts (“dipoles”) due to slight sub-pixel displacement of the object between the science image and the template (e.g. due to imperfect astrometric alignment, or due to large proper motion for the templates acquired long ago). Also, the intensity of the object may also be slightly different on the science image - e.g. due to slightly different photometric band - that leads to unshifted positive or negative differences. In principle, such cases may be automatically detected and - if appropriate - rejected by a simple adjustment procedure based solely on the information we already have inside typical cutout. The adjustment here means optimizing slight (sub-pixel) shifts between the image and (convolved) template, as well as slight scaling of the template, in order to minimize the residuals. We have a dedicated routine, stdpipe.cutouts.adjust_cutout(), that tries to perform such optimization, and may be used inside the pipelines like in the following example:
for i,cand in enumerate(candidates):
print('Candidate %d with mag = %.2f +/- %.2f at x/y = %.1f %.1d and RA/Dec = %.4f %.4f' %
(i, cand['mag_calib'], cand['mag_calib_err'], cand['x'], cand['y'], cand['ra'], cand['dec']))
# Produce the cutout with all necessary planes
cutout = cutouts.get_cutout(image, cand, 20, mask=mask|tmask, diff=diff, template=tmpl,
convolved=conv, err=ediff, header=header, filename=filename, time=time)
# Try to adjust the position and scale of the cutout to see whether it disappears or not
# Here we use only inner 2*fwhm x 2*fwhm part for fitting
# and limit possible shifts and scale to 1 pixel and 2.0, correspondingly
if cutouts.adjust_cutout(cutout, inner=2*fwhm, max_shift=1, max_scale=2.0,
fit_bg=True, normalize=False, verbose=True):
# The optimization converged - now we may check its actual adjustment
# and decide whether the transient disappeared or not
# E.g. we see whether final chi2 is at least 3 times smaller than original one
# and its corresponding p-value is worse than 1e-5
# and the fitted scale is between 0.8 and 1.2
if ((cutout['meta']['adjust_pval'] > 1e-5 or
cutout['meta']['adjust_chi2'] < 0.3*cutout['meta']['adjust_chi2_0']) and
cutout['meta']['adjust_scale'] > 0.8 and cutout['meta']['adjust_scale'] < 1.2):
# Well, it really "disappeared"
print("The candidate is no more significant"
cutout['meta']['adjusted'] = True
# We may now plot the results, including the results of the adjustment routine
# It will be shown in `adjusted` plane, if the optimization converged
plots.plot_cutout(cutout, ['image', 'template', 'convolved', 'diff', 'adjusted', 'mask'],
qq=[0.5, 99.5], stretch='linear')
- stdpipe.cutouts.adjust_cutout(cutout, max_shift=2, max_scale=1.1, inner=None, normalize=False, fit_bg=False, verbose=False)[source]
Fit a positional and flux-scaling adjustment to minimize the image–template residual.
Optimizes a shift (dx, dy), scale, and optionally background levels to minimize the chi-squared residual between
cutout['image']andcutout['convolved']. On success, adds acutout['adjusted']plane with the optimized difference.- Parameters:
- cutoutdict
Cutout structure as returned by
get_cutout(). Must containimage,convolved, anderrplanes.- max_shiftfloat, optional
Maximum allowed positional shift in pixels (symmetric bound).
- max_scalefloat, optional
Maximum allowed flux scale factor; scale is bounded to
(1/max_scale, max_scale).- innerint, optional
If set, only the central
inner × innerpixel box is used for optimization.- normalizebool, optional
If True, divide the
adjustedplane by theerrplane.- fit_bgbool, optional
If True, fit background levels as free parameters. If False, estimate backgrounds from the cutout using SExtractor-mode (
2.5*median − 1.5*mean) and hold them fixed.- verbosebool or callable, optional
Whether to show verbose messages. May be boolean or a
print-like callable.
- Returns:
- bool
Trueif optimization succeeded,Falseotherwise.
Notes
On success the following keys are added to
cutout['meta']:adjust_chi2_0,adjust_chi2,adjust_df,adjust_pval,adjust_dx,adjust_dy,adjust_scale,adjust_bg,adjust_tbg.