package ini.trakem2.imaging;
import ij.process.ByteProcessor;
import ij.process.ColorProcessor;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
import ini.trakem2.utils.Utils;
import java.awt.image.ColorModel;
import java.lang.reflect.Field;
public class FloatProcessorT2 extends FloatProcessor {
static private Field fmin, fmax, ffixedScale;
static {
try {
fmin = FloatProcessor.class.getDeclaredField("min");
fmin.setAccessible(true);
fmax = FloatProcessor.class.getDeclaredField("max");
fmax.setAccessible(true);
ffixedScale = FloatProcessor.class.getDeclaredField("fixedScale");
ffixedScale.setAccessible(true);
} catch (Exception e) { e.printStackTrace(); }
}
public final void setMinMax(final double min, final double max) {
try {
fmin.set(this, (float)min);
fmax.set(this, (float)max);
ffixedScale.set(this, true);
super.minMaxSet = true;
} catch (Exception e) { e.printStackTrace(); }
}
/** Set pixels and change image dimensions if width and height are different than the current. */
public final void setPixels(final int width, final int height, final float[] pixels) {
this.width = width;
this.height = height;
this.roiX = 0;
this.roiY = 0;
this.roiWidth = width;
this.roiHeight = height;
super.setPixels(pixels);
}
public final void resizeInPlace(final int w, final int h) {
double min = getMin();
double max = getMax();
this.setPixels(w, h, (float[])super.resize(w, h).getPixels());
// set min,max again, since super.getPixels removes them
setMinMax(min, max);
}
/**
* Resizes this {@link FloatProcessorT2} instance by a factor of two by
* picking simply all pixels at even coordinates. The primary use for this
* method is downsampling after the image was smoothed with a respective
* Gaussian (e.g. σ=sqrt(0.75) to go from 0.5 to 0.5).
*/
public final void halfSizeInPlace() {
double min = getMin();
double max = getMax();
final int width2 = width + width;
final int wb = ( width + 1 ) / 2;
final int hb = ( height + 1 ) / 2;
final int nb = hb * wb;
final float[] aPixels = ( float[] )getPixels();
final float[] bPixels = new float[ nb ];
for ( int ya = 0, yb = 0; yb < nb; ya += width2, yb += wb )
{
for ( int xa = 0, xb = 0; xb < wb; xa += 2, ++xb )
{
bPixels[ yb + xb ] = aPixels[ ya + xa ];
}
}
setPixels( wb, hb, bPixels );
// set min,max again, since super.getPixels removes them
setMinMax(min, max);
}
public FloatProcessorT2(final int width, final int height, final float[] pixels, final ColorModel cm) {
super(width, height, null, cm);
if (pixels!=null && width*height!=pixels.length)
throw new IllegalArgumentException("width*height!=pixels.length");
this.width = width;
this.height = height;
setPixels(pixels); //this.pixels = pixels;
this.cm = cm;
resetRoi();
//if (pixels!=null)
// findMinAndMax();
}
public FloatProcessorT2(final int width, final int height, final float[] pixels, final ColorModel cm, final double min, final double max) {
this(width, height, pixels, cm);
setMinMax(min, max);
}
public FloatProcessorT2(final int width, final int height, final double min, final double max) {
this(width, height, new float[width*height], null);
setMinMax(min, max);
}
public FloatProcessorT2(final int width, final int height) {
this(width, height, 0, 0);
}
public FloatProcessorT2(final int width, final int height, final byte[] pix, final double min, final double max) {
this(width, height, new float[width*height], null, min, max);
final float[] pixels = (float[])getPixels(); // I luv pointlessly private fields
for (int i=0; i<pix.length; i++) {
pixels[i] = (pix[i]&0xff);
}
}
public FloatProcessorT2(final ColorProcessor cp, final int channel) {
this(cp.getWidth(), cp.getHeight(), 0, 255);
final int[] c = (int[])cp.getPixels();
int bitmask = 0;
int shift = 0;
switch (channel) {
case 0: bitmask = 0x00ff0000; shift = 16; break; // red
case 1: bitmask = 0x0000ff00; shift = 8; break; // green
case 2: bitmask = 0x000000ff; break; // blue
}
final float[] pixels = (float[])this.getPixels(); // I luv pointlessly private fields
for (int i=0; i<pixels.length; i++) pixels[i] = ((c[i] & bitmask)>>shift);
super.setMinAndMax(0, 255); // we know them
}
public FloatProcessorT2(final FloatProcessor fp) {
this(fp.getWidth(), fp.getHeight(), (float[])fp.getPixels(), fp.getColorModel(), fp.getMin(), fp.getMax());
}
public FloatProcessorT2(final ByteProcessor bp) {
this((FloatProcessor)bp.convertToFloat());
super.setMinAndMax(0, 255); // to avoid looking for it when min,max are perfectly known.
}
/** Returns a new, blank FloatProcessor with the specified width and height. */
public ImageProcessor createProcessor(final int width, final int height) {
ImageProcessor ip2 = new FloatProcessorT2(width, height, new float[width*height], getColorModel());
return ip2;
}
public void findMinAndMax() {
Utils.printCaller(this, 15);
Utils.log2("FPT2.findMinAndMax called");
super.findMinAndMax();
}
public final float[] getFloatPixels() { return (float[])getPixels(); } // I luv pointlessly private fields
/** Return the float array of pixels as a byte array, cropping (no scaling). */
public final byte[] getBytePixels() {
final float[] f = getFloatPixels();
final byte[] b = new byte[f.length];
int val;
final int size = width*height;
for (int i=0; i<size; ++i) {
val = (int)(f[i] + 0.5f);
if (val < 0) val = 0;
if (val > 255) val = 255;
b[i] = (byte)val;
}
return b;
}
public final byte[] getScaledBytePixels() {
final float[] f = getFloatPixels();
final byte[] b = new byte[f.length];
int val;
final int size = width*height;
final double min = getMin();
final double scale = 255 / (getMax() - min + 1);
//
for (int i=0; i<size; ++i) {
val = (int)((f[i] - min) * scale + 0.5);
if (val < 0) val = 0;
if (val > 255) val = 255;
b[i] = (byte)val;
}
return b;
}
/** Return the float array of pixels as a byte array, cropping (no scaling). */
public final int[] getRGBPixels() {
final float[] f = getFloatPixels();
final int[] rgb = new int[f.length];
int val;
final int size = width*height;
for (int i=0; i<size; ++i) {
val = (int)(f[i] + 0.5f);
if (val < 0) val = 0;
if (val > 255) val = 255;
rgb[i] = 0xff000000 | (val<<16) | (val<<8) | val;
}
return rgb;
}
/** Return the float array of pixels as a byte array, cropping (no scaling).
* It's your problem to ensure alpha has same length as width*height. */
public final int[] getARGBPixels(final byte[] alpha) {
final float[] f = getFloatPixels();
final int[] rgb = new int[f.length];
int val;
final int size = width*height;
for (int i=0; i<size; ++i) {
val = (int)(f[i] + 0.5f);
if (val < 0) val = 0;
if (val > 255) val = 255;
rgb[i] = ((alpha[i]&0xff)<<24) | (val<<16) | (val<<8) | val;
}
return rgb;
}
/** Return the float array of pixels as a byte array, cropping (no scaling).
* It's your problem to ensure alpha and outside have same length as width*height. */
public final int[] getARGBPixels(final byte[] alpha, final byte[] outside) {
final float[] f = getFloatPixels();
final int[] rgb = new int[f.length];
int val;
final int size = width*height;
for (int i=0; i<size; ++i) {
val = (int)(f[i] + 0.5f);
if (val < 0) val = 0;
if (val > 255) val = 255;
rgb[i] = ( (outside[i]&0xff) != 255 ? 0 : ((alpha[i]&0xff)<<24) ) | (val<<16) | (val<<8) | val;
}
return rgb;
}
public final void debugMinMax(String msg) {
try {
Utils.log(msg + "\n\tmin, max: " + fmin.get(this) +", " + fmax.get(this) + " minMaxSet: " + super.minMaxSet);
} catch (Throwable t) { ini.trakem2.utils.IJError.print(t); }
}
/** Return the float array of pixels as a byte array, with scaling.
* It's your problem to ensure alpha has same length as width*height. */
public final int[] getARGBPixels(final float[] alpha) {
final float[] f = getFloatPixels();
final int[] rgb = new int[f.length];
int val;
final int size = width*height;
final float min = (float)getMin();
final float max = (float)getMax();
final float scale = 256.0f/(max-min+1);
for (int i=0; i<size; ++i) {
val = (int)(f[i] - min);
if (val < 0) val = 0;
val = (int)(val*scale + 0.5f);
if (val > 255) val = 255;
rgb[i] = (((int)(alpha[i]+0.5f))<<24) + (val<<16) + (val<<8) + val;
}
return rgb;
}
/** Return the float array of pixels as a byte array, cropping (no scaling).
* It's your problem to ensure alpha and outside have same length as width*height. */
public final int[] getARGBPixels(final float[] alpha, final float[] outside) {
final float[] f = getFloatPixels();
final int[] rgb = new int[f.length];
int val;
final int size = width*height;
final float min = (float)getMin();
final float max = (float)getMax();
final float scale = 256.0f/(max-min+1);
for (int i=0; i<size; ++i) {
val = (int)(f[i] - min);
if (val < 0) val = 0;
val = (int)(val*scale + 0.5f);
if (val > 255) val = 255;
rgb[i] = ( ((int)(outside[i]+0.5f)) == 255 ? (((int)(alpha[i]+0.5f))<<24) : 0 ) + (val<<16) + (val<<8) + val;
}
return rgb;
}
}