Resample a region of a data grid
You should use a resampling function which matches the
numerical type of the data you are processing by replacing
$<$X$>$
in the generic function name astResample$<$X$>$
by an appropriate 1- or 2-character type code. For example, if you are resampling
data with type "
float"
, you should use the function astResampleF (see the "
Data Type Codes"
section below for the codes appropriate to other numerical
types).
Resampling of the grid of input data is performed by transforming the coordinates of the centre of each output grid element (or pixel) into the coordinate system of the input grid. Since the resulting coordinates will not, in general, coincide with the centre of an input pixel, sub-pixel interpolation is performed between the neighbouring input pixels. This produces a resampled value which is then assigned to the output pixel. A choice of sub-pixel interpolation schemes is provided, but you may also implement your own.
This algorithm samples the input data value, it does not integrate it. Thus total data value
in the input image will not, in general, be conserved. However, an option is provided (see
the "
Control Flags"
section below) which can produce approximate flux conservation by
scaling the output values using the ratio of the output pixel size to the input pixel
size. However, if accurate flux conservation is important to you, consder using the
astRebin$<$X$>$
or astRebinSeq$<$X$>$
family of functions instead.
Output pixel coordinates are transformed into the coordinate system of the
input grid using the inverse transformation of the Mapping which is supplied.
This means that geometrical features in the input data are subjected to the
Mapping’
s forward transformation as they are transferred from the input to the
output grid (although the Mapping’
s forward transformation is not explicitly
used).
In practice, transforming the coordinates of every pixel of a large data grid can be time-consuming, especially if the Mapping involves complicated functions, such as sky projections. To improve performance, it is therefore possible to approximate non-linear Mappings by a set of linear transformations which are applied piece-wise to separate sub-regions of the data. This approximation process is applied automatically by an adaptive algorithm, under control of an accuracy criterion which expresses the maximum tolerable geometrical distortion which may be introduced, as a fraction of a pixel.
This algorithm first attempts to approximate the Mapping with a linear transformation applied over the whole region of the output grid which is being used. If this proves to be insufficiently accurate, the output region is sub-divided into two along its largest dimension and the process is repeated within each of the resulting sub-regions. This process of sub-division continues until a sufficiently good linear approximation is found, or the region to which it is being applied becomes too small (in which case the original Mapping is used directly).
The number of input coordinates used by this Mapping (as given by its Nin attribute)
should match the number of input grid dimensions given by the value of "
ndim_in"
below. Similarly, the number of output coordinates (Nout attribute) should match the
number of output grid dimensions given by "
ndim_out"
.
"
ndim_in"
elements, containing the coordinates
of the centre of the first pixel in the input grid along each dimension. "
ndim_in"
elements, containing
the coordinates of the centre of the last pixel in the input grid along each
dimension.
Note that "
lbnd_in"
and "
ubnd_in"
together define the shape and size of
the input grid, its extent along a particular (j’
th) dimension being
ubnd_in[j]-lbnd_in[j]$+$1
(assuming the index "
j"
to be zero-based). They also define the input grid’
s
coordinate system, each pixel having unit extent along each dimension with integral
coordinate values at its centre.
"
float"
).
The storage order of data within this array should be such that the index of the first grid dimension varies most rapidly and that of the final dimension least rapidly (i.e. Fortran array indexing is used).
"
in"
array. If given, this should contain a set of
non-negative values which represent estimates of the statistical variance associated
with each element of the "
in"
array. If this array is supplied (together with the
corresponding "
out_var"
array), then estimates of the variance of the resampled output
data will be calculated.
If no input variance estimates are being provided, a NULL pointer should be given.
"
Sub-Pixel
Interpolation Schemes"
section below. If a value of zero is supplied, then the
default linear interpolation scheme is used (equivalent to supplying the value
AST__LINEAR).
Alternatively, you may supply a value which indicates that you will provide your own
function to perform sub-pixel interpolation by means of the "
finterp "
parameter.
Again, see the "
Sub-Pixel Interpolation Schemes"
section below for details.
"
interp"
parameter indicates that you will provide your
own function for sub-pixel interpolation, then a pointer to that function should be
given here. For details of the interface which the function should have (several are
possible, depending on the value of "
interp"
), see the "
Sub-Pixel Interpolation
Schemes"
section below.
If the "
interp"
parameter has any other value, corresponding to one of the pre-defined
interpolation schemes, then this function will not be used and you may supply a NULL
pointer.
"
Sub-Pixel Interpolation Schemes"
section below (you may also use this array to pass values to your own interpolation
function).
If no additional parameters are required, this array is not used and a NULL pointer may be given.
"
Control Flags"
section below for a description of the options available. If
no flag values are to be set, a value of zero should be given. ’
s coordinate
system.
If piece-wise linear approximation is not required, a value of zero may be given. This will ensure that the Mapping is used without any approximation, but may increase execution time.
If a smaller value is used, the output region will first be divided into sub-regions
whose size does not exceed "
maxpix"
pixels in any dimension. Only at this point will
attempts at approximation commence.
This value may occasionally be useful in preventing false convergence of the adaptive algorithm in cases where the Mapping appears approximately linear on large scales, but has irregularities (e.g. holes) on smaller scales. A value of, say, 50 to 100 pixels can also be employed as a safeguard in general-purpose software, since the effect on performance is minimal.
If too small a value is given, it will have the effect of inhibiting linear
approximation altogether (equivalent to setting "
tol"
to zero). Although this
may degrade performance, accurate results will still be obtained.
"
in"
array. It
specifies the value used to flag missing data (bad pixels) in the input and output
arrays.
If the AST__USEBAD flag is set via the "
flags"
parameter, then this value is used to
test for bad pixels in the "
in"
(and "
in_var"
) array(s).
Unless the AST__NOBAD flag is set via the "
flags"
parameter, this value is also used
to flag any output elements in the "
out"
(and "
out_var"
) array(s) for which
resampled values could not be obtained (see the "
Propagation of Missing Data"
section below for details of the circumstances under which this may occur). The
astResample$<$X$>$
function return value indicates whether any such values have been produced. If the
AST__NOBAD flag is set. then output array elements for which no resampled value could
be obtained are left set to the value they had on entry to this function.
"
ndim_out"
elements, containing the coordinates
of the centre of the first pixel in the output grid along each dimension. "
ndim_out"
elements, containing
the coordinates of the centre of the last pixel in the output grid along each
dimension.
Note that "
lbnd_out"
and "
ubnd_out"
together define the shape, size and coordinate
system of the output grid in the same way as "
lbnd_in"
and "
ubnd_in"
define the
shape, size and coordinate system of the input grid.
"
ndim_out"
elements, containing the coordinates of the first pixel in
the region of the output grid for which a resampled value is to be calculated. "
ndim_out"
elements, containing the coordinates
of the last pixel in the region of the output grid for which a resampled value is to be
calculated.
Note that "
lbnd"
and "
ubnd"
together define the shape and position of a
(hyper-)rectangular region of the output grid for which resampled values should be
produced. This region should lie wholly within the extent of the output grid (as
defined by the "
lbnd_out"
and "
ubnd_out"
arrays). Regions of the output grid
lying outside this region will not be modified.
"
in"
array, and the data storage order should be such that the
index of the first grid dimension varies most rapidly and that of the final
dimension least rapidly (i.e. Fortran array indexing is used). "
out"
array. If
given, this array will be used to return variance estimates for the resampled
data values. This array will only be used if the "
in_var"
array has also been
supplied.
The output variance values will be calculated on the assumption that errors on the input data values are statistically independent and that their variance estimates may simply be summed (with appropriate weighting factors) when several input pixels contribute to an output data value. If this assumption is not valid, then the output error estimates may be biased. In addition, note that the statistical errors on neighbouring output data values (as well as the estimates of those errors) may often be correlated, even if the above assumption about the input data is correct, because of the sub-pixel interpolation schemes employed.
If no output variance estimates are required, a NULL pointer should be given.
"
badval"
and "
flags"
parameters. A value of zero will be returned if this function is invoked with the global error status set, or if it should fail for any reason.
D: double
F: float
L: long int (may be 32 or 64 bit)
K: 64 bit int
UL: unsigned long int (may be 32 or 64 bit)
UK: unsigned 64 bit int
I: int
UI: unsigned int
S: short int
US: unsigned short int
B: byte (signed char)
UB: unsigned byte (unsigned char)
For example, astResampleD would be used to process "
double"
data, while astResampleS
would be used to process "
short int"
data, etc.
In general, a balance must be struck between schemes which tend to degrade sharp
features in the data by smoothing them, and those which attempt to preserve sharp
features. The latter will often tend to introduce unwanted oscillations, typically
visible as "
ringing"
around sharp features and edges, especially if the data are
under-sampled (i.e. if the sharpest features are less than about two pixels across). In
practice, a good interpolation scheme is likely to be a compromise and may exhibit some
aspects of both these features.
For under-sampled data, some interpolation schemes may appear to preserve data resolution because they transform single input pixels into single output pixels, rather than spreading their data between several output pixels. While this may look better cosmetically, it can result in a geometrical shift of sharp features in the data. You should beware of this if you plan to use such features (e.g.) for image alignment.
The following are two easy-to-use sub-pixel interpolation schemes which are generally
applicable. They are selected by supplying the appropriate value (defined in the "
ast.h"
header file) via the "
interp"
parameter. In these cases, the "
finterp"
and "
params"
parameters are not used:
AST__NEAREST: This is the simplest possible scheme, in which the value of the input pixel with the nearest centre to the interpolation point is used. This is very quick to execute and will preserve single-pixel features in the data, but may displace them by up to half their width along each dimension. It often gives a good cosmetic result, so is useful for quick-look processing, but is unsuitable if accurate geometrical transformation is required.
AST__LINEAR: This is the default scheme, which uses linear interpolation between the nearest neighbouring pixels in the input grid (there are two neighbours in one dimension, four neighbours in two dimensions, eight in three dimensions, etc.). It is superior to the nearest-pixel scheme (above) in not displacing features in the data, yet it still executes fairly rapidly. It is generally a safe choice if you do not have any particular reason to favour another scheme, since it cannot introduce oscillations. However, it does introduce some spatial smoothing which varies according to the distance of the interpolation point from the neighbouring pixels. This can degrade the shape of sharp features in the data in a position-dependent way. It may also show in the output variance grid (if used) as a pattern of stripes or fringes.
An alternative set of interpolation schemes is based on forming the interpolated value
from the weighted sum of a set of surrounding pixel values (not necessarily just the
nearest neighbours). This approach has its origins in the theory of digital filtering,
in which interpolated values are obtained by conceptually passing the sampled data
(represented by a grid of delta functions) through a linear filter which implements a
convolution. Because the convolution kernel is continuous, the convolution
yields a continuous function which may then be evaluated at fractional pixel
positions. The (possibly multi-dimensional) kernel is usually regarded as "
separable"
and formed from the product of a set of identical 1-dimensional kernel
functions, evaluated along each dimension. Different interpolation schemes are
then distinguished by the choice of this 1-dimensional interpolation kernel.
The number of surrounding pixels which contribute to the result may also be
varied.
From a practical standpoint, it is useful to divide the weighted sum of pixel values by the sum of the weights when determining the interpolated value. Strictly, this means that a true convolution is no longer being performed. However, the distinction is rarely important in practice because (for slightly subtle reasons) the sum of weights is always approximately constant for good interpolation kernels. The advantage of this technique, which is used here, is that it can easily accommodate missing data and tends to minimise unwanted oscillations at the edges of the data grid.
In the following schemes, which are based on a 1-dimensional interpolation kernel, the
first element of the "
params"
array should be used to specify how many pixels are
to contribute to the interpolated result on either side of the interpolation
point in each dimension (the nearest integer value is used). Execution time
increases rapidly with this number. Typically, a value of 2 is appropriate and
the minimum value used will be 1 (i.e. two pixels altogether, one on either
side of the interpolation point). A value of zero or less may be given for "
params[0]"
to indicate that a suitable number of pixels should be calculated
automatically.
In each of these cases, the "
finterp"
parameter is not used:
AST__GAUSS: This scheme uses a kernel of the form
exp(-k$\ast $x$\ast $x),
with k a positive constant. The full-width at half-maximum (FWHM) is given by "
params[1]"
to zero will select the number of contributing pixels so as to utilise the
width of the kernel out to where the envelope declines to 1% of its maximum
value). This kernel suppresses noise at the expense of smoothing the output
array.
AST__SINC: This scheme uses a sinc(pi$\ast $x)
kernel, where x is the pixel offset from the interpolation point and sinc(z)=sin(z)/z.
This sometimes features as an "
optimal"
interpolation kernel in books on image
processing. Its supposed optimality depends on the assumption that the data are
band-limited (i.e. have no spatial frequencies above a certain value) and are
adequately sampled. In practice, astronomical data rarely meet these requirements. In
addition, high spatial frequencies are often present due (e.g.) to image defects and
cosmic ray events. Consequently, substantial ringing can be experienced with this
kernel. The kernel also decays slowly with distance, so that many surrounding pixels
are required, leading to poor performance. Abruptly truncating it, by using only a few
neighbouring pixels, improves performance and may reduce ringing (if "
params[0]"
is
set to zero, then only two pixels will be used on either side). However, a more gradual
truncation, as implemented by other kernels, is generally to be preferred.
This kernel is provided mainly so that you can convince yourself not to use
it!
AST__SINCSINC: This scheme uses an improved kernel, of the form
sinc(pi$\ast $x).sinc(k$\ast $pi$\ast $x),
with k a constant, out to the point where
sinc(k$\ast $pi$\ast $x)
goes to zero, and zero beyond. The second sinc() factor provides an "
envelope"
which gradually rolls
off the normal sinc(pi$\ast $x)
kernel at large offsets. The width of this envelope is specified by giving the number
of pixels offset at which it goes to zero by means of the "
params[1]"
value, which
should be at least 1.0 (in addition, setting "
params[0]"
to zero will select the
number of contributing pixels so as to utilise the full width of the kernel, out to
where it reaches zero). The case given by "
params[0]=2, params[1]=2"
is typically a
good choice and is sometimes known as the Lanczos kernel. This is a valuable
general-purpose interpolation scheme, intermediate in its visual effect on
images between the AST__NEAREST and AST__LINEAR schemes. Although the kernel is
slightly oscillatory, ringing is adequately suppressed if the data are well
sampled.
AST__SINCCOS: This scheme uses a kernel of the form
sinc(pi$\ast $x).cos(k$\ast $pi$\ast $x),
with k a constant, out to the point where
cos(k$\ast $pi$\ast $x)
goes to zero, and zero beyond. As above, the cos() factor provides an envelope
which gradually rolls off the sinc() kernel at large offsets. The width of this
envelope is specified by giving the number of pixels offset at which it goes
to zero by means of the "
params[1]"
value, which should be at least 1.0 (in
addition, setting "
params[0]"
to zero will select the number of contributing
pixels so as to utilise the full width of the kernel, out to where it reaches
zero). This scheme gives similar results to the AST__SINCSINC scheme, which it
resembles.
AST__SINCGAUSS: This scheme uses a kernel of the form
sinc(pi$\ast $x).exp(-k$\ast $x$\ast $x),
with k a positive constant. Here, the sinc() kernel is rolled off using a Gaussian
envelope which is specified by giving its full-width at half-maximum (FWHM) by means of
the "
params[1]"
value, which should be at least 0.1 (in addition, setting "
params[0]"
to zero will select the number of contributing pixels so as to utilise the width of the
kernel out to where the envelope declines to 1% of its maximum value). On astronomical
images and spectra, good results are often obtained by approximately matching the FWHM
of the envelope function, given by "
params[1]"
, to the point spread function of
the input data. However, there does not seem to be any theoretical reason for
this.
AST__SOMB: This scheme uses a somb(pi$\ast $x)
kernel (a "
sombrero"
function), where x is the pixel offset from the interpolation point and
somb(z)=2$\ast $J1(z)/z
(J1 is a Bessel function of the first kind of order 1). It is similar to the AST__SINC
kernel, and has the same parameter usage.
AST__SOMBCOS: This scheme uses a kernel of the form somb(pi$\ast $x).cos(k$\ast $pi$\ast $x), with k a constant, out to the point where cos(k$\ast $pi$\ast $x) goes to zero, and zero beyond. It is similar to the AST__SINCCOS kernel, and has the same parameter usage.
In addition, the following schemes are provided which are not based on a 1-dimensional kernel:
AST__BLOCKAVE: This scheme simply takes an average of all the pixels on the input grid
in a cube centred on the interpolation point. The number of pixels in the cube is
determined by the value of the first element of the "
params"
array, which gives the
number of pixels in each dimension on either side of the central point. Hence a block
of (2 $\ast $
params[0])$$
ndim_in
pixels in the input grid will be examined to determine the value of the output pixel.
If the variance is not being used (var_in or var_out = NULL) then all valid pixels in
this cube will be averaged in to the result with equal weight. If variances are being
used, then each input pixel will be weighted proportionally to the reciprocal
of its variance; any pixel without a valid variance will be discarded. This
scheme is suitable where the output grid is much coarser than the input grid;
if the ratio of pixel sizes is R then a suitable value of params[0] may be
R/2.
Finally, supplying the following values for "
interp"
allows you to implement your own
sub-pixel interpolation scheme by means of your own function. You should supply a
pointer to this function via the "
finterp"
parameter:
AST__UKERN1: In this scheme, you supply a function to evaluate your own 1-dimensional
interpolation kernel, which is then used to perform sub-pixel interpolation (as
described above). The function you supply should have the same interface as the
fictitious astUkern1 function (q.v.). In addition, a value should be given via "
params[0]"
to specify the number of neighbouring pixels which are to contribute to each
interpolated value (in the same way as for the pre-defined interpolation schemes
described above). Other elements of the "
params"
array are available to pass values to
your interpolation function.
AST__UINTERP: This is a completely general scheme, in which your interpolation function has
access to all of the input data. This allows you to implement any interpolation algorithm
you choose, which could (for example) be non-linear, or adaptive. In this case, the
astResample$<$X$>$
functions play no role in the sub-pixel interpolation process and simply
handle the geometrical transformation of coordinates and other housekeeping.
The function you supply should have the same interface as the fictitious
astUinterp function (q.v.). In this case, the "
params"
parameter is not used by
astResample$<$X$>$,
but is available to pass values to your interpolation function.
"
ast.h"
header file and may be used to
provide additional control over the resampling process. Having selected a set
of flags, you should supply the bitwise OR of their values via the "
flags"
parameter:
AST__NOBAD: Indicates that any output array elements for which no resampled value could
be obtained should be left set to the value they had on entry to this function. If
this flag is not supplied, such output array elements are set to the value
supplied for parameter "
badval"
. Note, this flag cannot be used in conjunction
with the AST__CONSERVEFLUX flag (an error will be reported if both flags are
specified).
AST__URESAMP1, 2, 3 & 4: A set of four flags which are reserved for your own use. They may be used to pass private information to any sub-pixel interpolation function which you implement yourself. They are ignored by all the pre-defined interpolation schemes.
AST__USEBAD: Indicates that there may be bad pixels in the input array(s) which must be
recognised by comparing with the value given for "
badval"
and propagated to the output
array(s). If this flag is not set, all input values are treated literally and the "
badval"
value is only used for flagging output array values.
AST__CONSERVEFLUX: Indicates that the output pixel values should be scaled in such a way as to preserve (approximately) the total data value in a feature on the sky. Without this flag, each output pixel value represents an instantaneous sample of the input data values at the corresponding input position. This is appropriate if the input data represents the spatial density of some quantity (e.g. surface brightness in Janskys per square arc-second) because the output pixel values will have the same normalisation and units as the input pixel values. However, if the input data values represent flux (or some other physical quantity) per pixel, then the AST__CONSERVEFLUX flag could be used. This causes each output pixel value to be scaled by the ratio of the output pixel size to the input pixel size.
This flag can only be used if the Mapping is successfully approximated by one or more
linear transformations. Thus an error will be reported if it used when the "
tol"
parameter is set to zero (which stops the use of linear approximations), or if the
Mapping is too non-linear to be approximated by a piece-wise linear transformation. The
ratio of output to input pixel size is evaluated once for each panel of the piece-wise
linear approximation to the Mapping, and is assumed to be constant for all output
pixels in the panel. The scaling factors for adjacent panels will in general differ
slightly, and so the joints between panels may be visible when viewing the output
image at high contrast. If this is a problem, reduce the value of the "
tol"
parameter until the difference between adjacent panels is sufficiently small to be
insignificant.
Note, this flag cannot be used in conjunction with the AST__NOBAD flag (an error will be reported if both flags are specified).
"
badval"
value in the "
out"
array. These may be
produced if any of the following happen:
The input position (the transformed position of the output pixel’
s centre) lies
outside the boundary of the grid of input pixels.
The input position lies inside the boundary of a bad input pixel. In this context, an
input pixel is considered bad if its data value is equal to "
badval"
and the
AST__USEBAD flag is set via the "
flags"
parameter. (Positions which have half-integral
coordinate values, and therefore lie on a pixel boundary, are regarded as lying within
the pixel with the larger, i.e. more positive, index.)
The set of neighbouring input pixels (excluding those which are bad) is unsuitable for calculating an interpolated value. Whether this is true may depend on the sub-pixel interpolation scheme in use.
The interpolated value lies outside the range which can be represented using the data
type of the "
out"
array.
In addition, associated output variance estimates (if calculated) may be declared bad
and flagged with the "
badval"
value in the "
out_var"
array under any of the following
circumstances:
The associated resampled data value (in the "
out"
array) is bad.
The set of neighbouring input pixels which contributed to the output data value do not
all have valid variance estimates associated with them. In this context, an input
variance estimate may be regarded as bad either because it has the value "
badval"
(and
the AST__USEBAD flag is set), or because it is negative.
The set of neighbouring input pixels for which valid variance values are available is unsuitable for calculating an overall variance value. Whether this is true may depend on the sub-pixel interpolation scheme in use.
The variance value lies outside the range which can be represented using the data type
of the "
out_var"
array.
If the AST__NOBAD flag is specified via parameter "
flags"
, then output array
elements that would otherwise be set to "
badval"
are instead left holding the
value they had on entry to this function. The number of such array elements
is returned as the function value.
"
8-byte"
interface for this function should be
used. This alternative interface uses 8 byte integer arguments (instead of
4-byte) to hold pixel indices and pixel counts. Specifically, the arguments "
lbnd_in"
, "
ubnd_in"
, "
lbnd_out"
, "
ubnd_out"
, "
lbnd"
, "
ubnd"
are changed
from type "
int"
to type "
int64_t"
(defined in header file stdint.h). The
function return type is similarly changed to type int64_t. The function name is
changed by inserting the digit "
8"
before the trailing data type code. Thus,
astResample$<$X$>$
becomes astResample8$<$X$>$.