package ij.process;
import java.util.*;
import java.awt.*;
import java.awt.image.*;
import ij.gui.*;
public class ShortProcessor extends ImageProcessor {
private int min, max, snapshotMin, snapshotMax;
private short[] pixels;
private byte[] pixels8;
private short[] snapshotPixels;
private byte[] LUT;
private boolean fixedScale;
private int bgValue;
public ShortProcessor(int width, int height, short[] pixels, ColorModel cm) {
if (pixels!=null && width*height!=pixels.length)
throw new IllegalArgumentException(WRONG_LENGTH);
init(width, height, pixels, cm);
}
public ShortProcessor(int width, int height) {
this(width, height, new short[width*height], null);
}
public ShortProcessor(BufferedImage bi) {
if (bi.getType()!=BufferedImage.TYPE_USHORT_GRAY)
throw new IllegalArgumentException("Type!=TYPE_USHORT_GRAY");
WritableRaster raster = bi.getRaster();
DataBuffer buffer = raster.getDataBuffer();
short[] data = ((DataBufferUShort) buffer).getData();
init(raster.getWidth(), raster.getHeight(), data, null);
}
void init(int width, int height, short[] pixels, ColorModel cm) {
this.width = width;
this.height = height;
this.pixels = pixels;
this.cm = cm;
resetRoi();
}
public ShortProcessor(int width, int height, short[] pixels, ColorModel cm, boolean unsigned) {
this(width, height, pixels, cm);
}
public ShortProcessor(int width, int height, boolean unsigned) {
this(width, height);
}
public void findMinAndMax() {
if (fixedScale || pixels==null)
return;
int size = width*height;
int value;
int min = pixels[0]&0xffff;
int max = pixels[0]&0xffff;
for (int i=1; i<size; i++) {
value = pixels[i]&0xffff;
if (value<min)
min = value;
else if (value>max)
max = value;
}
this.min = min;
this.max = max;
minMaxSet = true;
}
public Image createImage() {
if (!minMaxSet)
findMinAndMax();
boolean firstTime = pixels8==null;
boolean thresholding = minThreshold!=NO_THRESHOLD && lutUpdateMode<NO_LUT_UPDATE;
if (firstTime || !lutAnimation)
create8BitImage(thresholding&&lutUpdateMode==RED_LUT);
if (cm==null)
makeDefaultColorModel();
if (thresholding) {
int t1 = (int)minThreshold;
int t2 = (int)maxThreshold;
int size = width*height;
int value;
if (lutUpdateMode==BLACK_AND_WHITE_LUT) {
for (int i=0; i<size; i++) {
value = (pixels[i]&0xffff);
if (value>=t1 && value<=t2)
pixels8[i] = (byte)255;
else
pixels8[i] = (byte)0;
}
} else { for (int i=0; i<size; i++) {
value = (pixels[i]&0xffff);
if (value>=t1 && value<=t2)
pixels8[i] = (byte)255;
}
}
}
return createBufferedImage();
}
private byte[] create8BitImage(boolean thresholding) {
int size = width*height;
if (pixels8==null)
pixels8 = new byte[size];
int value;
int min2=(int)getMin(), max2=(int)getMax();
int maxValue = 255;
double scale = 256.0/(max2-min2+1);
if (thresholding) {
maxValue = 254;
scale = 255.0/(max2-min2+1);
}
for (int i=0; i<size; i++) {
value = (pixels[i]&0xffff)-min2;
if (value<0) value = 0;
value = (int)(value*scale+0.5);
if (value>maxValue) value = maxValue;
pixels8[i] = (byte)value;
}
return pixels8;
}
@Override
byte[] create8BitImage() {
return create8BitImage(false);
}
Image createBufferedImage() {
if (raster==null) {
SampleModel sm = getIndexSampleModel();
DataBuffer db = new DataBufferByte(pixels8, width*height, 0);
raster = Raster.createWritableRaster(sm, db, null);
}
if (image==null || cm!=cm2) {
if (cm==null) cm = getDefaultColorModel();
image = new BufferedImage(cm, raster, false, null);
cm2 = cm;
}
lutAnimation = false;
return image;
}
public BufferedImage getBufferedImage() {
return convertToByte(true).getBufferedImage();
}
public BufferedImage get16BitBufferedImage() {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
Raster raster = bi.getData();
DataBufferUShort db = (DataBufferUShort)raster.getDataBuffer();
System.arraycopy(getPixels(), 0, db.getData(), 0, db.getData().length);
bi.setData(raster);
return bi;
}
public ImageProcessor createProcessor(int width, int height) {
ImageProcessor ip2 = new ShortProcessor(width, height, new short[width*height], getColorModel());
ip2.setMinAndMax(getMin(), getMax());
ip2.setInterpolationMethod(interpolationMethod);
return ip2;
}
public void snapshot() {
snapshotWidth=width;
snapshotHeight=height;
snapshotMin=(int)getMin();
snapshotMax=(int)getMax();
if (snapshotPixels==null || (snapshotPixels!=null && snapshotPixels.length!=pixels.length))
snapshotPixels = new short[width * height];
System.arraycopy(pixels, 0, snapshotPixels, 0, width*height);
}
public void reset() {
if (snapshotPixels==null)
return;
min=snapshotMin;
max=snapshotMax;
minMaxSet = true;
System.arraycopy(snapshotPixels, 0, pixels, 0, width*height);
}
public void reset(ImageProcessor mask) {
if (mask==null || snapshotPixels==null)
return;
if (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight)
throw new IllegalArgumentException(maskSizeError(mask));
byte[] mpixels = (byte[])mask.getPixels();
for (int y=roiY, my=0; y<(roiY+roiHeight); y++, my++) {
int i = y * width + roiX;
int mi = my * roiWidth;
for (int x=roiX; x<(roiX+roiWidth); x++) {
if (mpixels[mi++]==0)
pixels[i] = snapshotPixels[i];
i++;
}
}
}
public void swapPixelArrays() {
if (snapshotPixels==null) return;
short pixel;
for (int i=0; i<pixels.length; i++) {
pixel = pixels[i];
pixels[i] = snapshotPixels[i];
snapshotPixels[i] = pixel;
}
}
public void setSnapshotPixels(Object pixels) {
snapshotPixels = (short[])pixels;
snapshotWidth=width;
snapshotHeight=height;
}
public Object getSnapshotPixels() {
return snapshotPixels;
}
public double getMin() {
if (!minMaxSet) findMinAndMax();
return min;
}
public double getMax() {
if (!minMaxSet) findMinAndMax();
return max;
}
public void setMinAndMax(double minimum, double maximum) {
if (minimum==0.0 && maximum==0.0) {
resetMinAndMax();
return;
}
if (minimum<0.0)
minimum = 0.0;
if (maximum>65535.0)
maximum = 65535.0;
min = (int)minimum;
max = (int)maximum;
fixedScale = true;
minMaxSet = true;
resetThreshold();
}
public void resetMinAndMax() {
fixedScale = false;
findMinAndMax();
resetThreshold();
}
public int getPixel(int x, int y) {
if (x>=0 && x<width && y>=0 && y<height)
return pixels[y*width+x]&0xffff;
else
return 0;
}
public final int get(int x, int y) {
return pixels[y*width+x]&0xffff;
}
public final void set(int x, int y, int value) {
pixels[y*width+x] = (short)value;
}
public final int get(int index) {
return pixels[index]&0xffff;
}
public final void set(int index, int value) {
pixels[index] = (short)value;
}
public final float getf(int x, int y) {
return pixels[y*width+x]&0xffff;
}
public final void setf(int x, int y, float value) {
pixels[y*width + x] = (short)(value+0.5f);
}
public final float getf(int index) {
return pixels[index]&0xffff;
}
public final void setf(int index, float value) {
pixels[index] = (short)value;
}
public double getInterpolatedPixel(double x, double y) {
if (interpolationMethod==BICUBIC)
return getBicubicInterpolatedPixel(x, y, this);
else {
if (x<0.0) x = 0.0;
if (x>=width-1.0) x = width-1.001;
if (y<0.0) y = 0.0;
if (y>=height-1.0) y = height-1.001;
return getInterpolatedPixel(x, y, pixels);
}
}
final public int getPixelInterpolated(double x, double y) {
if (interpolationMethod==BILINEAR) {
if (x<0.0 || y<0.0 || x>=width-1 || y>=height-1)
return 0;
else
return (int)Math.round(getInterpolatedPixel(x, y, pixels));
} else if (interpolationMethod==BICUBIC) {
int value = (int)(getBicubicInterpolatedPixel(x, y, this)+0.5);
if (value<0) value = 0;
if (value>65535) value = 65535;
return value;
} else
return getPixel((int)(x+0.5), (int)(y+0.5));
}
public final void putPixel(int x, int y, int value) {
if (x>=0 && x<width && y>=0 && y<height) {
if (value>65535) value = 65535;
if (value<0) value = 0;
pixels[y*width + x] = (short)value;
}
}
public void putPixelValue(int x, int y, double value) {
if (x>=0 && x<width && y>=0 && y<height) {
if (cTable!=null&&cTable[0]==-32768f) value += 32768.0;
if (value>65535.0)
value = 65535.0;
else if (value<0.0)
value = 0.0;
pixels[y*width + x] = (short)(value+0.5);
}
}
public void drawPixel(int x, int y) {
if (x>=clipXMin && x<=clipXMax && y>=clipYMin && y<=clipYMax)
putPixel(x, y, fgColor);
}
public float getPixelValue(int x, int y) {
if (x>=0 && x<width && y>=0 && y<height) {
if (cTable==null)
return pixels[y*width + x]&0xffff;
else
return cTable[pixels[y*width + x]&0xffff];
} else
return Float.NaN;
}
public Object getPixels() {
return (Object)pixels;
}
public Object getPixelsCopy() {
if (snapshotPixels!=null && snapshotCopyMode) {
snapshotCopyMode = false;
return snapshotPixels;
} else {
short[] pixels2 = new short[width*height];
System.arraycopy(pixels, 0, pixels2, 0, width*height);
return pixels2;
}
}
public void setPixels(Object pixels) {
this.pixels = (short[])pixels;
resetPixels(pixels);
if (pixels==null) snapshotPixels = null;
if (pixels==null) pixels8 = null;
raster = null;
}
void getRow2(int x, int y, int[] data, int length) {
int value;
for (int i=0; i<length; i++)
data[i] = pixels[y*width+x+i]&0xffff;
}
void putColumn2(int x, int y, int[] data, int length) {
int value;
for (int i=0; i<length; i++)
pixels[(y+i)*width+x] = (short)data[i];
}
public void copyBits(ImageProcessor ip, int xloc, int yloc, int mode) {
boolean temporaryFloat = ip.getBitDepth()==32 && (mode==Blitter.MULTIPLY || mode==Blitter.DIVIDE);
if (temporaryFloat) {
FloatProcessor ipFloat = this.convertToFloatProcessor();
new FloatBlitter(ipFloat).copyBits(ip, xloc, yloc, mode);
setPixels(1, ipFloat);
} else {
ip = ip.convertToShort(false);
new ShortBlitter(this).copyBits(ip, xloc, yloc, mode);
}
}
public void applyTable(int[] lut) {
if (lut.length!=65536)
throw new IllegalArgumentException("lut.length!=65536");
int lineStart, lineEnd, v;
for (int y=roiY; y<(roiY+roiHeight); y++) {
lineStart = y * width + roiX;
lineEnd = lineStart + roiWidth;
for (int i=lineEnd; --i>=lineStart;) {
v = lut[pixels[i]&0xffff];
pixels[i] = (short)v;
}
}
findMinAndMax();
}
private void process(int op, double value) {
int v1, v2;
double range = getMax()-getMin();
int offset = isSigned16Bit()?32768:0;
int min2 = (int)getMin() - offset;
int max2 = (int)getMax() - offset;
int fgColor2 = fgColor - offset;
int intValue = (int)value;
for (int y=roiY; y<(roiY+roiHeight); y++) {
int i = y * width + roiX;
for (int x=roiX; x<(roiX+roiWidth); x++) {
v1 = (pixels[i]&0xffff) - offset;
switch(op) {
case INVERT:
v2 = max2 - (v1 - min2);
break;
case FILL:
v2 = fgColor2;
break;
case SET:
v2 = intValue;
break;
case ADD:
v2 = v1 + intValue;
break;
case MULT:
v2 = (int)Math.round(v1*value);
break;
case AND:
v2 = v1 & intValue;
break;
case OR:
v2 = v1 | intValue;
break;
case XOR:
v2 = v1 ^ intValue;
break;
case GAMMA:
if (range<=0.0 || v1==min2)
v2 = v1;
else
v2 = (int)(Math.exp(value*Math.log((v1-min2)/range))*range+min2);
break;
case LOG:
if (v1<=0)
v2 = 0;
else
v2 = (int)(Math.log(v1)*(max2/Math.log(max2)));
break;
case EXP:
v2 = (int)(Math.exp(v1*(Math.log(max2)/max2)));
break;
case SQR:
double d1 = v1;
v2 = (int)(d1*d1);
break;
case SQRT:
v2 = (int)Math.sqrt(v1);
break;
case ABS:
v2 = (int)Math.abs(v1);
break;
case MINIMUM:
if (v1<value)
v2 = intValue;
else
v2 = v1;
break;
case MAXIMUM:
if (v1>value)
v2 = intValue;
else
v2 = v1;
break;
default:
v2 = v1;
}
v2 += offset;
if (v2 < 0)
v2 = 0;
if (v2 > 65535)
v2 = 65535;
pixels[i++] = (short)v2;
}
}
}
public void invert() {
int range = 65536;
int defaultRange = ij.ImagePlus.getDefault16bitRange();
if (defaultRange>0 && !isSigned16Bit())
range = (int)Math.pow(2,defaultRange);
setMinAndMax(0, range-1);
process(INVERT, 0.0);
resetMinAndMax();
}
public void add(int value) {process(ADD, value);}
public void add(double value) {process(ADD, value);}
public void set(double value) {process(SET, value);}
public void multiply(double value) {process(MULT, value);}
public void and(int value) {process(AND, value);}
public void or(int value) {process(OR, value);}
public void xor(int value) {process(XOR, value);}
public void gamma(double value) {process(GAMMA, value);}
public void log() {process(LOG, 0.0);}
public void exp() {process(EXP, 0.0);}
public void sqr() {process(SQR, 0.0);}
public void sqrt() {process(SQRT, 0.0);}
public void abs() {process(ABS, 0.0);}
public void min(double value) {process(MINIMUM, value);}
public void max(double value) {process(MAXIMUM, value);}
public void fill() {
process(FILL, 0.0);
}
public void fill(ImageProcessor mask) {
if (mask==null)
{fill(); return;}
int roiWidth=this.roiWidth, roiHeight=this.roiHeight;
int roiX=this.roiX, roiY=this.roiY;
if (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight)
return;
byte[] mpixels = (byte[])mask.getPixels();
for (int y=roiY, my=0; y<(roiY+roiHeight); y++, my++) {
int i = y * width + roiX;
int mi = my * roiWidth;
for (int x=roiX; x<(roiX+roiWidth); x++) {
if (mpixels[mi++]!=0)
pixels[i] = (short)fgColor;
i++;
}
}
}
public void convolve3x3(int[] kernel) {
filter3x3(CONVOLVE, kernel);
}
public void filter(int type) {
filter3x3(type, null);
}
void filter3x3(int type, int[] kernel) {
int v1, v2, v3; int v4, v5, v6;
int v7, v8, v9;
int k1=0, k2=0, k3=0; int k4=0, k5=0, k6=0;
int k7=0, k8=0, k9=0;
int scale = 0;
if (type==CONVOLVE) {
k1=kernel[0]; k2=kernel[1]; k3=kernel[2];
k4=kernel[3]; k5=kernel[4]; k6=kernel[5];
k7=kernel[6]; k8=kernel[7]; k9=kernel[8];
for (int i=0; i<kernel.length; i++)
scale += kernel[i];
if (scale==0) scale = 1;
}
short[] pixels2 = (short[])getPixelsCopy();
int xEnd = roiX + roiWidth;
int yEnd = roiY + roiHeight;
for (int y=roiY; y<yEnd; y++) {
int p = roiX + y*width; int p6 = p - (roiX>0 ? 1 : 0); int p3 = p6 - (y>0 ? width : 0); int p9 = p6 + (y<height-1 ? width : 0); v2 = pixels2[p3]&0xffff;
v5 = pixels2[p6]&0xffff;
v8 = pixels2[p9]&0xffff;
if (roiX>0) { p3++; p6++; p9++; }
v3 = pixels2[p3]&0xffff;
v6 = pixels2[p6]&0xffff;
v9 = pixels2[p9]&0xffff;
switch (type) {
case BLUR_MORE:
for (int x=roiX; x<xEnd; x++,p++) {
if (x<width-1) { p3++; p6++; p9++; }
v1 = v2; v2 = v3;
v3 = pixels2[p3]&0xffff;
v4 = v5; v5 = v6;
v6 = pixels2[p6]&0xffff;
v7 = v8; v8 = v9;
v9 = pixels2[p9]&0xffff;
pixels[p] = (short)((v1+v2+v3+v4+v5+v6+v7+v8+v9+4)/9);
}
break;
case FIND_EDGES:
for (int x=roiX; x<xEnd; x++,p++) {
if (x<width-1) { p3++; p6++; p9++; }
v1 = v2; v2 = v3;
v3 = pixels2[p3]&0xffff;
v4 = v5; v5 = v6;
v6 = pixels2[p6]&0xffff;
v7 = v8; v8 = v9;
v9 = pixels2[p9]&0xffff;
double sum1 = v1 + 2*v2 + v3 - v7 - 2*v8 - v9;
double sum2 = v1 + 2*v4 + v7 - v3 - 2*v6 - v9;
double result = Math.sqrt(sum1*sum1 + sum2*sum2);
if (result>65535.0) result = 65535.0;
pixels[p] = (short)result;
}
break;
case CONVOLVE:
for (int x=roiX; x<xEnd; x++,p++) {
if (x<width-1) { p3++; p6++; p9++; }
v1 = v2; v2 = v3;
v3 = pixels2[p3]&0xffff;
v4 = v5; v5 = v6;
v6 = pixels2[p6]&0xffff;
v7 = v8; v8 = v9;
v9 = pixels2[p9]&0xffff;
int sum = k1*v1 + k2*v2 + k3*v3
+ k4*v4 + k5*v5 + k6*v6
+ k7*v7 + k8*v8 + k9*v9;
sum = (sum+scale/2)/scale; if(sum>65535) sum = 65535;
if(sum<0) sum = 0;
pixels[p] = (short)sum;
}
break;
}
}
}
public void rotate(double angle) {
short[] pixels2 = (short[])getPixelsCopy();
ImageProcessor ip2 = null;
if (interpolationMethod==BICUBIC)
ip2 = new ShortProcessor(getWidth(), getHeight(), pixels2, null);
double centerX = roiX + (roiWidth-1)/2.0;
double centerY = roiY + (roiHeight-1)/2.0;
int xMax = roiX + this.roiWidth - 1;
double angleRadians = -angle/(180.0/Math.PI);
double ca = Math.cos(angleRadians);
double sa = Math.sin(angleRadians);
double tmp1 = centerY*sa-centerX*ca;
double tmp2 = -centerX*sa-centerY*ca;
double tmp3, tmp4, xs, ys;
int index, ixs, iys;
double dwidth=width,dheight=height;
double xlimit = width-1.0, xlimit2 = width-1.001;
double ylimit = height-1.0, ylimit2 = height-1.001;
int background = isSigned16Bit()?bgValue+32768:bgValue;
if (interpolationMethod==BICUBIC) {
for (int y=roiY; y<(roiY + roiHeight); y++) {
index = y*width + roiX;
tmp3 = tmp1 - y*sa + centerX;
tmp4 = tmp2 + y*ca + centerY;
for (int x=roiX; x<=xMax; x++) {
xs = x*ca + tmp3;
ys = x*sa + tmp4;
int value = (int)(getBicubicInterpolatedPixel(xs, ys, ip2)+0.5);
if (value<0) value = 0;
if (value>65535) value = 65535;
pixels[index++] = (short)value;
}
}
} else {
for (int y=roiY; y<(roiY + roiHeight); y++) {
index = y*width + roiX;
tmp3 = tmp1 - y*sa + centerX;
tmp4 = tmp2 + y*ca + centerY;
for (int x=roiX; x<=xMax; x++) {
xs = x*ca + tmp3;
ys = x*sa + tmp4;
if ((xs>=-0.01) && (xs<dwidth) && (ys>=-0.01) && (ys<dheight)) {
if (interpolationMethod==BILINEAR) {
if (xs<0.0) xs = 0.0;
if (xs>=xlimit) xs = xlimit2;
if (ys<0.0) ys = 0.0;
if (ys>=ylimit) ys = ylimit2;
pixels[index++] = (short)(getInterpolatedPixel(xs, ys, pixels2)+0.5);
} else {
ixs = (int)(xs+0.5);
iys = (int)(ys+0.5);
if (ixs>=width) ixs = width - 1;
if (iys>=height) iys = height -1;
pixels[index++] = pixels2[width*iys+ixs];
}
} else
pixels[index++] = (short)background;
}
}
}
}
public void flipVertical() {
int index1,index2;
short tmp;
for (int y=0; y<roiHeight/2; y++) {
index1 = (roiY+y)*width+roiX;
index2 = (roiY+roiHeight-1-y)*width+roiX;
for (int i=0; i<roiWidth; i++) {
tmp = pixels[index1];
pixels[index1++] = pixels[index2];
pixels[index2++] = tmp;
}
}
}
public void scale(double xScale, double yScale) {
double xCenter = roiX + roiWidth/2.0;
double yCenter = roiY + roiHeight/2.0;
int xmin, xmax, ymin, ymax;
if ((xScale>1.0) && (yScale>1.0)) {
xmin = (int)(xCenter-(xCenter-roiX)*xScale);
if (xmin<0) xmin = 0;
xmax = xmin + (int)(roiWidth*xScale) - 1;
if (xmax>=width) xmax = width - 1;
ymin = (int)(yCenter-(yCenter-roiY)*yScale);
if (ymin<0) ymin = 0;
ymax = ymin + (int)(roiHeight*yScale) - 1;
if (ymax>=height) ymax = height - 1;
} else {
xmin = roiX;
xmax = roiX + roiWidth - 1;
ymin = roiY;
ymax = roiY + roiHeight - 1;
}
short[] pixels2 = (short[])getPixelsCopy();
ImageProcessor ip2 = null;
if (interpolationMethod==BICUBIC)
ip2 = new ShortProcessor(getWidth(), getHeight(), pixels2, null);
boolean checkCoordinates = (xScale < 1.0) || (yScale < 1.0);
short min2 = (short)getMin();
int index1, index2, xsi, ysi;
double ys, xs;
if (interpolationMethod==BICUBIC) {
for (int y=ymin; y<=ymax; y++) {
ys = (y-yCenter)/yScale + yCenter;
int index = y*width + xmin;
for (int x=xmin; x<=xmax; x++) {
xs = (x-xCenter)/xScale + xCenter;
int value = (int)(getBicubicInterpolatedPixel(xs, ys, ip2)+0.5);
if (value<0) value=0; if (value>65535) value=65535;
pixels[index++] = (short)value;
}
}
} else {
double xlimit = width-1.0, xlimit2 = width-1.001;
double ylimit = height-1.0, ylimit2 = height-1.001;
for (int y=ymin; y<=ymax; y++) {
ys = (y-yCenter)/yScale + yCenter;
ysi = (int)ys;
if (ys<0.0) ys = 0.0;
if (ys>=ylimit) ys = ylimit2;
index1 = y*width + xmin;
index2 = width*(int)ys;
for (int x=xmin; x<=xmax; x++) {
xs = (x-xCenter)/xScale + xCenter;
xsi = (int)xs;
if (checkCoordinates && ((xsi<xmin) || (xsi>xmax) || (ysi<ymin) || (ysi>ymax)))
pixels[index1++] = min2;
else {
if (interpolationMethod==BILINEAR) {
if (xs<0.0) xs = 0.0;
if (xs>=xlimit) xs = xlimit2;
pixels[index1++] = (short)(getInterpolatedPixel(xs, ys, pixels2)+0.5);
} else
pixels[index1++] = pixels2[index2+xsi];
}
}
}
}
}
private final double getInterpolatedPixel(double x, double y, short[] pixels) {
int xbase = (int)x;
int ybase = (int)y;
double xFraction = x - xbase;
double yFraction = y - ybase;
int offset = ybase * width + xbase;
int lowerLeft = pixels[offset]&0xffff;
int lowerRight = pixels[offset + 1]&0xffff;
int upperRight = pixels[offset + width + 1]&0xffff;
int upperLeft = pixels[offset + width]&0xffff;
double upperAverage = upperLeft + xFraction * (upperRight - upperLeft);
double lowerAverage = lowerLeft + xFraction * (lowerRight - lowerLeft);
return lowerAverage + yFraction * (upperAverage - lowerAverage);
}
public ImageProcessor resize(int dstWidth, int dstHeight) {
if (roiWidth==dstWidth && roiHeight==dstHeight)
return crop();
if ((width==1||height==1) && interpolationMethod!=NONE)
return resizeLinearly(dstWidth, dstHeight);
double srcCenterX = roiX + roiWidth/2.0;
double srcCenterY = roiY + roiHeight/2.0;
double dstCenterX = dstWidth/2.0;
double dstCenterY = dstHeight/2.0;
double xScale = (double)dstWidth/roiWidth;
double yScale = (double)dstHeight/roiHeight;
if (interpolationMethod!=NONE) {
if (dstWidth!=width) dstCenterX+=xScale/4.0;
if (dstHeight!=height) dstCenterY+=yScale/4.0;
}
int inc = getProgressIncrement(dstWidth,dstHeight);
ImageProcessor ip2 = createProcessor(dstWidth, dstHeight);
short[] pixels2 = (short[])ip2.getPixels();
double xs, ys;
if (interpolationMethod==BICUBIC) {
for (int y=0; y<=dstHeight-1; y++) {
if (inc>0&&y%inc==0) showProgress((double)y/dstHeight);
ys = (y-dstCenterY)/yScale + srcCenterY;
int index2 = y*dstWidth;
for (int x=0; x<=dstWidth-1; x++) {
xs = (x-dstCenterX)/xScale + srcCenterX;
int value = (int)(getBicubicInterpolatedPixel(xs, ys, this)+0.5);
if (value<0) value=0; if (value>65535) value=65535;
pixels2[index2++] = (short)value;
}
}
} else {
double xlimit = width-1.0, xlimit2 = width-1.001;
double ylimit = height-1.0, ylimit2 = height-1.001;
int index1, index2;
for (int y=0; y<=dstHeight-1; y++) {
if (inc>0&&y%inc==0) showProgress((double)y/dstHeight);
ys = (y-dstCenterY)/yScale + srcCenterY;
if (interpolationMethod==BILINEAR) {
if (ys<0.0) ys = 0.0;
if (ys>=ylimit) ys = ylimit2;
}
index1 = width*(int)ys;
index2 = y*dstWidth;
for (int x=0; x<=dstWidth-1; x++) {
xs = (x-dstCenterX)/xScale + srcCenterX;
if (interpolationMethod==BILINEAR) {
if (xs<0.0) xs = 0.0;
if (xs>=xlimit) xs = xlimit2;
pixels2[index2++] = (short)(getInterpolatedPixel(xs, ys, pixels)+0.5);
} else
pixels2[index2++] = pixels[index1+(int)xs];
}
}
}
if (inc>0) showProgress(1.0);
return ip2;
}
public ImageProcessor crop() {
ImageProcessor ip2 = createProcessor(roiWidth, roiHeight);
short[] pixels2 = (short[])ip2.getPixels();
for (int ys=roiY; ys<roiY+roiHeight; ys++) {
int offset1 = (ys-roiY)*roiWidth;
int offset2 = ys*width+roiX;
for (int xs=0; xs<roiWidth; xs++)
pixels2[offset1++] = pixels[offset2++];
}
return ip2;
}
public ImageProcessor duplicate() {
ImageProcessor ip2 = createProcessor(width, height);
short[] pixels2 = (short[])ip2.getPixels();
System.arraycopy(pixels, 0, pixels2, 0, width*height);
return ip2;
}
public void setColor(Color color) {
drawingColor = color;
int bestIndex = getBestIndex(color);
if (bestIndex>0 && getMin()==0.0 && getMax()==0.0) {
setValue(bestIndex);
setMinAndMax(0.0,255.0);
} else if (bestIndex==0 && getMin()>0.0 && (color.getRGB()&0xffffff)==0) {
if (isSigned16Bit())
setValue(32768);
else
setValue(0.0);
} else
fgColor = (int)(getMin() + (getMax()-getMin())*(bestIndex/255.0));
fillValueSet = true;
}
public void setBackgroundColor(Color color) {
int bestIndex = getBestIndex(color);
int value = (int)(getMin() + (getMax()-getMin())*(bestIndex/255.0));
setBackgroundValue(value);
}
public void setValue(double value) {
fgColor = (int)value;
if (fgColor<0) fgColor = 0;
if (fgColor>65535) fgColor = 65535;
fillValueSet = true;
}
public double getForegroundValue() {
return fgColor;
}
public void setBackgroundValue(double value) {
bgValue = (int)value;
if (bgValue<0) bgValue = 0;
if (bgValue>65535) bgValue = 65535;
}
public double getBackgroundValue() {
return bgValue;
}
public int[] getHistogram() {
if (mask!=null)
return getHistogram(mask);
int roiX=this.roiX, roiY=this.roiY;
int roiWidth=this.roiWidth, roiHeight=this.roiHeight;
int[] histogram = new int[65536];
for (int y=roiY; y<(roiY+roiHeight); y++) {
int i = y*width + roiX;
for (int x=roiX; x<(roiX+roiWidth); x++)
histogram[pixels[i++]&0xffff]++;
}
return histogram;
}
int[] getHistogram(ImageProcessor mask) {
if (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight)
throw new IllegalArgumentException(maskSizeError(mask));
int roiX=this.roiX, roiY=this.roiY;
int roiWidth=this.roiWidth, roiHeight=this.roiHeight;
byte[] mpixels = (byte[])mask.getPixels();
int[] histogram = new int[65536];
for (int y=roiY, my=0; y<(roiY+roiHeight); y++, my++) {
int i = y * width + roiX;
int mi = my * roiWidth;
for (int x=roiX; x<(roiX+roiWidth); x++) {
if (mpixels[mi++]!=0)
histogram[pixels[i]&0xffff]++;
i++;
}
}
return histogram;
}
int[] getHistogram2() {
if (mask!=null)
return getHistogram2(mask);
int roiX=this.roiX, roiY=this.roiY;
int roiWidth=this.roiWidth, roiHeight=this.roiHeight;
int max = 0;
int value;
for (int y=roiY; y<(roiY+roiHeight); y++) {
int index = y*width + roiX;
for (int i=0; i<roiWidth; i++) {
value = pixels[index++]&0xffff;
if (value>max)
max = value;
}
}
int size = max + 1;
if (size<256) size = 256;
int[] histogram = new int[size];
for (int y=roiY; y<(roiY+roiHeight); y++) {
int index = y*width + roiX;
for (int i=0; i<roiWidth; i++)
histogram[pixels[index++]&0xffff]++;
}
return histogram;
}
private int[] getHistogram2(ImageProcessor mask) {
if (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight)
throw new IllegalArgumentException(maskSizeError(mask));
int roiX=this.roiX, roiY=this.roiY;
int roiWidth=this.roiWidth, roiHeight=this.roiHeight;
byte[] mpixels = (byte[])mask.getPixels();
int max = 0;
int value;
for (int y=roiY; y<(roiY+roiHeight); y++) {
int index = y*width + roiX;
for (int i=0; i<roiWidth; i++) {
value = pixels[index++]&0xffff;
if (value>max)
max = value;
}
}
int size = max + 1;
if (size<256) size = 256;
int[] histogram = new int[size];
for (int y=roiY, my=0; y<(roiY+roiHeight); y++, my++) {
int index = y * width + roiX;
int mi = my * roiWidth;
for (int i=0; i<roiWidth; i++) {
if (mpixels[mi++]!=0)
histogram[pixels[index]&0xffff]++;
index++;
}
}
return histogram;
}
public void setLutAnimation(boolean lutAnimation) {
this.lutAnimation = false;
}
public void setThreshold(double minThreshold, double maxThreshold, int lutUpdate) {
if (minThreshold==NO_THRESHOLD) {
resetThreshold();
return;
}
if (minThreshold<0.0) minThreshold = 0.0;
if (maxThreshold>65535.0) maxThreshold = 65535.0;
int min2=(int)getMin(), max2=(int)getMax();
if (max2>min2) {
if (lutUpdate==OVER_UNDER_LUT) {
double minT = ((minThreshold-getMin())/(getMax()-getMin())*255.0);
double maxT = ((maxThreshold-getMin())/(getMax()-getMin())*255.0);
super.setThreshold(minT, maxT, lutUpdate); } else {
lutUpdateMode = lutUpdate;
if (rLUT1==null) {
if (cm==null)
makeDefaultColorModel();
baseCM = cm;
IndexColorModel m = (IndexColorModel)cm;
rLUT1 = new byte[256]; gLUT1 = new byte[256]; bLUT1 = new byte[256];
m.getReds(rLUT1); m.getGreens(gLUT1); m.getBlues(bLUT1);
rLUT2 = new byte[256]; gLUT2 = new byte[256]; bLUT2 = new byte[256];
}
if (lutUpdateMode==RED_LUT)
cm = getThresholdColorModel();
else
cm = getDefaultColorModel();
}
} else
super.resetThreshold();
this.minThreshold = Math.round(minThreshold);
this.maxThreshold = Math.round(maxThreshold);
}
public void convolve(float[] kernel, int kernelWidth, int kernelHeight) {
ImageProcessor ip2 = convertToFloat();
ip2.setRoi(getRoi());
new ij.plugin.filter.Convolver().convolve(ip2, kernel, kernelWidth, kernelHeight);
ip2 = ip2.convertToShort(false);
short[] pixels2 = (short[])ip2.getPixels();
System.arraycopy(pixels2, 0, pixels, 0, pixels.length);
}
public void noise(double standardDeviation) {
if (rnd==null)
rnd = new Random();
if (!Double.isNaN(seed))
rnd.setSeed((int) seed);
seed = Double.NaN;
int v, ran;
boolean inRange;
for (int y=roiY; y<(roiY+roiHeight); y++) {
int i = y * width + roiX;
for (int x=roiX; x<(roiX+roiWidth); x++) {
inRange = false;
do {
ran = (int)Math.round(rnd.nextGaussian()*standardDeviation);
v = (pixels[i] & 0xffff) + ran;
inRange = v>=0 && v<=65535;
if (inRange) pixels[i] = (short)v;
} while (!inRange);
i++;
}
}
resetMinAndMax();
}
public void threshold(int level) {
for (int i=0; i<width*height; i++) {
if ((pixels[i]&0xffff)<=level)
pixels[i] = 0;
else
pixels[i] = (short)255;
}
findMinAndMax();
}
public FloatProcessor toFloat(int channelNumber, FloatProcessor fp) {
int size = width*height;
if (fp == null || fp.getWidth()!=width || fp.getHeight()!=height)
fp = new FloatProcessor(width, height, new float[size], cm);
float[] fPixels = (float[])fp.getPixels();
for (int i=0; i<size; i++)
fPixels[i] = pixels[i]&0xffff;
fp.setRoi(getRoi());
fp.setMask(mask);
fp.setMinAndMax(getMin(), getMax());
fp.setThreshold(minThreshold, maxThreshold, ImageProcessor.NO_LUT_UPDATE);
return fp;
}
public void setPixels(int channelNumber, FloatProcessor fp) {
float[] fPixels = (float[])fp.getPixels();
float value;
int size = width*height;
for (int i=0; i<size; i++) {
value = fPixels[i] + 0.5f;
if (value<0f) value = 0f;
if (value>65535f) value = 65535f;
pixels[i] = (short)value;
}
setMinAndMax(fp.getMin(), fp.getMax());
}
public double maxValue() {
return 65535.0;
}
public int getBitDepth() {
return 16;
}
public boolean isSigned16Bit() {
return cTable!=null && cTable[0]==-32768f && cTable[1]==-32767f;
}
public ByteProcessor createMask() {
if (getMinThreshold()==NO_THRESHOLD)
return null;
int minThreshold = (int)getMinThreshold();
int maxThreshold = (int)getMaxThreshold();
ByteProcessor mask = new ByteProcessor(width, height);
byte[] mpixels = (byte[])mask.getPixels();
for (int i=0; i<pixels.length; i++) {
int value = pixels[i]&0xffff;
if (value>=minThreshold && value<=maxThreshold)
mpixels[i] = (byte)255;
}
return mask;
}
public void medianFilter() {}
public void erode() {}
public void dilate() {}
}