5 import java.awt.image.*;
6 import java.lang.reflect.*;
21 public static final int BLACK = 0xFF000000;
33 static public final int RED_LUT=0, BLACK_AND_WHITE_LUT=1, NO_LUT_UPDATE=2, OVER_UNDER_LUT=3;
34 static final int INVERT=0, FILL=1, ADD=2, MULT=3, AND=4, OR=5,
35 XOR=6, GAMMA=7, LOG=8, MINIMUM=9, MAXIMUM=10, SQR=11, SQRT=12;
36 static final int BLUR_MORE=0, FIND_EDGES=1, MEDIAN_FILTER=2, MIN=3, MAX=4;
37 static final String WRONG_LENGTH =
"(width*height) != pixels.length";
40 protected int lineWidth = 1;
43 protected FontMetrics fontMetrics;
44 protected boolean antialiasedText;
45 protected boolean boldFont;
48 ProgressBar progressBar;
49 boolean pixelsModified;
50 protected int width, snapshotWidth;
51 protected int height, snapshotHeight;
52 protected int roiX, roiY, roiWidth, roiHeight;
53 protected int xMin, xMax, yMin, yMax;
54 boolean newSnapshot =
false;
56 protected ColorModel baseCM;
57 protected ColorModel cm;
58 protected byte[] rLUT1, gLUT1, bLUT1;
59 protected byte[] rLUT2, gLUT2, bLUT2;
60 protected boolean interpolate;
62 protected int histogramSize = 256;
63 protected double histogramMin, histogramMax;
64 protected float[] cTable;
65 protected boolean lutAnimation;
66 protected MemoryImageSource source;
68 protected boolean newPixels;
69 protected Color drawingColor = Color.black;
70 protected int clipXMin, clipXMax, clipYMin, clipYMax;
74 protected void showProgress(
double percentDone) {
75 if (progressBar!=null)
76 progressBar.show(percentDone);
79 protected void hideProgress() {
99 makeDefaultColorModel();
109 if (!(
this instanceof
ColorProcessor) && !(cm instanceof IndexColorModel))
110 throw new IllegalArgumentException(
"Must be IndexColorModel");
113 rLUT1 = rLUT2 = null;
115 inversionTested =
false;
119 protected void makeDefaultColorModel() {
120 byte[] rLUT =
new byte[256];
121 byte[] gLUT =
new byte[256];
122 byte[] bLUT =
new byte[256];
123 for(
int i=0; i<256; i++) {
128 cm =
new IndexColorModel(8, 256, rLUT, gLUT, bLUT);
135 makeDefaultColorModel();
136 IndexColorModel icm = (IndexColorModel)cm;
137 int mapSize = icm.getMapSize();
138 byte[] reds =
new byte[mapSize];
139 byte[] greens =
new byte[mapSize];
140 byte[] blues =
new byte[mapSize];
141 byte[] reds2 =
new byte[mapSize];
142 byte[] greens2 =
new byte[mapSize];
143 byte[] blues2 =
new byte[mapSize];
145 icm.getGreens(greens);
147 for (
int i=0; i<mapSize; i++) {
148 reds2[i] = (byte)(reds[mapSize-i-1]&255);
149 greens2[i] = (byte)(greens[mapSize-i-1]&255);
150 blues2[i] = (byte)(blues[mapSize-i-1]&255);
152 ColorModel cm =
new IndexColorModel(8, mapSize, reds2, greens2, blues2);
159 makeDefaultColorModel();
160 IndexColorModel icm = (IndexColorModel)cm;
161 int mapSize = icm.getMapSize();
162 byte[] rLUT =
new byte[mapSize];
163 byte[] gLUT =
new byte[mapSize];
164 byte[] bLUT =
new byte[mapSize];
168 int minDistance = Integer.MAX_VALUE;
175 for (
int i=0; i<mapSize; i++) {
176 r2 = rLUT[i]&0xff; g2 = gLUT[i]&0xff; b2 = bLUT[i]&0xff;
177 distance = (r2-r1)*(r2-r1)+(g2-g1)*(g2-g1)+(b2-b1)*(b2-b1);
179 if (distance<minDistance) {
180 minDistance = distance;
183 if (minDistance==0.0)
189 protected boolean inversionTested =
false;
190 protected boolean invertedLut;
196 inversionTested =
true;
197 if (cm==null || !(cm instanceof IndexColorModel))
198 return (invertedLut=
false);
199 IndexColorModel icm = (IndexColorModel)cm;
202 for (
int i=1; i<255; i++) {
203 v1 = icm.getRed(i-1)+icm.getGreen(i-1)+icm.getBlue(i-1);
204 v2 = icm.getRed(i)+icm.getGreen(i)+icm.getBlue(i);
215 if (cm==null || !(cm instanceof IndexColorModel))
217 IndexColorModel icm = (IndexColorModel)cm;
218 int mapSize = icm.getMapSize();
219 byte[] reds =
new byte[mapSize];
220 byte[] greens =
new byte[mapSize];
221 byte[] blues =
new byte[mapSize];
223 icm.getGreens(greens);
225 boolean isColor =
false;
226 for (
int i=0; i<mapSize; i++) {
227 if ((reds[i] != greens[i]) || (greens[i] != blues[i])) {
239 if (cm==null || !(cm instanceof IndexColorModel))
243 IndexColorModel icm = (IndexColorModel)cm;
244 int mapSize = icm.getMapSize();
247 byte[] reds =
new byte[mapSize];
248 byte[] greens =
new byte[mapSize];
249 byte[] blues =
new byte[mapSize];
251 icm.getGreens(greens);
254 int r2=reds[0]&255, g2=greens[0]&255, b2=blues[0]&255;
255 double sum=0.0, sum2=0.0;
256 for (
int i=0; i<mapSize; i++) {
257 r=reds[i]&255; g=greens[i]&255; b=blues[i]&255;
258 d=r-r2; sum+=d; sum2+=d*d;
259 d=g-g2; sum+=d; sum2+=d*d;
260 d=b-b2; sum+=d; sum2+=d*d;
263 double stdDev = (768*sum2-sum*sum)/768.0;
265 stdDev = Math.sqrt(stdDev/(767.0));
274 public abstract void setColor(Color color);
282 public abstract void setValue(
double value);
285 public abstract double getMin();
288 public abstract double getMax();
305 public void setThreshold(
double minThreshold,
double maxThreshold,
int lutUpdate) {
309 this.minThreshold = minThreshold;
310 this.maxThreshold = maxThreshold;
317 if (lutUpdate==NO_LUT_UPDATE)
321 makeDefaultColorModel();
323 IndexColorModel m = (IndexColorModel)cm;
324 rLUT1 =
new byte[256]; gLUT1 =
new byte[256]; bLUT1 =
new byte[256];
325 m.getReds(rLUT1); m.getGreens(gLUT1); m.getBlues(bLUT1);
326 rLUT2 =
new byte[256]; gLUT2 =
new byte[256]; bLUT2 =
new byte[256];
328 int t1 = (int)minThreshold;
329 int t2 = (int)maxThreshold;
331 if (lutUpdate==RED_LUT)
332 for (
int i=0; i<256; i++) {
333 if (i>=t1 && i<=t2) {
334 rLUT2[i] = (byte)255;
343 else if (lutUpdate==BLACK_AND_WHITE_LUT)
344 for (
int i=0; i<256; i++) {
345 if (i>=t1 && i<=t2) {
350 rLUT2[i] = (byte)255;
351 gLUT2[i] = (byte)255;
352 bLUT2[i] = (byte)255;
356 for (
int i=0; i<256; i++) {
357 if (i>=t1 && i<=t2) {
364 gLUT2[i] = (byte)255;
369 bLUT2[i] = (byte)255;
373 cm =
new IndexColorModel(8, 256, rLUT2, gLUT2, bLUT2);
384 rLUT1 = rLUT2 = null;
385 inversionTested =
false;
408 setRoi(roi.x, roi.y, roi.width, roi.height);
415 public void setRoi(
int x,
int y,
int rwidth,
int rheight) {
416 if (x<0 || y<0 || x+rwidth>width || y+rheight>height) {
418 Rectangle r1 =
new Rectangle(x, y, rwidth, rheight);
419 Rectangle r2 = r1.intersection(
new Rectangle(0, 0, width, height));
420 if (r2.width<=0 || r2.height<=0) {
421 roiX=0; roiY=0; roiWidth=0; roiHeight=0;
422 xMin=0; xMax=0; yMin=0; yMax=0;
427 Rectangle r3 =
new Rectangle(0, 0, r2.width, r2.height);
433 roiX=r2.x; roiY=r2.y; roiWidth=r2.width; roiHeight=r2.height;
435 roiX=x; roiY=y; roiWidth=rwidth; roiHeight=rheight;
440 xMin = Math.max(roiX, 1);
441 xMax = Math.min(roiX + roiWidth - 1, width - 2);
442 yMin = Math.max(roiY, 1);
443 yMax = Math.min(roiY + roiHeight - 1, height - 2);
488 Rectangle bounds = roi.getBounds();
489 for (
int i=0; i<roi.npoints; i++) {
490 roi.xpoints[i] -= bounds.x;
491 roi.ypoints[i] -= bounds.y;
494 pf.
setPolygon(roi.xpoints, roi.ypoints, roi.npoints);
498 for (
int i=0; i<roi.npoints; i++) {
499 roi.xpoints[i] += bounds.x;
500 roi.ypoints[i] += bounds.y;
506 roiX=0; roiY=0; roiWidth=width; roiHeight=height;
507 xMin=1; xMax=width-2; yMin=1; yMax=height-2;
509 clipXMin=0; clipXMax=width-1; clipYMin=0; clipYMax=height-1;
515 return new Rectangle(roiX, roiY, roiWidth, roiHeight);
533 return mask!=null?(byte[])mask.
getPixels():null;
545 this.interpolate = interpolate;
558 private void process(
int op,
double value) {
559 double SCALE = 255.0/Math.log(255.0);
562 int[] lut =
new int[256];
563 for (
int i=0; i<256; i++) {
575 v = (int)Math.round(i * value);
587 v = (int)(Math.exp(Math.log(i/255.0)*value)*255.0);
593 v = (int)(Math.log(i) * SCALE);
599 v = (int)Math.sqrt(i);
632 public double[]
getLine(
double x1,
double y1,
double x2,
double y2) {
635 int n = (int)Math.round(Math.sqrt(dx*dx + dy*dy));
639 double[] data =
new double[n];
643 for (
int i=0; i<n; i++) {
652 for (
int i=0; i<n; i++) {
661 public void getRow(
int x,
int y,
int[] data,
int length) {
662 for (
int i=0; i<length; i++)
667 public void getColumn(
int x,
int y,
int[] data,
int length) {
668 for (
int i=0; i<length; i++)
674 public void putRow(
int x,
int y,
int[] data,
int length) {
675 for (
int i=0; i<length; i++)
681 public void putColumn(
int x,
int y,
int[] data,
int length) {
685 for (
int i=0; i<length; i++)
702 if (lineWidth<1) lineWidth = 1;
709 int absdx = dx>=0?dx:-dx;
710 int absdy = dy>=0?dy:-dy;
711 int n = absdy>absdx?absdy:absdx;
712 double xinc = (double)dx/n;
713 double yinc = (double)dy/n;
720 else if (lineWidth==2)
731 public void drawLine(
int x1,
int y1,
int x2,
int y2) {
737 public void drawRect(
int x,
int y,
int width,
int height) {
738 if (width<1 || height<1)
742 lineTo(x+width-1, y+height-1);
749 moveTo(p.xpoints[0], p.ypoints[0]);
750 for (
int i=0; i<p.npoints; i++)
751 lineTo(p.xpoints[i], p.ypoints[i]);
752 lineTo(p.xpoints[0], p.ypoints[0]);
771 public void drawDot(
int xcenter,
int ycenter) {
774 for (
int x=-r; x<=r; x++)
775 for (
int y=-r; y<=r; y++)
780 private void setupFrame() {
784 frame.setBackground(Color.white);
787 font =
new Font(
"SansSerif", Font.PLAIN, 12);
788 if (fontMetrics==null) {
790 fontMetrics = frame.getFontMetrics(font);
799 if (ij.IJ.isMacOSX())
809 int h = fontMetrics.getHeight();
810 Image img = frame.createImage(w, h);
811 Graphics g = img.getGraphics();
812 FontMetrics metrics = g.getFontMetrics(font);
813 int fontHeight = metrics.getHeight();
814 int descent = metrics.getDescent();
817 if (antialiasedText) {
818 Java2.setAntialiasedText(g,
true);
823 g.setColor(drawingColor);
824 g.drawString(s, 0, h-descent);
837 if (ij.IJ.isMacOSX()) {
838 Java2.setAntialiasedText(g,
false);
839 g.setColor(Color.white);
840 g.fillRect(0, 0, w, h);
842 g.setColor(Color.black);
843 g.drawString(s, 0, h-descent);
847 byte[] mpixels = (byte[])textMask.
getPixels();
850 if (cxx<width && cy-h<height) {
868 this.justification = justification;
875 boldFont = font.isBold();
882 this.antialiasedText =
true;
884 this.antialiasedText =
false;
891 if (antialiasedText) {
892 Graphics g = frame.getGraphics();
893 Java2.setAntialiasedText(g,
true);
894 w =
Java2.getStringWidth(s, fontMetrics, g);
897 w = fontMetrics.stringWidth(s);
916 int[] kernel = {-1, -1, -1,
946 int[] col1 =
new int[roiHeight];
947 int[] col2 =
new int[roiHeight];
948 for (
int x=0; x<roiWidth/2; x++) {
949 getColumn(roiX+x, roiY, col1, roiHeight);
950 getColumn(roiX+roiWidth-x-1, roiY, col2, roiHeight);
951 putColumn(roiX+x, roiY, col2, roiHeight);
952 putColumn(roiX+roiWidth-x-1, roiY, col1, roiHeight);
963 int[] arow =
new int[width];
964 for (
int row=0; row<height; row++) {
965 getRow(0, row, arow, width);
966 ip2.
putColumn(width2-row-1, 0, arow, height2);
977 int[] arow =
new int[width];
978 int[] arow2 =
new int[width];
979 for (
int row=0; row<height; row++) {
980 getRow(0, row, arow, width);
981 for (
int i=0; i<width; i++) {
982 arow2[i] = arow[width-i-1];
996 return (
"width="+width+
", height="+height+
", min="+
getMin()+
", max="+
getMax()+
", v="+
getPixel(0,0));
1015 this.cTable = cTable;
1020 histogramSize = size;
1026 return histogramSize;
1032 if (histMin>histMax) {
1036 histogramMin = histMin;
1037 histogramMax = histMax;
1042 return histogramMin;
1047 return histogramMax;
1064 public abstract int getPixel(
int x,
int y);
1071 if (iArray==null) iArray =
new int[1];
1094 public abstract void putPixel(
int x,
int y,
int value);
1103 public abstract void putPixelValue(
int x,
int y,
double value);
1106 public abstract void drawPixel(
int x,
int y);
1110 public abstract void setPixels(Object pixels);
1126 public void add(
int value) {process(ADD, value);}
1129 public void add(
double value) {process(ADD, value);}
1132 public void multiply(
double value) {process(MULT, value);}
1135 public void and(
int value) {process(AND, value);}
1138 public void or(
int value) {process(OR, value);}
1141 public void xor(
int value) {process(XOR, value);}
1144 public void gamma(
double value) {process(GAMMA, value);}
1147 public void log() {process(LOG, 0.0);}
1150 public void sqr() {process(SQR, 0.0);}
1153 public void sqrt() {process(SQRT, 0.0);}
1156 public void min(
double value) {process(MINIMUM, value);}
1159 public void max(
double value) {process(MAXIMUM, value);}
1171 public abstract void reset();
1182 public abstract void filter(
int type);
1190 public abstract void noise(
double range);
1198 public abstract void threshold(
int level);
1202 Rectangle saveRoi =
getRoi();
1216 public abstract void scale(
double xScale,
double yScale);
1226 public abstract void rotate(
double angle);
1234 public abstract void erode();
1237 public abstract void dilate();
1243 this.lutAnimation = lutAnimation;
1247 void resetPixels(Object pixels) {
1286 public abstract void convolve(
float[] kernel,
int kernelWidth,
int kernelHeight);
1311 int maxValue = histogram.length - 1;
1312 double result, sum1, sum2, sum3, sum4;
1315 histogram[maxValue] = 0;
1317 while ((histogram[min]==0) && (min<maxValue))
1320 while ((histogram[max]==0) && (max>0))
1323 level = histogram.length/2;
1327 int movingIndex =
min;
1328 int inc = Math.min(max/40, 1);
1330 sum1=sum2=sum3=sum4=0.0;
1331 for (
int i=min; i<=movingIndex; i++) {
1332 sum1 += i*histogram[i];
1333 sum2 += histogram[i];
1335 for (
int i=(movingIndex+1); i<=
max; i++) {
1336 sum3 += i*histogram[i];
1337 sum4 += histogram[i];
1339 result = (sum1/sum2 + sum3/sum4)/2.0;
1341 if (max>255 && (movingIndex%inc)==0)
1342 showProgress((
double)(movingIndex)/max);
1343 }
while ((movingIndex+1)<=result && movingIndex<max-1);
1346 level = (int)Math.round(result);
1353 if (clipRect==null) {
1359 clipXMin = clipRect.x;
1360 clipXMax = clipRect.x + clipRect.width - 1;
1361 clipYMin = clipRect.y;
1362 clipYMax = clipRect.y + clipRect.height - 1;
1363 if (clipXMin<0) clipXMin = 0;
1364 if (clipXMax>=width) clipXMax = width-1;
1365 if (clipYMin<0) clipYMin = 0;
1366 if (clipYMax>=height) clipYMax = height-1;
1372 roiWidth+
"x"+roiHeight+
")";