
nom.tam.fits.compression.algorithm.quant.QuantizeOption Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nom-tam-fits Show documentation
Show all versions of nom-tam-fits Show documentation
Java library for reading and writing FITS files. FITS, the Flexible Image Transport System, is the format commonly used in the archiving and transport of astronomical data.
package nom.tam.fits.compression.algorithm.quant;
import nom.tam.fits.compression.algorithm.api.ICompressOption;
import nom.tam.fits.compression.provider.param.api.ICompressParameters;
import nom.tam.fits.compression.provider.param.base.BundledParameters;
import nom.tam.fits.compression.provider.param.quant.QuantizeParameters;
/*
* #%L
* nom.tam FITS library
* %%
* Copyright (C) 1996 - 2024 nom-tam-fits
* %%
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
* #L%
*/
/**
* Quantization options when they are part of the compression scheme. When compressing tables and images includes
* quantization (integer representation of floating point data), users can control how exactly the quantization should
* be performed. When reading compressed FITS files, these options will be set automatically based on the header values
* recorded in the compressed HDU.
*
* @see nom.tam.image.compression.hdu.CompressedImageHDU#setQuantAlgorithm(String)
* @see nom.tam.image.compression.hdu.CompressedImageHDU#getCompressOption(Class)
*/
public class QuantizeOption implements ICompressOption {
/**
* and including NULL_VALUE. These values may not be used to represent the quantized and scaled floating point pixel
* values If lossy Hcompression is used, and the tiledImageOperation contains null values, then it is also possible
* for the compressed values to slightly exceed the range of the actual (lossless) values so we must reserve a
* little more space value used to represent undefined pixels
*/
private static final int NULL_VALUE = Integer.MIN_VALUE + 1;
/** Shared configuration across copies */
private Config config;
/** The parameters that represent settings for this option in the FITS headers and/or compressed data columns */
protected QuantizeParameters parameters;
private ICompressOption compressOption;
private double bScale = Double.NaN;
private double bZero = Double.NaN;
private double nullValue = Double.NaN;
private Integer nullValueIndicator;
private boolean checkNull;
private int intMaxValue;
private int intMinValue;
private double maxValue;
private double minValue;
private int tileIndex = 0;
private int tileHeight;
private int tileWidth;
QuantizeOption() {
this(null);
}
/**
* Creates a new set of quantization options, to be used together with the specified compression options.
*
* @param compressOption Compression-specific options to pair with these quantization options, or null
.
*
* @since 1.18
*/
public QuantizeOption(ICompressOption compressOption) {
parameters = new QuantizeParameters(this);
config = new Config();
this.compressOption = compressOption;
}
@Override
public QuantizeOption copy() {
try {
QuantizeOption copy = (QuantizeOption) clone();
if (compressOption != null) {
copy.compressOption = compressOption.copy();
}
copy.parameters = parameters.copy(copy);
return copy;
} catch (CloneNotSupportedException e) {
throw new IllegalStateException("option could not be cloned", e);
}
}
/**
* Returns the integer value that represents missing (null
) data in the quantized representation.
*
* @return the integer blanking value (null
value).
*
* @see #setBNull(Integer)
*/
public Integer getBNull() {
return nullValueIndicator;
}
/**
* Returns the quantization level.
*
* @return the floating-point difference between integer levels in the quantized data.
*
* @see #setBScale(double)
* @see #getBZero()
*/
public double getBScale() {
return bScale;
}
/**
* Returns the quantization offset.
*
* @return the floating-point value corresponding to the integer level 0.
*
* @see #setBZero(double)
* @see #getBScale()
*/
public double getBZero() {
return bZero;
}
@Override
public ICompressParameters getCompressionParameters() {
if (compressOption == null) {
return parameters;
}
return new BundledParameters(parameters, compressOption.getCompressionParameters());
}
/**
* Returns the compression or quantization options, recast for the selected option class.
*
* @param the generic type of the compression option
* @param clazz the option class for the compression algorithm used with the quantization, or
* QunatizeOption.class
for our own options.
*
* @return the recast options for the requested class or null
id we do not have access to options
* of the requested class.
*
* @see #getCompressOption()
*/
public T getCompressOption(Class clazz) {
return unwrap(clazz);
}
/**
* Returns the options for the compression algorithm that accompanies quantization.
*
* @return the options for the compression algorithm, or null
*
* @see #getCompressOption(Class)
*/
public final ICompressOption getCompressOption() {
return compressOption;
}
/**
* Returns the maximum integer level in the quantized representation.
*
* @return the maximum integer level in the quantized data.
*
* @see #getMaxValue()
* @see #getIntMinValue()
*/
public int getIntMaxValue() {
return intMaxValue;
}
/**
* Returns the maximum integer level in the quantized representation.
*
* @return the maximum integer level in the quantized data.
*
* @see #getMinValue()
* @see #getIntMinValue()
*/
public int getIntMinValue() {
return intMinValue;
}
/**
* Returns the maximum floating-point value in the data
*
* @return the maximum floating-point value in the data before quantization.
*
* @see #getIntMaxValue()
* @see #getMinValue()
*/
public double getMaxValue() {
return maxValue;
}
/**
* Returns the minimum floating-point value in the data
*
* @return the minimum floating-point value in the data before quantization.
*
* @see #getIntMinValue()
* @see #getMaxValue()
*/
public double getMinValue() {
return minValue;
}
/**
* Returns the floating-point value that indicates a null
datum in the image before quantization is
* applied. Normally, the FITS standard is that NaN values indicate null
values in floating-point
* images. While this class allows using other values also, they are not recommended since they are not supported by
* FITS in a standard way.
*
* @return the floating-point value that represents a null
value (missing data) in the image before
* quantization.
*
* @see #setNullValue(double)
* @see #getNullValueIndicator()
* @see #isCheckNull()
*/
public double getNullValue() {
return nullValue;
}
/**
* @deprecated use {@link #getBNull()} instead (duplicate method). Returns the integer value that represents missing
* data (null
) in the quantized representation.
*
* @return the integer blanking value (null
value).
*
* @see #setBNull(Integer)
*/
public final Integer getNullValueIndicator() {
return getBNull();
}
/**
* Returns the quantization resolution level used for automatic qunatization. For Gaussian noise the quantization
* level is the standard deviation of the noise divided by this Q value. Thus Q values of a few will ensure that
* quantization retains just about all of the information in the noisy data.
*
* @return The current Q value, defined as the number of quantized levels per standard deviation (for Gaussian
* noise).
*
* @see #setQlevel(double)
* @see #getBScale()
*/
public double getQLevel() {
return config.qlevel;
}
/**
* Gets the random seed value used for dithering
*
* @return the random seed value used for dithering
*
* @see #setSeed(long)
* @see RandomSequence
*/
public long getSeed() {
return config.seed;
}
/**
* Returns the sequential tile index that this option is currently configured for.
*
* @return the sequential tile index that the quantization is configured for
*
* @see #setTileIndex(int)
*/
public long getTileIndex() {
return tileIndex;
}
/**
* Returns the tile height
*
* @return the tile height in pixels
*
* @see #setTileHeight(int)
* @see #getTileWidth()
*/
@Override
public int getTileHeight() {
return tileHeight;
}
/**
* Returns the tile width
*
* @return the tile width in pixels
*
* @see #setTileWidth(int)
* @see #getTileHeight()
*/
@Override
public int getTileWidth() {
return tileWidth;
}
/**
* Checks whether we force the integer quantized level 0 to correspond to a floating-point level 0.0, when using
* automatic quantization.
*
* @return true
if we want to keep `BZERO` at 0 when quantizing automatically.
*
* @see #setCenterOnZero(boolean)
*/
public boolean isCenterOnZero() {
return config.centerOnZero;
}
/**
* Whether the floating-point data may contain null
values (normally NaNs).
*
* @return true
if we should expect null
in the floating-point data. This is automatically
* true
if {@link #setBNull(Integer)} was called with a non-null value.
*
* @see #setBNull(Integer)
*/
public boolean isCheckNull() {
return checkNull;
}
/**
* Whether automatic quantization treats 0.0 as a special value. Normally values within the `BSCALE` quantization
* level around 0.0 will be assigned the same integer quanta, and will become indistinguishable in the quantized
* data. Some software may, in their misguided ways, assign exact zero values a special meaning (such as no data) in
* which case we may want to distinguish these as we apply quantization. However, it is generally not a good idea to
* use 0 as a special value.
*
* @return true
to treat 0.0 (exact) as a special value, or false
to treat is as any other
* measured value (recommended).
*
* @see #setCheckZero(boolean)
* @see #getBScale()
*/
public boolean isCheckZero() {
return config.checkZero;
}
/**
* Whether dithering is enabled
*
* @return true
if dithering is enabled, or else false
*
* @see #setDither(boolean)
* @see #isDither2()
*/
public boolean isDither() {
return config.dither;
}
/**
* Whether dither method 2 is used.
*
* @return true
if dither method 2 is used, or else false
*
* @see #setDither2(boolean)
* @see #isDither()
*/
public boolean isDither2() {
return config.dither2;
}
@Override
public boolean isLossyCompression() {
return true;
}
/**
* Sets the integer value that represents missing data (null
) in the quantized representation.
*
* @param blank the new integer blanking value (that is one that denotes a missing or null
datum).
* Setting this option to null
disables the treatment of issing or null
* data.
*
* @return itself
*
* @see #getBNull()
* @see #isCheckNull()
*/
public ICompressOption setBNull(Integer blank) {
if (blank != null) {
nullValueIndicator = blank;
checkNull = true;
} else {
checkNull = false;
}
return this;
}
/**
* Sets the quantization level.
*
* @param value the new floating-point difference between integer levels in the quantized data.
*
* @return itself
*
* @see #setQlevel(double)
* @see #setBZero(double)
* @see #getBScale()
*/
public QuantizeOption setBScale(double value) {
bScale = value;
return this;
}
/**
* Sets the quantization offset.
*
* @param value the new floating-point value corresponding to the integer level 0.
*
* @return itself
*
* @see #setBScale(double)
* @see #getBZero()
*/
public QuantizeOption setBZero(double value) {
bZero = value;
return this;
}
/**
* Enabled or disables keeping `BZERO` at 0 when using automatic quantization.
*
* @param value true
to keep `BZERO` at 0 when quantizing automatically, that is keep the integer
* quantized level 0 correspond to floating-point level 0.0. Or, false
to let the
* automatic quantization algorithm determine the optimal quantization offset.
*
* @return iftself
*
* @see #isCenterOnZero()
*/
public QuantizeOption setCenterOnZero(boolean value) {
config.centerOnZero = value;
return this;
}
/**
* @deprecated {@link #setBNull(Integer)} controls this feature automatically as needed. Sets whether we
* should expect the floating-point data to contain null
values (normally NaNs).
*
* @param value true
if the floating-point data may contain null
values.
*
* @return itself
*
* @see #setCheckNull(boolean)
* @see #setBNull(Integer)
* @see #getNullValue()
*/
public QuantizeOption setCheckNull(boolean value) {
checkNull = value;
if (nullValueIndicator == null) {
nullValueIndicator = NULL_VALUE;
}
return this;
}
/**
* Sets whether automatic quantization is to treat 0.0 as a special value. Normally values within the `BSCALE`
* quantization level around 0.0 will be assigned the same integer quanta, and will become indistinguishable in the
* quantized data. However some software may assign exact zero values a special meaning (such as no data) in which
* case we may want to distinguish these as we apply qunatization. However, it is generally not a good idea to use 0
* as a special value. To mark missing data, the FITS standard recognises only NaN as a special value -- while all
* other values should constitute valid measurements.
*
* @deprecated It is strongly discouraged to treat 0.0 values as special. FITS only recognises NaN as a
* special floating-point value marking missing data. All other floating point values are
* considered valid measurements.
*
* @param value whether to treat values around 0.0 as special.
*
* @return itself
*
* @see #isCheckZero()
*/
public QuantizeOption setCheckZero(boolean value) {
config.checkZero = value;
return this;
}
/**
* Enables or disables dithering.
*
* @param value true
to enable dithering, or else false
to disable
*
* @return itself
*
* @see #isDither()
* @see #setDither2(boolean)
*/
public QuantizeOption setDither(boolean value) {
config.dither = value;
return this;
}
/**
* Sets whether dithering is to use method 2.
*
* @param value true
to use dither method 2, or else false
for method 1.
*
* @return itself
*
* @see #isDither2()
* @see #setDither(boolean)
*/
public QuantizeOption setDither2(boolean value) {
config.dither2 = value;
return this;
}
/**
* Sets the maximum integer level in the quantized representation.
*
* @param value the new maximum integer level in the quantized data.
*
* @return itself
*
* @see #getIntMaxValue()
* @see #setIntMinValue(int)
*/
public QuantizeOption setIntMaxValue(int value) {
intMaxValue = value;
return this;
}
/**
* Sets the minimum integer level in the quantized representation.
*
* @param value the new minimum integer level in the quantized data.
*
* @return itself
*
* @see #getIntMinValue()
* @see #setIntMaxValue(int)
*/
public QuantizeOption setIntMinValue(int value) {
intMinValue = value;
return this;
}
/**
* Sets the maximum floating-point value in the data
*
* @param value the maximum floating-point value in the data before quantization.
*
* @return itself
*
* @see #getMaxValue()
* @see #setMinValue(double)
*/
public QuantizeOption setMaxValue(double value) {
maxValue = value;
return this;
}
/**
* Sets the minimum floating-point value in the data
*
* @param value the mininum floating-point value in the data before quantization.
*
* @return itself
*
* @see #getMinValue()
* @see #setMaxValue(double)
*/
public QuantizeOption setMinValue(double value) {
minValue = value;
return this;
}
/**
* @deprecated The use of null values other than NaN
for floating-point data types is not
* standard in FITS. You should therefore avoid using this method to change it. Returns the
* floating-point value that indicates a null
datum in the image before
* quantization is applied. Normally, the FITS standard is that NaN values indicate
* null
values in floating-point images. While this class allows using other
* values also, they are not recommended since they are not supported by FITS in a standard
* way.
*
* @param value the new floating-point value that represents a null
value (missing data) in the
* image before quantization.
*
* @return itself
*
* @see #setNullValue(double)
*/
public QuantizeOption setNullValue(double value) {
nullValue = value;
return this;
}
@Override
public void setParameters(ICompressParameters parameters) {
if (parameters instanceof QuantizeParameters) {
this.parameters = (QuantizeParameters) parameters.copy(this);
} else if (parameters instanceof BundledParameters) {
BundledParameters bundle = (BundledParameters) parameters;
for (int i = 0; i < bundle.size(); i++) {
setParameters(bundle.get(i));
}
} else if (compressOption != null) {
compressOption.setParameters(parameters);
}
}
/**
* Sets the quantization resolution level to use for automatic quantization. For Gaussian noise the quantization
* level is the standard deviation of the noise divided by this Q value. Thus Q values of a few will ensusre that
* quantization retains just about all of the information contained in the noisy data.
*
* @param value The new Q value, defined as the number of quantized levels per standard deviation (for Gaussian
* noise).
*
* @return itself
*
* @see #getQLevel()
* @see #setBScale(double)
*/
public QuantizeOption setQlevel(double value) {
config.qlevel = value;
return this;
}
/**
* Sets the seed value for the dither random generator
*
* @param value The seed value, as in ZDITHER0
, normally a number between 1 and 10000 (inclusive).
*
* @return itself
*
* @see #setTileIndex(int)
*/
public QuantizeOption setSeed(long value) {
config.seed = value;
return this;
}
/**
* Sets the tile index for which to initialize the random number generator with the given seed (i.e.
* ZDITHER0
value).
*
* @param index The 0-based tile index
*
* @return itself
*
* @see #setSeed(long)
*/
public QuantizeOption setTileIndex(int index) {
tileIndex = index;
return this;
}
@Override
public QuantizeOption setTileHeight(int value) {
tileHeight = value;
if (compressOption != null) {
compressOption.setTileHeight(value);
}
return this;
}
@Override
public QuantizeOption setTileWidth(int value) {
tileWidth = value;
if (compressOption != null) {
compressOption.setTileWidth(value);
}
return this;
}
@Override
public T unwrap(Class clazz) {
if (clazz.isAssignableFrom(this.getClass())) {
return clazz.cast(this);
}
if (compressOption != null) {
if (clazz.isAssignableFrom(compressOption.getClass())) {
return clazz.cast(compressOption);
}
}
return null;
}
/**
* Stores configuration in a way that can be shared and modified across enclosing option copies.
*
* @author Attila Kovacs
*
* @since 1.18
*/
private static final class Config {
private boolean centerOnZero;
private boolean checkZero;
private boolean dither;
private boolean dither2;
private double qlevel = Double.NaN;
private long seed = 1L;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy