Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
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;
}
}