24 if (
name ==
"HCOMPRESS")
37 return "GZIP_SHUFFLE";
44 os <<
"Unrecognized compression algorithm: " << algorithm;
63 "Unsupported compression algorithm: HCOMPRESS_1");
66 os <<
"Unrecognized cfitsio compression: " << cfitsio;
85 os <<
"Unrecognized compression algorithm: " << algorithm;
91 int rows,
float quantizeLevel_)
92 : algorithm(algorithm_), tiles(
ndarray::allocate(MAX_COMPRESS_DIM)), quantizeLevel(quantizeLevel_) {
95 for (
int ii = 2; ii < MAX_COMPRESS_DIM; ++ii)
tiles[ii] = 1;
115 return "STDEV_POSITIVE";
117 return "STDEV_NEGATIVE";
124 os <<
"Unrecognized scaling algorithm: " << algorithm;
131 float quantizeLevel_,
float quantizePad_,
bool fuzz_,
double bscale_,
133 : algorithm(algorithm_),
136 seed(
std::abs(seed_ - 1) % (N_RANDOM - 1) +
138 maskPlanes(maskPlanes_),
139 quantizeLevel(quantizeLevel_),
140 quantizePad(quantizePad_),
147template <
typename T,
int N>
149 ndarray::Array<bool, N, N>
const& mask) {
151 auto const& flatMask = ndarray::flatten<1>(mask);
152 for (
auto mm = flatMask.begin(); mm != flatMask.end(); ++mm) {
155 ndarray::Array<T, 1, 1> array = ndarray::allocate(num);
156 auto const& flatImage = ndarray::flatten<1>(
image);
157 auto mm = ndarray::flatten<1>(mask).begin();
158 auto aa = array.begin();
159 for (
auto ii = flatImage.begin(); ii != flatImage.end(); ++ii, ++mm) {
166 auto const q1 = num / 4;
167 auto const q2 = num / 2;
168 auto const q3 = q1 + q2;
173 T
const median = num % 2 ? array[num / 2] : 0.5 * (array[num / 2] + array[num / 2 - 1]);
176 T
const lq = array[q1];
177 T
const uq = array[q3];
182template <
typename T,
int N>
184 ndarray::Array<bool, N, N>
const& mask) {
186 auto mm = ndarray::flatten<1>(mask).begin();
187 auto const& flatImage = ndarray::flatten<1>(
image);
188 for (
auto ii = flatImage.begin(); ii != flatImage.end(); ++ii, ++mm) {
199double rangeForBitpix(
int bitpix,
bool cfitsioPadding) {
201 bitpix = detail::Bitpix<T>::value;
203 double range =
std::pow(2.0, bitpix) - 1;
204 if (cfitsioPadding) {
212template <
typename T,
int N>
213ImageScale ImageScalingOptions::determineFromRange(ndarray::Array<T const, N, N>
const&
image,
214 ndarray::Array<bool, N, N>
const& mask,
bool isUnsigned,
215 bool cfitsioPadding)
const {
216 auto minMax = calculateMinMax(
image, mask);
217 T const min = minMax.first;
218 T const max = minMax.second;
220 double range = rangeForBitpix<T>(
bitpix, cfitsioPadding);
224 if (cfitsioPadding) {
231template <
typename T,
int N>
232ImageScale ImageScalingOptions::determineFromStdev(ndarray::Array<T const, N, N>
const&
image,
233 ndarray::Array<bool, N, N>
const& mask,
bool isUnsigned,
234 bool cfitsioPadding)
const {
235 auto stats = calculateMedianStdev(
image, mask);
236 auto const median = stats.first,
stdev = stats.second;
240 auto minMax = calculateMinMax(
image, mask);
241 T const min = minMax.first;
242 T const max = minMax.second;
243 double range = rangeForBitpix<T>(
bitpix, cfitsioPadding);
248 if (numUnique < range) {
262 diskVal = (
bitpix == 8) ? 255 : (1L << (
bitpix - 1)) - 1;
275 double bzero =
static_cast<T>(imageVal -
bscale * diskVal);
280template <
typename T,
class Enable =
void>
282 static double constexpr value = 0.0;
290 static double constexpr value = 0.0;
295struct Bzero<T, typename
std::enable_if<std::numeric_limits<T>::is_integer &&
296 !std::numeric_limits<T>::is_signed>
::type> {
301template <
typename T,
int N>
303 ndarray::Array<bool, N, N>
const& mask)
const {
307 "Image scaling not supported for integral types");
309 bool const isUnsigned =
bitpix == 8 || (
bitpix == 0 && detail::Bitpix<T>::value == 8);
315 return determineFromRange(
image, mask, isUnsigned, cfitsioPadding);
321 return determineFromStdev(
image, mask, isUnsigned, cfitsioPadding);
337 CfitsioRandom(
int seed) : _seed(seed) {
338 assert(seed != 0 && seed < N_RANDOM);
344 void resetForTile(
int iTile) {
345 _start = (iTile + _seed - 1) % N_RANDOM;
359 if (_index == N_RANDOM) {
361 if (_start == N_RANDOM) {
369 template <
typename T>
370 ndarray::Array<T, 1, 1> forImage(
typename ndarray::Array<T const, 2, 2>::Index
const& shape,
371 ndarray::Array<long, 1>
const& tiles) {
372 std::size_t const xSize = shape[1], ySize = shape[0];
373 ndarray::Array<T, 1, 1> out = ndarray::allocate(xSize * ySize);
374 std::size_t const xTileSize = tiles[0] <= 0 ? xSize : tiles[0];
375 std::size_t const yTileSize = tiles[1] < 0 ? ySize : (tiles[1] == 0 ? 1 : tiles[1]);
376 int const xNumTiles =
std::ceil(xSize /
static_cast<float>(xTileSize));
377 int const yNumTiles =
std::ceil(ySize /
static_cast<float>(yTileSize));
378 for (
int iTile = 0, yTile = 0; yTile < yNumTiles; ++yTile) {
379 int const yStart = yTile * yTileSize;
380 int const yStop =
std::min(yStart + yTileSize, ySize);
381 for (
int xTile = 0; xTile < xNumTiles; ++xTile, ++iTile) {
382 int const xStart = xTile * xTileSize;
383 int const xStop =
std::min(xStart + xTileSize, xSize);
385 for (
int y = yStart;
y < yStop; ++
y) {
386 auto iter = out.begin() +
y * xSize + xStart;
387 for (
int x = xStart;
x < xStop; ++
x, ++
iter) {
388 *
iter =
static_cast<T>(getNext());
398 void reseed() { _index =
static_cast<int>(
fits_rand_value[_start] * 500); }
409 bool forceNonfiniteRemoval,
bool fuzz,
410 ndarray::Array<long, 1>
const& tiles,
415 "Floating-point images may not be converted to different floating-point types");
419 "Scaling may not be applied to floating-point images");
425 if (!forceNonfiniteRemoval) {
430 ndarray::Array<T, 1, 1> out = ndarray::allocate(
image.getNumElements());
431 auto outIter = out.begin();
432 auto const& flatImage = ndarray::flatten<1>(
image);
433 for (
auto inIter = flatImage.begin(); inIter != flatImage.end(); ++inIter, ++outIter) {
450 double const scale = 1.0 /
bscale;
453 ndarray::Array<double, 1, 1> out;
455 if (tiles.isEmpty()) {
457 "Tile sizes must be provided if fuzzing is desired");
459 out = CfitsioRandom(seed).forImage<
double>(
image.getShape(), tiles);
461 out = ndarray::allocate(num);
464 auto outIter = out.begin();
465 auto const& flatImage = ndarray::flatten<1>(
image);
466 for (
auto inIter = flatImage.begin(); inIter != flatImage.end(); ++inIter, ++outIter) {
467 double value = (*inIter -
bzero) * scale;
486 ndarray::Array<T, 2, 2> memory = ndarray::allocate(
image.getShape());
492#define INSTANTIATE(TYPE) \
493 template ImageScale ImageScalingOptions::determine<TYPE, 2>( \
494 ndarray::Array<TYPE const, 2, 2> const& image, ndarray::Array<bool, 2, 2> const& mask) const; \
495 template std::shared_ptr<detail::PixelArrayBase> ImageScale::toFits<TYPE>( \
496 ndarray::Array<TYPE const, 2, 2> const&, bool, bool, ndarray::Array<long, 1> const&, int) const; \
497 template ndarray::Array<TYPE, 2, 2> ImageScale::fromFits<TYPE>(ndarray::Array<TYPE, 2, 2> const&) const;
table::Key< std::string > name
#define INSTANTIATE(FROMSYS, TOSYS)
#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.
ImageScale determine(image::ImageBase< T > const &image, image::Mask< image::MaskPixel > const *mask=nullptr) const
Determine the scaling for a particular image.
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)
double bzero
Manually specified BZERO (for MANUAL scaling)
Reports invalid arguments.
int const N_RESERVED_VALUES
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.
Scaling zero-point, set according to pixel type.
static double constexpr 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.