Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
ImageProcessor.java
1 package ij.process;
2 
3 import java.util.*;
4 import java.awt.*;
5 import java.awt.image.*;
6 import java.lang.reflect.*;
7 import ij.gui.*;
8 import ij.util.Java2;
9 
18 public abstract class ImageProcessor extends Object {
19 
21  public static final int BLACK = 0xFF000000;
22 
24  public static final double NO_THRESHOLD = -808080.0;
25 
27  public static final int LEFT_JUSTIFY = 0;
29  public static final int CENTER_JUSTIFY = 1;
31  public static final int RIGHT_JUSTIFY = 2;
32 
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";
38 
39  int fgColor = 0;
40  protected int lineWidth = 1;
41  protected int cx, cy; //current drawing coordinates
42  protected Font font;
43  protected FontMetrics fontMetrics;
44  protected boolean antialiasedText;
45  protected boolean boldFont;
46  static Frame frame;
47 
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; // true if pixels = snapshotPixels
55  ImageProcessor mask = null;
56  protected ColorModel baseCM; // base color model
57  protected ColorModel cm;
58  protected byte[] rLUT1, gLUT1, bLUT1; // base LUT
59  protected byte[] rLUT2, gLUT2, bLUT2; // LUT as modified by setMinAndMax and setThreshold
60  protected boolean interpolate;
61  protected double minThreshold=NO_THRESHOLD, maxThreshold=NO_THRESHOLD;
62  protected int histogramSize = 256;
63  protected double histogramMin, histogramMax;
64  protected float[] cTable;
65  protected boolean lutAnimation;
66  protected MemoryImageSource source;
67  protected Image img;
68  protected boolean newPixels;
69  protected Color drawingColor = Color.black;
70  protected int clipXMin, clipXMax, clipYMin, clipYMax; // clip rect used by drawTo, drawLine, drawDot and drawPixel
71  protected int justification = LEFT_JUSTIFY;
72 
73 
74  protected void showProgress(double percentDone) {
75  if (progressBar!=null)
76  progressBar.show(percentDone);
77  }
78 
79  protected void hideProgress() {
80  showProgress(1.0);
81  newSnapshot = false;
82  }
83 
85  public int getWidth() {
86  return width;
87  }
88 
90  public int getHeight() {
91  return height;
92  }
93 
97  public ColorModel getColorModel() {
98  if (cm==null)
99  makeDefaultColorModel();
100  if (baseCM!=null)
101  return baseCM;
102  else
103  return cm;
104  }
105 
108  public void setColorModel(ColorModel cm) {
109  if (!(this instanceof ColorProcessor) && !(cm instanceof IndexColorModel))
110  throw new IllegalArgumentException("Must be IndexColorModel");
111  this.cm = cm;
112  baseCM = null;
113  rLUT1 = rLUT2 = null;
114  newPixels = true;
115  inversionTested = false;
116  minThreshold = NO_THRESHOLD;
117  }
118 
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++) {
124  rLUT[i]=(byte)i;
125  gLUT[i]=(byte)i;
126  bLUT[i]=(byte)i;
127  }
128  cm = new IndexColorModel(8, 256, rLUT, gLUT, bLUT);
129  }
130 
133  public void invertLut() {
134  if (cm==null)
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];
144  icm.getReds(reds);
145  icm.getGreens(greens);
146  icm.getBlues(blues);
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);
151  }
152  ColorModel cm = new IndexColorModel(8, mapSize, reds2, greens2, blues2);
153  setColorModel(cm);
154  }
155 
157  public int getBestIndex(Color c) {
158  if (cm==null)
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];
165  icm.getReds(rLUT);
166  icm.getGreens(gLUT);
167  icm.getBlues(bLUT);
168  int minDistance = Integer.MAX_VALUE;
169  int distance;
170  int minIndex = 0;
171  int r1=c.getRed();
172  int g1=c.getGreen();
173  int b1=c.getBlue();
174  int r2,b2,g2;
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);
178  //ij.IJ.write(i+" "+minIndex+" "+distance+" "+(rLUT[i]&255));
179  if (distance<minDistance) {
180  minDistance = distance;
181  minIndex = i;
182  }
183  if (minDistance==0.0)
184  break;
185  }
186  return minIndex;
187  }
188 
189  protected boolean inversionTested = false;
190  protected boolean invertedLut;
191 
193  public boolean isInvertedLut() {
194  if (inversionTested)
195  return invertedLut;
196  inversionTested = true;
197  if (cm==null || !(cm instanceof IndexColorModel))
198  return (invertedLut=false);
199  IndexColorModel icm = (IndexColorModel)cm;
200  invertedLut = true;
201  int v1, v2;
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);
205  if (v1<v2) {
206  invertedLut = false;
207  break;
208  }
209  }
210  return invertedLut;
211  }
212 
214  public boolean isColorLut() {
215  if (cm==null || !(cm instanceof IndexColorModel))
216  return false;
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];
222  icm.getReds(reds);
223  icm.getGreens(greens);
224  icm.getBlues(blues);
225  boolean isColor = false;
226  for (int i=0; i<mapSize; i++) {
227  if ((reds[i] != greens[i]) || (greens[i] != blues[i])) {
228  isColor = true;
229  break;
230  }
231  }
232  return isColor;
233  }
234 
235 
238  public boolean isPseudoColorLut() {
239  if (cm==null || !(cm instanceof IndexColorModel))
240  return false;
242  return true;
243  IndexColorModel icm = (IndexColorModel)cm;
244  int mapSize = icm.getMapSize();
245  if (mapSize!=256)
246  return false;
247  byte[] reds = new byte[mapSize];
248  byte[] greens = new byte[mapSize];
249  byte[] blues = new byte[mapSize];
250  icm.getReds(reds);
251  icm.getGreens(greens);
252  icm.getBlues(blues);
253  int r, g, b, d;
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;
261  r2=r; g2=g; b2=b;
262  }
263  double stdDev = (768*sum2-sum*sum)/768.0;
264  if (stdDev>0.0)
265  stdDev = Math.sqrt(stdDev/(767.0));
266  else
267  stdDev = 0.0;
268  //ij.IJ.log("isPseudoColorLut: "+(stdDev<10.0) + " " + stdDev);
269  return stdDev<20.0;
270  }
271 
274  public abstract void setColor(Color color);
275 
277  public void setColor(int value) {
278  fgColor = value;
279  }
280 
282  public abstract void setValue(double value);
283 
285  public abstract double getMin();
286 
288  public abstract double getMax();
289 
295  public abstract void setMinAndMax(double min, double max);
296 
300  public void resetMinAndMax() {}
301 
305  public void setThreshold(double minThreshold, double maxThreshold, int lutUpdate) {
306  //ij.IJ.write("setThreshold: "+" "+minThreshold+" "+maxThreshold+" "+lutUpdate);
307  if (this instanceof ColorProcessor)
308  return;
309  this.minThreshold = minThreshold;
310  this.maxThreshold = maxThreshold;
311 
312  if (minThreshold==NO_THRESHOLD) {
313  resetThreshold();
314  return;
315  }
316 
317  if (lutUpdate==NO_LUT_UPDATE)
318  return;
319  if (rLUT1==null) {
320  if (cm==null)
321  makeDefaultColorModel();
322  baseCM = cm;
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];
327  }
328  int t1 = (int)minThreshold;
329  int t2 = (int)maxThreshold;
330  int index;
331  if (lutUpdate==RED_LUT)
332  for (int i=0; i<256; i++) {
333  if (i>=t1 && i<=t2) {
334  rLUT2[i] = (byte)255;
335  gLUT2[i] = (byte)0;
336  bLUT2[i] = (byte)0;
337  } else {
338  rLUT2[i] = rLUT1[i];
339  gLUT2[i] = gLUT1[i];
340  bLUT2[i] = bLUT1[i];
341  }
342  }
343  else if (lutUpdate==BLACK_AND_WHITE_LUT)
344  for (int i=0; i<256; i++) {
345  if (i>=t1 && i<=t2) {
346  rLUT2[i] = (byte)0;
347  gLUT2[i] = (byte)0;
348  bLUT2[i] = (byte)0;
349  } else {
350  rLUT2[i] = (byte)255;
351  gLUT2[i] = (byte)255;
352  bLUT2[i] = (byte)255;
353  }
354  }
355  else
356  for (int i=0; i<256; i++) {
357  if (i>=t1 && i<=t2) {
358  rLUT2[i] = rLUT1[i];
359  gLUT2[i] = gLUT1[i];
360  bLUT2[i] = bLUT1[i];
361 
362  } else if (i>t2) {
363  rLUT2[i] = (byte)0;
364  gLUT2[i] = (byte)255;
365  bLUT2[i] = (byte)0;
366  } else {
367  rLUT2[i] = (byte)0;
368  gLUT2[i] = (byte)0;
369  bLUT2[i] = (byte)255;
370  }
371  }
372 
373  cm = new IndexColorModel(8, 256, rLUT2, gLUT2, bLUT2);
374  newPixels = true;
375  }
376 
378  public void resetThreshold() {
379  minThreshold = NO_THRESHOLD;
380  if (baseCM!=null) {
381  cm = baseCM;
382  baseCM = null;
383  }
384  rLUT1 = rLUT2 = null;
385  inversionTested = false;
386  newPixels = true;
387  }
388 
391  public double getMinThreshold() {
392  return minThreshold;
393  }
394 
396  public double getMaxThreshold() {
397  return maxThreshold;
398  }
399 
404  public void setRoi(Rectangle roi) {
405  if (roi==null)
406  resetRoi();
407  else
408  setRoi(roi.x, roi.y, roi.width, roi.height);
409  }
410 
415  public void setRoi(int x, int y, int rwidth, int rheight) {
416  if (x<0 || y<0 || x+rwidth>width || y+rheight>height) {
417  //find intersection of roi and this image
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;
423  mask=null;
424  return;
425  }
426  if (mask!=null && mask.getWidth()==rwidth && mask.getHeight()==rheight) {
427  Rectangle r3 = new Rectangle(0, 0, r2.width, r2.height);
428  if (x<0) r3.x = -x;
429  if (y<0) r3.y = -y;
430  mask.setRoi(r3);
431  mask = mask.crop();
432  }
433  roiX=r2.x; roiY=r2.y; roiWidth=r2.width; roiHeight=r2.height;
434  } else {
435  roiX=x; roiY=y; roiWidth=rwidth; roiHeight=rheight;
436  }
437  if (mask!=null && (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight))
438  mask = null;
439  //setup limits for 3x3 filters
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);
444  }
445 
459  public void setRoi(ij.gui.Roi roi) {
460  if (roi==null)
461  resetRoi();
462  else {
463  setMask(roi.getMask());
464  setRoi(roi.getBounds());
465  }
466  }
467 
485  public void setRoi(Polygon roi) {
486  if (roi==null)
487  {resetRoi(); return;}
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;
492  }
493  PolygonFiller pf = new PolygonFiller();
494  pf.setPolygon(roi.xpoints, roi.ypoints, roi.npoints);
495  ImageProcessor mask = pf.getMask(bounds.width, bounds.height);
496  setMask(mask);
497  setRoi(bounds);
498  for (int i=0; i<roi.npoints; i++) {
499  roi.xpoints[i] += bounds.x;
500  roi.ypoints[i] += bounds.y;
501  }
502  }
503 
505  public void resetRoi() {
506  roiX=0; roiY=0; roiWidth=width; roiHeight=height;
507  xMin=1; xMax=width-2; yMin=1; yMax=height-2;
508  mask=null;
509  clipXMin=0; clipXMax=width-1; clipYMin=0; clipYMax=height-1;
510  }
511 
514  public Rectangle getRoi() {
515  return new Rectangle(roiX, roiY, roiWidth, roiHeight);
516  }
517 
521  public void setMask(ImageProcessor mask) {
522  this.mask = mask;
523  }
524 
528  return mask;
529  }
530 
532  public byte[] getMaskArray() {
533  return mask!=null?(byte[])mask.getPixels():null;
534  }
535 
538  public void setProgressBar(ProgressBar pb) {
539  progressBar = pb;
540  }
541 
544  public void setInterpolate(boolean interpolate) {
545  this.interpolate = interpolate;
546  }
547 
549  public boolean getInterpolate() {
550  return interpolate;
551  }
552 
554  public boolean isKillable() {
555  return false;
556  }
557 
558  private void process(int op, double value) {
559  double SCALE = 255.0/Math.log(255.0);
560  int v;
561 
562  int[] lut = new int[256];
563  for (int i=0; i<256; i++) {
564  switch(op) {
565  case INVERT:
566  v = 255 - i;
567  break;
568  case FILL:
569  v = fgColor;
570  break;
571  case ADD:
572  v = i + (int)value;
573  break;
574  case MULT:
575  v = (int)Math.round(i * value);
576  break;
577  case AND:
578  v = i & (int)value;
579  break;
580  case OR:
581  v = i | (int)value;
582  break;
583  case XOR:
584  v = i ^ (int)value;
585  break;
586  case GAMMA:
587  v = (int)(Math.exp(Math.log(i/255.0)*value)*255.0);
588  break;
589  case LOG:
590  if (i==0)
591  v = 0;
592  else
593  v = (int)(Math.log(i) * SCALE);
594  break;
595  case SQR:
596  v = i*i;
597  break;
598  case SQRT:
599  v = (int)Math.sqrt(i);
600  break;
601  case MINIMUM:
602  if (i<value)
603  v = (int)value;
604  else
605  v = i;
606  break;
607  case MAXIMUM:
608  if (i>value)
609  v = (int)value;
610  else
611  v = i;
612  break;
613  default:
614  v = i;
615  }
616  if (v < 0)
617  v = 0;
618  if (v > 255)
619  v = 255;
620  lut[i] = v;
621  }
622  applyTable(lut);
623  }
624 
632  public double[] getLine(double x1, double y1, double x2, double y2) {
633  double dx = x2-x1;
634  double dy = y2-y1;
635  int n = (int)Math.round(Math.sqrt(dx*dx + dy*dy));
636  double xinc = dx/n;
637  double yinc = dy/n;
638  n++;
639  double[] data = new double[n];
640  double rx = x1;
641  double ry = y1;
642  if (interpolate)
643  for (int i=0; i<n; i++) {
644  if (cTable!=null)
645  data[i] = getInterpolatedValue(rx, ry);
646  else
647  data[i] = getInterpolatedPixel(rx, ry);
648  rx += xinc;
649  ry += yinc;
650  }
651  else
652  for (int i=0; i<n; i++) {
653  data[i] = getPixelValue((int)(rx+0.5), (int)(ry+0.5));
654  rx += xinc;
655  ry += yinc;
656  }
657  return data;
658  }
659 
661  public void getRow(int x, int y, int[] data, int length) {
662  for (int i=0; i<length; i++)
663  data[i] = getPixel(x++, y);
664  }
665 
667  public void getColumn(int x, int y, int[] data, int length) {
668  for (int i=0; i<length; i++)
669  data[i] = getPixel(x, y++);
670  }
671 
674  public void putRow(int x, int y, int[] data, int length) {
675  for (int i=0; i<length; i++)
676  putPixel(x++, y, data[i]);
677  }
678 
681  public void putColumn(int x, int y, int[] data, int length) {
682  //if (x>=0 && x<width && y>=0 && (y+length)<=height)
683  // ((ShortProcessor)this).putColumn2(x, y, data, length);
684  //else
685  for (int i=0; i<length; i++)
686  putPixel(x, y++, data[i]);
687  }
688 
694  public void moveTo(int x, int y) {
695  cx = x;
696  cy = y;
697  }
698 
700  public void setLineWidth(int width) {
701  lineWidth = width;
702  if (lineWidth<1) lineWidth = 1;
703  }
704 
706  public void lineTo(int x2, int y2) {
707  int dx = x2-cx;
708  int dy = y2-cy;
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;
714  double x = cx+0.5;
715  double y = cy+0.5;
716  n++;
717  do {
718  if (lineWidth==1)
719  drawPixel((int)x, (int)y);
720  else if (lineWidth==2)
721  drawDot2((int)x, (int)y);
722  else
723  drawDot((int)x, (int)y);
724  x += xinc;
725  y += yinc;
726  } while (--n>0);
727  cx = x2; cy = y2;
728  }
729 
731  public void drawLine(int x1, int y1, int x2, int y2) {
732  moveTo(x1, y1);
733  lineTo(x2, y2);
734  }
735 
737  public void drawRect(int x, int y, int width, int height) {
738  if (width<1 || height<1)
739  return;
740  moveTo(x, y);
741  lineTo(x+width-1, y);
742  lineTo(x+width-1, y+height-1);
743  lineTo(x, y+height-1);
744  lineTo(x, y);
745  }
746 
748  public void drawPolygon(Polygon p) {
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]);
753  }
754 
756  public void fillPolygon(Polygon p) {
757  setRoi(p);
758  fill(getMask());
759  resetRoi();
760  }
761 
763  public void drawDot2(int x, int y) {
764  drawPixel(x, y);
765  drawPixel(x-1, y);
766  drawPixel(x, y-1);
767  drawPixel(x-1, y-1);
768  }
769 
771  public void drawDot(int xcenter, int ycenter) {
772  int r = lineWidth/2;
773  int r2 = r*r+1;
774  for (int x=-r; x<=r; x++)
775  for (int y=-r; y<=r; y++)
776  if ((x*x+y*y)<=r2)
777  drawPixel(xcenter+x, ycenter+y);
778  }
779 
780  private void setupFrame() {
781  if (frame==null) {
782  frame = new Frame();
783  frame.pack();
784  frame.setBackground(Color.white);
785  }
786  if (font==null)
787  font = new Font("SansSerif", Font.PLAIN, 12);
788  if (fontMetrics==null) {
789  frame.setFont(font);
790  fontMetrics = frame.getFontMetrics(font);
791  }
792  }
793 
795  public void drawString(String s) {
796  if (s.equals(""))
797  return;
798  setupFrame();
799  if (ij.IJ.isMacOSX())
800  s += " ";
801  int w = getStringWidth(s);
802  int cxx = cx;
803  if (justification==CENTER_JUSTIFY)
804  cxx -= w/2;
805  else if (justification==RIGHT_JUSTIFY)
806  cxx -= w;
807  //if (antialiasedText)
808  // w = boldFont?(int)(1.15*w):(int)(1.08*w);
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();
815  g.setFont(font);
816 
817  if (antialiasedText) {
818  Java2.setAntialiasedText(g, true);
819  setRoi(cxx,cy-h,w,h);
820  ImageProcessor ip = crop();
821  resetRoi();
822  g.drawImage(ip.createImage(), 0, 0, null);
823  g.setColor(drawingColor);
824  g.drawString(s, 0, h-descent);
825  g.dispose();
826  ip = new ColorProcessor(img);
827  if (this instanceof ByteProcessor) {
828  ip = ip.convertToByte(false);
829  if (isInvertedLut()) ip.invert();
830  }
831  //new ij.ImagePlus("ip",ip).show();
832  insert(ip, cxx, cy-h);
833  cy += h;
834  return;
835  }
836 
837  if (ij.IJ.isMacOSX()) {
838  Java2.setAntialiasedText(g, false);
839  g.setColor(Color.white);
840  g.fillRect(0, 0, w, h);
841  }
842  g.setColor(Color.black);
843  g.drawString(s, 0, h-descent);
844  g.dispose();
845  ImageProcessor ip = new ColorProcessor(img);
846  ImageProcessor textMask = ip.convertToByte(false);
847  byte[] mpixels = (byte[])textMask.getPixels();
848  //new ij.ImagePlus("textmask",textMask).show();
849  textMask.invert();
850  if (cxx<width && cy-h<height) {
851  setMask(textMask);
852  setRoi(cxx,cy-h,w,h);
853  fill(getMask());
854  }
855  resetRoi();
856  cy += h;
857  }
858 
860  public void drawString(String s, int x, int y) {
861  moveTo(x, y);
862  drawString(s);
863  }
864 
867  public void setJustification(int justification) {
868  this.justification = justification;
869  }
870 
872  public void setFont(Font font) {
873  this.font = font;
874  fontMetrics = null;
875  boldFont = font.isBold();
876  }
877 
880  public void setAntialiasedText(boolean antialiasedText) {
881  if (antialiasedText && ij.IJ.isJava2() && ((this instanceof ByteProcessor) || (this instanceof ColorProcessor)))
882  this.antialiasedText = true;
883  else
884  this.antialiasedText = false;
885  }
886 
888  public int getStringWidth(String s) {
889  setupFrame();
890  int w;
891  if (antialiasedText) {
892  Graphics g = frame.getGraphics();
893  Java2.setAntialiasedText(g, true);
894  w = Java2.getStringWidth(s, fontMetrics, g);
895  g.dispose();
896  } else
897  w = fontMetrics.stringWidth(s);
898  return w;
899  }
900 
902  public FontMetrics getFontMetrics() {
903  setupFrame();
904  return fontMetrics;
905  }
906 
908  public void smooth() {
909  if (width>1)
910  filter(BLUR_MORE);
911  }
912 
914  public void sharpen() {
915  if (width>1) {
916  int[] kernel = {-1, -1, -1,
917  -1, 12, -1,
918  -1, -1, -1};
919  convolve3x3(kernel);
920  }
921  }
922 
924  public void findEdges() {
925  if (width>1)
926  filter(FIND_EDGES);
927  }
928 
930  public abstract void flipVertical();
931  /* {
932  int[] row1 = new int[roiWidth];
933  int[] row2 = new int[roiWidth];
934  for (int y=0; y<roiHeight/2; y++) {
935  getRow(roiX, roiY+y, row1, roiWidth);
936  getRow(roiX, roiY+roiHeight-y-1, row2, roiWidth);
937  putRow(roiX, roiY+y, row2, roiWidth);
938  putRow(roiX, roiY+roiHeight-y-1, row1, roiWidth);
939  }
940  newSnapshot = false;
941  }
942  */
943 
945  public void flipHorizontal() {
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);
953  }
954  newSnapshot = false;
955  }
956 
960  int width2 = height;
961  int height2 = width;
962  ImageProcessor ip2 = createProcessor(width2, height2);
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);
967  }
968  return ip2;
969  }
970 
974  int width2 = height;
975  int height2 = width;
976  ImageProcessor ip2 = createProcessor(width2, 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];
983  }
984  ip2.putColumn(row, 0, arow2, height2);
985  }
986  return ip2;
987  }
988 
990  public void insert(ImageProcessor ip, int xloc, int yloc) {
991  copyBits(ip, xloc, yloc, Blitter.COPY);
992  }
993 
995  public String toString() {
996  return ("width="+width+", height="+height+", min="+getMin()+", max="+getMax()+", v="+getPixel(0,0));
997  }
998 
1000  public void fill() {
1001  process(FILL, 0.0);
1002  }
1003 
1008  public abstract void fill(ImageProcessor mask);
1009 
1014  public void setCalibrationTable(float[] cTable) {
1015  this.cTable = cTable;
1016  }
1017 
1019  public void setHistogramSize(int size) {
1020  histogramSize = size;
1021  }
1022 
1025  public int getHistogramSize() {
1026  return histogramSize;
1027  }
1028 
1031  public void setHistogramRange(double histMin, double histMax) {
1032  if (histMin>histMax) {
1033  histMin = 0.0;
1034  histMax = 0.0;
1035  }
1036  histogramMin = histMin;
1037  histogramMax = histMax;
1038  }
1039 
1041  public double getHistogramMin() {
1042  return histogramMin;
1043  }
1044 
1046  public double getHistogramMax() {
1047  return histogramMax;
1048  }
1049 
1053  public abstract Object getPixels();
1054 
1058  public abstract Object getPixelsCopy();
1059 
1064  public abstract int getPixel(int x, int y);
1065 
1070  public int[] getPixel(int x, int y, int[] iArray) {
1071  if (iArray==null) iArray = new int[1];
1072  iArray[0] = getPixel(x, y);
1073  return iArray;
1074  }
1075 
1078  public void putPixel(int x, int y, int[] iArray) {
1079  putPixel(x, y, iArray[0]);
1080  }
1081 
1083  public abstract double getInterpolatedPixel(double x, double y);
1084 
1086  public double getInterpolatedValue(double x, double y) {
1087  return getInterpolatedPixel(x, y);
1088  }
1089 
1094  public abstract void putPixel(int x, int y, int value);
1095 
1100  public abstract float getPixelValue(int x, int y);
1101 
1103  public abstract void putPixelValue(int x, int y, double value);
1104 
1106  public abstract void drawPixel(int x, int y);
1107 
1110  public abstract void setPixels(Object pixels);
1111 
1114  public abstract void copyBits(ImageProcessor ip, int xloc, int yloc, int mode);
1115 
1120  public abstract void applyTable(int[] lut);
1121 
1123  public void invert() {process(INVERT, 0.0);}
1124 
1126  public void add(int value) {process(ADD, value);}
1127 
1129  public void add(double value) {process(ADD, value);}
1130 
1132  public void multiply(double value) {process(MULT, value);}
1133 
1135  public void and(int value) {process(AND, value);}
1136 
1138  public void or(int value) {process(OR, value);}
1139 
1141  public void xor(int value) {process(XOR, value);}
1142 
1144  public void gamma(double value) {process(GAMMA, value);}
1145 
1147  public void log() {process(LOG, 0.0);}
1148 
1150  public void sqr() {process(SQR, 0.0);}
1151 
1153  public void sqrt() {process(SQRT, 0.0);}
1154 
1156  public void min(double value) {process(MINIMUM, value);}
1157 
1159  public void max(double value) {process(MAXIMUM, value);}
1160 
1162  public abstract Image createImage();
1163 
1165  public abstract ImageProcessor createProcessor(int width, int height);
1166 
1168  public abstract void snapshot();
1169 
1171  public abstract void reset();
1172 
1174  public abstract void reset(ImageProcessor mask);
1175 
1178  public abstract void convolve3x3(int[] kernel);
1179 
1182  public abstract void filter(int type);
1183 
1185  public abstract void medianFilter();
1186 
1190  public abstract void noise(double range);
1191 
1194  public abstract ImageProcessor crop();
1195 
1198  public abstract void threshold(int level);
1199 
1202  Rectangle saveRoi = getRoi();
1203  ImageProcessor saveMask= getMask();
1204  resetRoi();
1205  ImageProcessor ip2 = crop();
1206  setRoi(saveRoi);
1207  setMask(saveMask);
1208  return ip2;
1209  }
1210 
1216  public abstract void scale(double xScale, double yScale);
1217 
1221  public abstract ImageProcessor resize(int dstWidth, int dstHeight);
1222 
1226  public abstract void rotate(double angle);
1227 
1231  public abstract int[] getHistogram();
1232 
1234  public abstract void erode();
1235 
1237  public abstract void dilate();
1238 
1242  public void setLutAnimation(boolean lutAnimation) {
1243  this.lutAnimation = lutAnimation;
1244  newPixels = true;
1245  }
1246 
1247  void resetPixels(Object pixels) {
1248  if (pixels==null) {
1249  if (img!=null) {
1250  img.flush();
1251  img = null;
1252  }
1253  source = null;
1254  }
1255  newPixels = true;
1256  }
1257 
1259  public ImageProcessor convertToByte(boolean doScaling) {
1260  TypeConverter tc = new TypeConverter(this, doScaling);
1261  return tc.convertToByte();
1262  }
1263 
1265  public ImageProcessor convertToShort(boolean doScaling) {
1266  TypeConverter tc = new TypeConverter(this, doScaling);
1267  return tc.convertToShort();
1268  }
1269 
1274  TypeConverter tc = new TypeConverter(this, false);
1275  return tc.convertToFloat(cTable);
1276  }
1277 
1280  TypeConverter tc = new TypeConverter(this, true);
1281  return tc.convertToRGB();
1282  }
1283 
1286  public abstract void convolve(float[] kernel, int kernelWidth, int kernelHeight);
1287 
1293  public void autoThreshold() {
1295  }
1296 
1304  public int getAutoThreshold() {
1305  return getAutoThreshold(getHistogram());
1306  }
1307 
1309  public int getAutoThreshold(int[] histogram) {
1310  int level;
1311  int maxValue = histogram.length - 1;
1312  double result, sum1, sum2, sum3, sum4;
1313 
1314  histogram[0] = 0; //set to zero so erased areas aren't included
1315  histogram[maxValue] = 0;
1316  int min = 0;
1317  while ((histogram[min]==0) && (min<maxValue))
1318  min++;
1319  int max = maxValue;
1320  while ((histogram[max]==0) && (max>0))
1321  max--;
1322  if (min>=max) {
1323  level = histogram.length/2;
1324  return level;
1325  }
1326 
1327  int movingIndex = min;
1328  int inc = Math.min(max/40, 1);
1329  do {
1330  sum1=sum2=sum3=sum4=0.0;
1331  for (int i=min; i<=movingIndex; i++) {
1332  sum1 += i*histogram[i];
1333  sum2 += histogram[i];
1334  }
1335  for (int i=(movingIndex+1); i<=max; i++) {
1336  sum3 += i*histogram[i];
1337  sum4 += histogram[i];
1338  }
1339  result = (sum1/sum2 + sum3/sum4)/2.0;
1340  movingIndex++;
1341  if (max>255 && (movingIndex%inc)==0)
1342  showProgress((double)(movingIndex)/max);
1343  } while ((movingIndex+1)<=result && movingIndex<max-1);
1344 
1345  showProgress(1.0);
1346  level = (int)Math.round(result);
1347  return level;
1348  }
1349 
1352  public void setClipRect(Rectangle clipRect) {
1353  if (clipRect==null) {
1354  clipXMin=0;
1355  clipXMax=width-1;
1356  clipYMin=0;
1357  clipYMax=height-1;
1358  } else {
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;
1367  }
1368  }
1369 
1370  protected String maskSizeError(ImageProcessor mask) {
1371  return "Mask size ("+mask.getWidth()+"x"+mask.getHeight()+") != ROI size ("+
1372  roiWidth+"x"+roiHeight+")";
1373  }
1374 
1375 }