25 if (
name ==
"HCOMPRESS")
38 return "GZIP_SHUFFLE";
45 os <<
"Unrecognized compression algorithm: " << algorithm;
64 "Unsupported compression algorithm: HCOMPRESS_1");
67 os <<
"Unrecognized cfitsio compression: " << cfitsio;
86 os <<
"Unrecognized compression algorithm: " << algorithm;
92 int rows,
float quantizeLevel_)
93 : algorithm(algorithm_), tiles(
ndarray::allocate(MAX_COMPRESS_DIM)), quantizeLevel(quantizeLevel_) {
96 for (
int ii = 2; ii < MAX_COMPRESS_DIM; ++ii)
tiles[ii] = 1;
116 return "STDEV_POSITIVE";
118 return "STDEV_NEGATIVE";
125 os <<
"Unrecognized scaling algorithm: " << algorithm;
132 float quantizeLevel_,
float quantizePad_,
bool fuzz_,
double bscale_,
134 : algorithm(algorithm_),
137 seed(
std::
abs(seed_ - 1) % (N_RANDOM - 1) +
139 maskPlanes(maskPlanes_),
140 quantizeLevel(quantizeLevel_),
141 quantizePad(quantizePad_),
148 template <
typename T,
int N>
150 ndarray::Array<bool, N, N>
const&
mask) {
152 auto const& flatMask = ndarray::flatten<1>(
mask);
153 for (
auto mm = flatMask.begin(); mm != flatMask.end(); ++mm) {
156 ndarray::Array<T, 1, 1> array = ndarray::allocate(num);
157 auto const& flatImage = ndarray::flatten<1>(
image);
158 auto mm = ndarray::flatten<1>(
mask).begin();
159 auto aa = array.begin();
160 for (
auto ii = flatImage.begin(); ii != flatImage.end(); ++ii, ++mm) {
167 auto const q1 = num / 4;
168 auto const q2 = num / 2;
169 auto const q3 = q1 + q2;
174 T
const median = num % 2 ? array[num / 2] : 0.5 * (array[num / 2] + array[num / 2 - 1]);
177 T
const lq = array[q1];
178 T
const uq = array[q3];
183 template <
typename T,
int N>
185 ndarray::Array<bool, N, N>
const&
mask) {
187 auto mm = ndarray::flatten<1>(
mask).begin();
188 auto const& flatImage = ndarray::flatten<1>(
image);
189 for (
auto ii = flatImage.begin(); ii != flatImage.end(); ++ii, ++mm) {
199 template <
typename T>
200 double rangeForBitpix(
int bitpix,
bool cfitsioPadding) {
202 bitpix = detail::Bitpix<T>::value;
204 double range =
std::pow(2.0, bitpix) - 1;
205 if (cfitsioPadding) {
213 template <
typename T,
int N>
214 ImageScale ImageScalingOptions::determineFromRange(ndarray::Array<T const, N, N>
const&
image,
215 ndarray::Array<bool, N, N>
const&
mask,
bool isUnsigned,
216 bool cfitsioPadding)
const {
217 auto minMax = calculateMinMax(
image,
mask);
218 T
const min = minMax.first;
219 T
const max = minMax.second;
221 double range = rangeForBitpix<T>(
bitpix, cfitsioPadding);
223 double const bscale =
static_cast<T
>((
max -
min) / range);
225 if (cfitsioPadding) {
232 template <
typename T,
int N>
233 ImageScale ImageScalingOptions::determineFromStdev(ndarray::Array<T const, N, N>
const&
image,
234 ndarray::Array<bool, N, N>
const&
mask,
bool isUnsigned,
235 bool cfitsioPadding)
const {
236 auto stats = calculateMedianStdev(
image,
mask);
237 auto const median = stats.first,
stdev = stats.second;
241 auto minMax = calculateMinMax(
image,
mask);
242 T
const min = minMax.first;
243 T
const max = minMax.second;
244 double range = rangeForBitpix<T>(
bitpix, cfitsioPadding);
249 if (numUnique < range) {
263 diskVal = (
bitpix == 8) ? 255 : (1L << (
bitpix - 1)) - 1;
276 double bzero =
static_cast<T
>(imageVal -
bscale * diskVal);
281 template <
typename T,
class Enable =
void>
283 static double constexpr
value = 0.0;
291 static double constexpr
value = 0.0;
295 template <
typename T>
296 struct Bzero<T, typename
std::enable_if<std::numeric_limits<T>::is_integer &&
297 !std::numeric_limits<T>::is_signed>
::type> {
302 template <
typename T,
int N>
304 ndarray::Array<bool, N, N>
const&
mask)
const {
308 "Image scaling not supported for integral types");
310 bool const isUnsigned =
bitpix == 8 || (
bitpix == 0 && detail::Bitpix<T>::value == 8);
316 return determineFromRange(
image,
mask, isUnsigned, cfitsioPadding);
322 return determineFromStdev(
image,
mask, isUnsigned, cfitsioPadding);
335 class CfitsioRandom {
338 CfitsioRandom(
int seed) : _seed(seed) {
339 assert(seed != 0 && seed < N_RANDOM);
345 void resetForTile(
int iTile) {
346 _start = (iTile + _seed - 1) % N_RANDOM;
360 if (_index == N_RANDOM) {
362 if (_start == N_RANDOM) {
370 template <
typename T>
371 ndarray::Array<T, 1, 1> forImage(
typename ndarray::Array<T const, 2, 2>::Index
const& shape,
372 ndarray::Array<long, 1>
const& tiles) {
373 std::size_t const xSize = shape[1], ySize = shape[0];
374 ndarray::Array<T, 1, 1> out = ndarray::allocate(xSize * ySize);
375 std::size_t const xTileSize = tiles[0] <= 0 ? xSize : tiles[0];
376 std::size_t const yTileSize = tiles[1] < 0 ? ySize : (tiles[1] == 0 ? 1 : tiles[1]);
377 int const xNumTiles =
std::ceil(xSize /
static_cast<float>(xTileSize));
378 int const yNumTiles =
std::ceil(ySize /
static_cast<float>(yTileSize));
379 for (
int iTile = 0, yTile = 0; yTile < yNumTiles; ++yTile) {
380 int const yStart = yTile * yTileSize;
381 int const yStop =
std::min(yStart + yTileSize, ySize);
382 for (
int xTile = 0; xTile < xNumTiles; ++xTile, ++iTile) {
383 int const xStart = xTile * xTileSize;
384 int const xStop =
std::min(xStart + xTileSize, xSize);
386 for (
int y = yStart;
y < yStop; ++
y) {
387 auto iter = out.begin() +
y * xSize + xStart;
388 for (
int x = xStart;
x < xStop; ++
x, ++
iter) {
389 *
iter =
static_cast<T
>(getNext());
399 void reseed() { _index =
static_cast<int>(
fits_rand_value[_start] * 500); }
408 template <
typename T>
410 bool forceNonfiniteRemoval,
bool fuzz,
411 ndarray::Array<long, 1>
const& tiles,
416 "Floating-point images may not be converted to different floating-point types");
420 "Scaling may not be applied to floating-point images");
426 if (!forceNonfiniteRemoval) {
431 ndarray::Array<T, 1, 1> out = ndarray::allocate(
image.getNumElements());
432 auto outIter = out.begin();
433 auto const& flatImage = ndarray::flatten<1>(
image);
434 for (
auto inIter = flatImage.begin(); inIter != flatImage.end(); ++inIter, ++outIter) {
454 ndarray::Array<double, 1, 1> out;
456 if (tiles.isEmpty()) {
458 "Tile sizes must be provided if fuzzing is desired");
460 out = CfitsioRandom(seed).forImage<
double>(
image.getShape(), tiles);
462 out = ndarray::allocate(num);
465 auto outIter = out.begin();
466 auto const& flatImage = ndarray::flatten<1>(
image);
467 for (
auto inIter = flatImage.begin(); inIter != flatImage.end(); ++inIter, ++outIter) {
485 template <
typename T>
487 ndarray::Array<T, 2, 2> memory = ndarray::allocate(
image.getShape());
493 #define INSTANTIATE(TYPE) \
494 template ImageScale ImageScalingOptions::determine<TYPE, 2>( \
495 ndarray::Array<TYPE const, 2, 2> const& image, ndarray::Array<bool, 2, 2> const& mask) const; \
496 template std::shared_ptr<detail::PixelArrayBase> ImageScale::toFits<TYPE>( \
497 ndarray::Array<TYPE const, 2, 2> const&, bool, bool, ndarray::Array<long, 1> const&, int) const; \
498 template ndarray::Array<TYPE, 2, 2> ImageScale::fromFits<TYPE>(ndarray::Array<TYPE, 2, 2> const&) const;
table::Key< std::string > name
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
ScalingAlgorithm algorithm
Scaling algorithm to use.
float quantizeLevel
Divisor of the standard deviation for STDEV_* scaling.
@ MANUAL
Scale set manually.
@ STDEV_NEGATIVE
Scale based on the standard deviation, dynamic range negative.
@ STDEV_POSITIVE
Scale based on the standard deviation. dynamic range positive.
@ STDEV_BOTH
Scale based on the standard deviation, dynamic range positive+negative.
@ RANGE
Scale to preserve dynamic range.
float quantizePad
Number of stdev to allow on the low/high side (for STDEV_POSITIVE/NEGATIVE)
ImageScalingOptions()
Default Ctor.
int bitpix
Bits per pixel (0, 8,16,32,64,-32,-64)
double bscale
Manually specified BSCALE (for MANUAL scaling)
ImageScale determine(image::ImageBase< T > const &image, std::shared_ptr< image::Mask< image::MaskPixel > const > mask=nullptr) const
Determine the scaling for a particular image.
double bzero
Manually specified BZERO (for MANUAL scaling)
Reports invalid arguments.
int const N_RESERVED_VALUES
#define INSTANTIATE(TYPE)
def scale(algorithm, min, max=None, frame=None)
std::shared_ptr< PixelArrayBase > makePixelArray(int bitpix, ndarray::Array< T, 1, 1 > const &array)
Create a PixelArray suitable for an image with the nominated BITPIX.
std::string compressionAlgorithmToString(ImageCompressionOptions::CompressionAlgorithm algorithm)
Provide string version of compression algorithm.
ImageScalingOptions::ScalingAlgorithm scalingAlgorithmFromString(std::string const &name)
Interpret scaling algorithm expressed in string.
int compressionAlgorithmToCfitsio(ImageCompressionOptions::CompressionAlgorithm algorithm)
Convert ImageCompressionOptions::CompressionAlgorithm to cfitsio.
std::string scalingAlgorithmToString(ImageScalingOptions::ScalingAlgorithm algorithm)
Provide string version of compression algorithm.
ImageCompressionOptions::CompressionAlgorithm compressionAlgorithmFromCfitsio(int cfitsio)
Convert compression algorithm from cfitsio to ImageCompressionOptions::CompressionAlgorithm.
ImageCompressionOptions::CompressionAlgorithm compressionAlgorithmFromString(std::string const &name)
Interpret compression algorithm expressed in string.
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Angle abs(Angle const &a)
A base class for image defects.
Scaling zero-point, set according to pixel type.
static constexpr double value
ImageCompressionOptions(CompressionAlgorithm algorithm_, Tiles tiles_, float quantizeLevel_=0.0)
Custom compression.
Tiles tiles
Tile size; a dimension with 0 means infinite (e.g., to specify one row: 0,1)
CompressionAlgorithm
Compression algorithms.
@ GZIP_SHUFFLE
GZIP compression with shuffle (most-significant byte first)
@ GZIP
Standard GZIP compression.
double bscale
Scale to apply when reading from FITS.
long blank
Value for integer images indicating non-finite values.
int bitpix
Bits per pixel; negative means floating-point: 8,16,32,64,-32,-64.
double bzero
Zero-point to apply when reading from FITS.
ndarray::Array< T, 2, 2 > fromFits(ndarray::Array< T, 2, 2 > const &image) const
Convert to an array.
std::shared_ptr< detail::PixelArrayBase > toFits(ndarray::Array< T const, 2, 2 > const &image, bool forceNonfiniteRemoval, bool fuzz=true, ndarray::Array< long, 1 > const &tiles=ndarray::Array< long, 1, 1 >(), int seed=1) const
Convert to an array of pixel values to write to FITS.
FITS BITPIX header value by C++ type.