Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
ImagePlus.java
1 package ij;
2 
3 import java.awt.*;
4 import java.awt.image.*;
5 import java.net.URL;
6 import java.util.*;
7 import ij.process.*;
8 import ij.io.*;
9 import ij.gui.*;
10 import ij.measure.*;
11 import ij.plugin.filter.Analyzer;
12 import ij.util.Tools;
13 
21 public class ImagePlus implements ImageObserver, Measurements {
22 
24  public static final int GRAY8 = 0;
25 
27  public static final int GRAY16 = 1;
28 
30  public static final int GRAY32 = 2;
31 
33  public static final int COLOR_256 = 3;
34 
36  public static final int COLOR_RGB = 4;
37 
39  public boolean changes;
40 
42  public double pixelWidth = 1.0;
43 
45  public double pixelHeight = 1.0;
46 
48  public double pixelDepth = 1.0;
49 
51  public String unit = "pixel";
52 
54  public String units = "pixels";
55 
57  public boolean sCalibrated;
58 
59  protected Image img;
60  protected ImageProcessor ip;
61  private ImageJ ij = IJ.getInstance();
62  private String title;
63  private String url;
64  private FileInfo fileInfo;
65  protected int width;
66  protected int height;
67  private int imageType = GRAY8;
68  private int currentSlice;
69  private Roi roi;
70  protected boolean locked = false;
71  private static int currentID = -1;
72  private int ID;
73  private static Component comp;
74  private boolean imageLoaded;
75  private int imageUpdateY, imageUpdateW;
76  private Properties properties;
77  private long startTime;
78  private Calibration calibration;
79  private static Calibration globalCalibration;
80  private boolean activated;
81  private boolean ignoreFlush;
82  private boolean errorLoadingImage;
83  protected ImageCanvas imageCanvas;
84 
86  public ImagePlus() {
87  ID = --currentID;
88  title="null";
89  }
90 
95  public ImagePlus(String title, Image img) {
96  this.title = title;
97  ID = --currentID;
98  if (img!=null)
99  setImage(img);
100  }
101 
103  public ImagePlus(String title, ImageProcessor ip) {
104  setProcessor(title, ip);
105  ID = --currentID;
106  }
107 
111  public ImagePlus(String pathOrURL) {
112  Opener opener = new Opener();
113  ImagePlus imp = null;
114  boolean isURL = pathOrURL.indexOf("://")>0;
115  if (isURL)
116  imp = opener.openURL(pathOrURL);
117  else
118  imp = opener.openImage(pathOrURL);
119  if (imp!=null) {
120  setProcessor(imp.getTitle(), imp.getProcessor());
122  properties = imp.getProperties();
123  if (isURL)
124  this.url = pathOrURL;
125  ID = --currentID;
126  }
127  }
128 
129 
134  public synchronized boolean lock() {
135  if (locked) {
136  IJ.beep();
137  IJ.showStatus("\"" + title + "\" is locked");
138  if (IJ.macroRunning()) {
139  IJ.error("Image is locked");
140  }
141  return false;
142  } else {
143  locked = true;
144  if (IJ.debugMode) IJ.log(title + ": lock");
145  return true;
146  }
147  }
148 
151  public synchronized boolean lockSilently() {
152  if (locked)
153  return false;
154  else {
155  locked = true;
156  if (IJ.debugMode) IJ.log(title + ": lock silently");
157  return true;
158  }
159  }
160 
162  public synchronized void unlock() {
163  locked = false;
164  if (IJ.debugMode) IJ.log(title + ": unlock");
165  }
166 
167  private void waitForImage(Image img) {
168  if (comp==null) {
169  comp = IJ.getInstance();
170  if (comp==null)
171  comp = new Canvas();
172  }
173  imageLoaded = false;
174  if (!comp.prepareImage(img, this)) {
175  double progress;
176  while (!imageLoaded && !errorLoadingImage) {
177  //IJ.showStatus(imageUpdateY+" "+imageUpdateW);
178  IJ.wait(30);
179  if (imageUpdateW>1) {
180  progress = (double)imageUpdateY/imageUpdateW;
181  if (!(progress<1.0)) {
182  progress = 1.0 - (progress-1.0);
183  if (progress<0.0) progress = 0.9;
184  }
185  IJ.showProgress(progress);
186  }
187  }
188  IJ.showProgress(1.0);
189  }
190  }
191 
196  public void draw(){
197  ij.getContentPane().repaint();
198  }
199 
201  public void draw(int x, int y, int width, int height){
202  ImageCanvas ic = getCanvas();
203  double mag = ic.getMagnification();
204  x = ic.screenX(x);
205  y = ic.screenY(y);
206  width = (int)(width*mag);
207  height = (int)(height*mag);
208  ic.repaint(x, y, width, height);
209  }
210 
215  public void updateAndDraw() {
216  if (ip != null) {
217  getCanvas().setImageUpdated();
218  draw();
219  }
220  }
221 
225  public void repaintWindow() {
226  draw();
227  }
228 
233  public void updateAndRepaintWindow() {
234  updateAndDraw();
235  }
236 
239  public void updateImage() {
240  if (ip!=null)
241  img = ip.createImage();
242  }
243 
244 
246  public void show() {
247  show("");
248  }
249 
252  public void show(String statusMessage) {
253  ij.setImagePlus(this);
254  }
255 
256 
258  public void setActivated() {
259  activated = true;
260  }
261 
263  public Image getImage() {
264  if (img==null && ip!=null)
265  img = ip.createImage();
266  return img;
267  }
268 
270  public int getID() {
271  return ID;
272  }
273 
277  public void setImage(Image img) {
278  roi = null;
279  errorLoadingImage = false;
280  waitForImage(img);
281  if (errorLoadingImage)
282  throw new IllegalStateException ("Error loading image");
283  this.img = img;
284  int newWidth = img.getWidth(ij);
285  int newHeight = img.getHeight(ij);
286  boolean dimensionsChanged = (newWidth!=width) || (newHeight!=height);
287  width = newWidth;
288  height = newHeight;
289  ip = null;
290  LookUpTable lut = new LookUpTable(img);
291  int type;
292  if (lut.getMapSize() > 0) {
293  if (lut.isGrayscale())
294  type = GRAY8;
295  else
296  type = COLOR_256;
297  } else
298  type = COLOR_RGB;
299  setType(type);
300  setupProcessor();
301  this.img = ip.createImage();
302  }
303 
306  public void setProcessor(String title, ImageProcessor ip) {
307  setProcessor2(title, ip);
308  }
309 
310  void setProcessor2(String title, ImageProcessor ip) {
311  if (title!=null) setTitle(title);
312  this.ip = ip;
313  if (ij!=null) ip.setProgressBar(ij.getProgressBar());
314  img = null;
315  boolean dimensionsChanged = width!=ip.getWidth() || height!=ip.getHeight();
316  if (dimensionsChanged)
317  roi = null;
318  int type;
319  if (ip instanceof ByteProcessor)
320  type = GRAY8;
321  else if (ip instanceof ColorProcessor)
322  type = COLOR_RGB;
323  else if (ip instanceof ShortProcessor)
324  type = GRAY16;
325  else
326  type = GRAY32;
327  if (width==0)
328  imageType = type;
329  else
330  setType(type);
331  width = ip.getWidth();
332  height = ip.getHeight();
333 
334  }
335 
336 
339  public void setFileInfo(FileInfo fi) {
340  if (fi!=null)
341  fi.pixels = null;
342  fileInfo = fi;
343  }
344 
345 
347  public void setColor(Color c) {
348  if (ip!=null)
349  ip.setColor(c);
350  }
351 
352  void setupProcessor() {
353  if (imageType==COLOR_RGB) {
354  if (ip == null || ip instanceof ByteProcessor) {
355  ip = new ColorProcessor(getImage());
356  if (IJ.debugMode) IJ.log(title + ": new ColorProcessor");
357  }
358  }
359  else if (ip==null || (ip instanceof ColorProcessor)) {
360  ip = new ByteProcessor(getImage());
361  if (IJ.debugMode) IJ.log(title + ": new ByteProcessor");
362  }
363  if (roi!=null && roi.isArea())
364  ip.setRoi(roi.getBounds());
365  else
366  ip.resetRoi();
367  }
368 
369  public boolean isProcessor() {
370  return ip!=null;
371  }
372 
376  public ImageProcessor getProcessor() {
377  if (ip==null && img==null)
378  return null;
379  setupProcessor();
380  ip.setLineWidth(Line.getWidth());
381  if (ij!=null) {
382  //setColor(Toolbar.getForegroundColor());
383  ip.setProgressBar(ij.getProgressBar());
384  }
385  return ip;
386  }
387 
390  public synchronized void trimProcessor() {
391  if (ip!=null && !locked) {
392  if (ip!=null && IJ.debugMode) IJ.log(title + ": trimProcessor");
393  ip.setPixels(ip.getPixels()); // sets snapshot buffer to null
394  }
395  }
396 
398  public void killProcessor() {
399  }
400 
403  public ImageProcessor getMask() {
404  if (roi==null) {
405  if (ip!=null) ip.resetRoi();
406  return null;
407  }
408  ImageProcessor mask = roi.getMask();
409  if (mask==null)
410  return null;
411  if (ip!=null) {
412  ip.setMask(mask);
413  ip.setRoi(roi.getBounds());
414  }
415  return mask;
416  }
417 
420  public ImageStatistics getStatistics() {
421  return getStatistics(AREA+MEAN+MODE+MIN_MAX);
422  }
423 
426  public ImageStatistics getStatistics(int mOptions) {
427  return getStatistics(mOptions, 256, 0.0, 0.0);
428  }
429 
435  public ImageStatistics getStatistics(int mOptions, int nBins) {
436  return getStatistics(mOptions, nBins, 0.0, 0.0);
437  }
438 
445  public ImageStatistics getStatistics(int mOptions, int nBins, double histMin, double histMax) {
446  setupProcessor();
447  ip.setMask(getMask());
448  ip.setHistogramSize(nBins);
449  ip.setHistogramRange(histMin, histMax);
450  ImageStatistics stats = ImageStatistics.getStatistics(ip, mOptions, getCalibration());
451  ip.setHistogramSize(256);
452  ip.setHistogramRange(0.0, 0.0);
453  return stats;
454  }
455 
457  public String getTitle() {
458  if (title==null)
459  return "";
460  else
461  return title;
462  }
463 
465  public String getShortTitle() {
466  String title = getTitle();
467  int index = title.indexOf(' ');
468  if (index>-1)
469  title = title.substring(0,index);
470  return title;
471  }
472 
474  public void setTitle(String title) {
475  if (title==null)
476  return;
477  String scale = "";
478  ImageCanvas ic = getCanvas();
479  if (ic != null) {
480  double magnification = ic.getMagnification();
481  if (magnification!=1.0) {
482  double percent = magnification*100.0;
483  if (percent==(int)percent)
484  scale = " (" + IJ.d2s(percent,0) + "%)";
485  else
486  scale = " (" + IJ.d2s(percent,1) + "%)";
487  }
488  }
489  this.title = title;
490  }
491 
492  public int getWidth() {
493  return width;
494  }
495 
496  public int getHeight() {
497  return height;
498  }
499 
501  public int getStackSize() {
502  return 1;
503  }
504 
506  public int getType() {
507  return imageType;
508  }
509 
511  public int getBitDepth() {
512  int bitDepth = 0;
513  switch (imageType) {
514  case GRAY8: case COLOR_256: bitDepth=8; break;
515  case GRAY16: bitDepth=16; break;
516  case GRAY32: bitDepth=32; break;
517  case COLOR_RGB: bitDepth=24; break;
518  }
519  return bitDepth;
520  }
521 
522  protected void setType(int type) {
523  if ((type<0) || (type>COLOR_RGB))
524  return;
525  int previousType = imageType;
526  imageType = type;
527  if (imageType!=previousType) {
528  Menus.updateMenus();
529  if (calibration!=null || globalCalibration!=null)
530  getCalibration().setImage(this);
531  }
532  }
533 
535  public void setProperty(String key, Object value) {
536  if (properties==null)
537  properties = new Properties();
538  properties.put(key, value);
539  }
540 
542  public Object getProperty(String key) {
543  if (properties==null)
544  return null;
545  else
546  return properties.get(key);
547  }
548 
550  public Properties getProperties() {
551  return properties;
552  }
553 
556  if (getImage()!=null)
557  return new LookUpTable(img);
558  else
559  return null;
560  }
561 
563  public boolean isInvertedLut() {
564  if (ip==null) {
565  if (img==null)
566  return false;
567  setupProcessor();
568  }
569  return ip.isInvertedLut();
570  }
571 
572  private int[] pvalue = new int[4];
573 
580  public int[] getPixel(int x, int y) {
581  pvalue[0]=pvalue[1]=pvalue[2]=pvalue[3]=0;
582  if (img == null)
583  return pvalue;
584  switch (imageType) {
585  case GRAY8: case COLOR_256:
586  int index;
587  if (ip!=null)
588  index = ip.getPixel(x, y);
589  else {
590  byte[] pixels8;
591  PixelGrabber pg = new PixelGrabber(img,x,y,1,1,false);
592  try {pg.grabPixels();}
593  catch (InterruptedException e){return pvalue;};
594  pixels8 = (byte[])(pg.getPixels());
595  index = pixels8!=null?pixels8[0]&0xff:0;
596  }
597  if (imageType!=COLOR_256) {
598  pvalue[0] = index;
599  return pvalue;
600  }
601  pvalue[3] = index;
602  // fall through to get rgb values
603  case COLOR_RGB:
604  int[] pixels32 = new int[1];
605  ImageCanvas ic = getCanvas();
606  PixelGrabber pg = new PixelGrabber(img, x, y, 1, 1, pixels32, 0, width);
607  try {pg.grabPixels();}
608  catch (InterruptedException e){return pvalue;};
609  int c = pixels32[0];
610  int r = (c&0xff0000)>>16;
611  int g = (c&0xff00)>>8;
612  int b = c&0xff;
613  pvalue[0] = r;
614  pvalue[1] = g;
615  pvalue[2] = b;
616  break;
617  case GRAY16: case GRAY32:
618  if (ip!=null) pvalue[0] = ip.getPixel(x, y);
619  break;
620  }
621  return pvalue;
622  }
623 
624 
626  void undoFilter() {
627  if (ip!=null) {
628  ip.reset();
629  updateAndDraw();
630  }
631  }
632 
633  public Roi getRoi() {
634  return roi;
635  }
636 
639  public void setRoi(Roi roi) {
640  killRoi();
641  if (roi==null)
642  return;
643  Rectangle bounds = roi.getBounds();
644  if (bounds.width==0 && bounds.height==0)
645  return;
646  this.roi = roi;
647  if (ip!=null) {
648  ip.setMask(null);
649  ip.setRoi(bounds);
650  }
651  this.roi.setImage(this);
652  draw();
653  }
654 
656  public void setRoi(int x, int y, int width, int height) {
657  setRoi(new Rectangle(x, y, width, height));
658  }
659 
661  public void setRoi(Rectangle r) {
662  if (r==null)
663  {killRoi(); return;}
664  killRoi();
665  roi = new Roi(r.x, r.y, r.width, r.height);
666  roi.setImage(this);
667  if (ip!=null) {
668  ip.setMask(null);
669  ip.setRoi(r);
670  }
671  draw();
672  }
673 
676  public void createNewRoi(int x, int y) {
677  killRoi();
678  switch (Toolbar.getToolId()) {
679  case Toolbar.RECTANGLE:
680  roi = new Roi(x, y, this);
681  break;
682  case Toolbar.OVAL:
683  roi = new OvalRoi(x, y, this);
684  break;
685  case Toolbar.POLYGON:
686  case Toolbar.POLYLINE:
687  case Toolbar.ANGLE:
688  roi = new PolygonRoi(x, y, this);
689  break;
690  case Toolbar.FREEROI:
691  case Toolbar.FREELINE:
692  roi = new FreehandRoi(x, y, this);
693  break;
694  case Toolbar.LINE:
695  roi = new Line(x, y, this);
696  break;
697  case Toolbar.TEXT:
698  roi = new TextRoi(x, y, this);
699  break;
700  }
701  }
702 
706  public void killRoi() {
707  if (roi!=null) {
708  saveRoi();
709  roi = null;
710  if (ip!=null)
711  ip.resetRoi();
712  draw();
713  }
714  }
715 
716  void saveRoi() {
717  if (roi!=null) {
718  roi.endPaste();
719  Rectangle r = roi.getBounds();
720  if (r.width>0 && r.height>0) {
721  Roi.previousRoi = (Roi)roi.clone();
722  if (IJ.debugMode) IJ.log("saveRoi: "+roi);
723  }
724  }
725  }
726 
727  public void restoreRoi() {
728  if (Roi.previousRoi!=null) {
729  Roi pRoi = Roi.previousRoi;
730  Rectangle r = pRoi.getBounds();
731  if (r.width<=width || r.height<=height) { // will it fit in this window?
732  roi = (Roi)pRoi.clone();
733  roi.setImage(this);
734  if ((r.x+r.width)>width || (r.y+r.height)>height) // does it need to be moved?
735  roi.setLocation((width-r.width)/2, (height-r.height)/2);
736  draw();
737  }
738  }
739  }
740 
741  void revert() {
742  if (roi!=null)
743  roi.endPaste();
744  trimProcessor();
745  FileInfo fi = getOriginalFileInfo();
746  if (fi!=null && fi.fileFormat!=FileInfo.UNKNOWN)
747  new FileOpener(fi).revertToSaved(this);
748  else if (url!=null) {
749  IJ.showStatus("Loading: " + url);
750  Opener opener = new Opener();
751  try {
752  ImagePlus imp = opener.openURL(url);
753  if (imp!=null)
754  setProcessor(null, imp.getProcessor());
755  } catch (Exception e) {}
756  if (getType()==COLOR_RGB && getTitle().endsWith(".jpg"))
757  Opener.convertGrayJpegTo8Bits(this);
758  }
759  if (getProperty("FHT")!=null) {
760  properties.remove("FHT");
761  if (getTitle().startsWith("FFT of "))
762  setTitle(getTitle().substring(6));
763  }
764  repaintWindow();
765  IJ.showStatus("");
766  }
767 
775  public FileInfo getFileInfo() {
776  FileInfo fi = new FileInfo();
777  fi.width = width;
778  fi.height = height;
779  fi.whiteIsZero = isInvertedLut();
780  fi.intelByteOrder = false;
781  setupProcessor();
782  fi.pixels = ip.getPixels();
783  Calibration cal = getCalibration();
784  if (cal.scaled()) {
785  fi.pixelWidth = cal.pixelWidth;
786  fi.pixelHeight = cal.pixelHeight;
787  fi.unit = cal.getUnit();
788  }
789  fi.frameInterval = cal.frameInterval;
790  if (cal.calibrated()) {
791  fi.calibrationFunction = cal.getFunction();
792  fi.coefficients = cal.getCoefficients();
793  fi.valueUnit = cal.getValueUnit();
794  }
795  switch (imageType) {
796  case GRAY8: case COLOR_256:
797  LookUpTable lut = createLut();
798  if (imageType==COLOR_256 || !lut.isGrayscale())
799  fi.fileType = FileInfo.COLOR8;
800  else
801  fi.fileType = FileInfo.GRAY8;
802  fi.lutSize = lut.getMapSize();
803  fi.reds = lut.getReds();
804  fi.greens = lut.getGreens();
805  fi.blues = lut.getBlues();
806  break;
807  case GRAY16:
808  fi.fileType = fi.GRAY16_UNSIGNED;
809  break;
810  case GRAY32:
811  fi.fileType = fi.GRAY32_FLOAT;
812  break;
813  case COLOR_RGB:
814  fi.fileType = fi.RGB;
815  break;
816  default:
817  }
818  return fi;
819  }
820 
826  public FileInfo getOriginalFileInfo() {
827  return fileInfo;
828  }
829 
831  public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h) {
832  imageUpdateY = y;
833  imageUpdateW = w;
834  if ((flags & ERROR) != 0) {
835  errorLoadingImage = true;
836  return false;
837  }
838  imageLoaded = (flags & (ALLBITS|FRAMEBITS|ABORT)) != 0;
839  return !imageLoaded;
840  }
841 
845  public synchronized void flush() {
846  if (locked || ignoreFlush)
847  return;
848  if (ip!=null) {
849  ip.setPixels(null);
850  ip = null;
851  }
852  if (roi!=null)
853  roi.setImage(null);
854  img = null;
855  System.gc();
856  }
857 
860  public void setIgnoreFlush(boolean ignoreFlush) {
861  this.ignoreFlush = ignoreFlush;
862  }
863 
867  ImagePlus imp2 = new ImagePlus();
868  imp2.setType(getType());
870  return imp2;
871  }
872 
874  public void copyScale(ImagePlus imp) {
875  if (imp!=null && globalCalibration==null)
877  }
878 
882  public void startTiming() {
883  startTime = System.currentTimeMillis();
884  }
885 
888  public long getStartTime() {
889  return startTime;
890  }
891 
893  public Calibration getCalibration() {
894  //IJ.log("getCalibration: "+globalCalibration+" "+calibration);
895  if (globalCalibration!=null)
896  return globalCalibration.copy();
897  else {
898  if (calibration==null)
899  calibration = new Calibration(this);
900  return calibration;
901  }
902  }
903 
905  public void setCalibration(Calibration cal) {
906  //IJ.write("setCalibration: "+cal);
907  if (cal==null)
908  calibration = null;
909  else {
910  calibration = cal.copy();
911  calibration.setImage(this);
912  }
913  }
914 
916  public void setGlobalCalibration(Calibration global) {
917  //IJ.log("setGlobalCalibration ("+getTitle()+"): "+global);
918  if (global==null)
919  globalCalibration = null;
920  else
921  globalCalibration = global.copy();
922  }
923 
928  public void mouseMoved(int x, int y) {
929  IJ.showStatus(getLocationAsString(x,y) + getValueAsString(x,y));
930  savex=x; savey=y;
931  }
932 
933  private int savex, savey;
934 
939  public void updateStatusbarValue() {
940  IJ.showStatus(getLocationAsString(savex,savey) + getValueAsString(savex,savey));
941  }
942 
943  String getFFTLocation(int x, int y, Calibration cal) {
944  double center = width/2.0;
945  double r = Math.sqrt((x-center)*(x-center) + (y-center)*(y-center));
946  if (r<1.0) r = 1.0;
947  double theta = Math.atan2(y-center, x-center);
948  theta = theta*180.0/Math.PI;
949  if (theta<0) theta = 360.0+theta;
950  String s = "r=";
951  if (cal.scaled())
952  s += IJ.d2s((width/r)*cal.pixelWidth,2) + " " + cal.getUnit() + "/c (" + IJ.d2s(r,0) + ")";
953  else
954  s += IJ.d2s(width/r,2) + " p/c (" + IJ.d2s(r,0) + ")";
955  s += ", theta= " + IJ.d2s(theta,2) + IJ.degreeSymbol;
956  return s;
957  }
958 
960  public String getLocationAsString(int x, int y) {
961  Calibration cal = getCalibration();
962  if (getProperty("FHT")!=null)
963  return getFFTLocation(x, height-y-1, cal);
964  y = Analyzer.updateY(y, height);
965  if (cal.scaled() && !IJ.altKeyDown()) {
966  String s = " x="+IJ.d2s(cal.getX(x)) + ", y=" + IJ.d2s(cal.getY(y));
967  return s;
968  } else {
969  String s = " x="+x+", y=" + y;
970  return s;
971  }
972  }
973 
974  private String getValueAsString(int x, int y) {
975  Calibration cal = getCalibration();
976  int[] v = getPixel(x, y);
977  switch (getType()) {
978  case GRAY8: case GRAY16:
979  double cValue = cal.getCValue(v[0]);
980  if (cValue==v[0])
981  return(", value=" + v[0]);
982  else
983  return(", value=" + IJ.d2s(cValue) + " ("+v[0]+")");
984  case GRAY32:
985  return(", value=" + Float.intBitsToFloat(v[0]));
986  case COLOR_256:
987  return(", index=" + v[3] + ", value=" + v[0] + "," + v[1] + "," + v[2]);
988  case COLOR_RGB:
989  return(", value=" + v[0] + "," + v[1] + "," + v[2]);
990  default: return("");
991  }
992  }
993 
994  public String toString() {
995  return getTitle()+" "+width+"x"+height;
996  }
997 
998  public ImageCanvas getCanvas() {
999  return imageCanvas;
1000  }
1001 
1002  public void setCanvas(ImageCanvas ic) {
1003  imageCanvas = ic;
1004  }
1005 
1006 
1007 }