Codebase list imagej / 02a3458
New upstream version 1.53j Nilesh Patra 2 years ago
35 changed file(s) with 751 addition(s) and 213 deletion(s). Raw diff Collapse all Expand all
186186 }
187187
188188 public void updateAndDraw() {
189 if (win==null) {
190 img = null;
191 return;
192 }
189193 updateImage();
190194 if (win!=null)
191195 notifyListeners(UPDATED);
24612461 return new String[0];
24622462 for (int i=0; i<lutsMenu.getItemCount(); i++) {
24632463 MenuItem menuItem = lutsMenu.getItem(i);
2464 if (menuItem.getActionListeners().length == 0) // separator?
2465 continue;
24662464 String label = menuItem.getLabel();
2467 if (label.equals("Invert LUT") || label.equals("Apply LUT"))
2465 if (label.equals("-") || label.equals("Invert LUT") || label.equals("Apply LUT"))
24682466 continue;
24692467 String command = (String)commands.get(label);
24702468 if (command==null || command.startsWith("ij.plugin.LutLoader"))
7676 MouseListener, KeyListener, WindowListener, ItemListener, Runnable {
7777
7878 /** Plugins should call IJ.getVersion() or IJ.getFullVersion() to get the version string. */
79 public static final String VERSION = "1.53i";
80 public static final String BUILD = ""; //44
79 public static final String VERSION = "1.53j";
80 public static final String BUILD = ""; //46
8181 public static Color backgroundColor = new Color(237,237,237);
8282 /** SansSerif, 12-point, plain font. */
8383 public static final Font SansSerif12 = new Font("SansSerif", Font.PLAIN, 12);
733733 if (!noGUI && (ij==null || (ij!=null && !ij.isShowing()))) {
734734 ij = new ImageJ(null, mode);
735735 ij.exitWhenQuitting = true;
736 }
736 } else if (batchMode && noGUI)
737 Prefs.load(null, null);
737738 int macros = 0;
738739 for (int i=0; i<nArgs; i++) {
739740 String arg = args[i];
297297 nothing if there is no window associated with
298298 this image (i.e. show() has not been called).*/
299299 public synchronized void updateAndDraw() {
300 if (win==null) {
301 img = null;
302 return;
303 }
300304 if (stack!=null && !stack.isVirtual() && currentSlice>=1 && currentSlice<=stack.size()) {
301305 if (stack.size()>1 && win!=null && !(win instanceof StackWindow)) {
302306 setStack(stack); //adds scroll bar if stack size has changed to >1
421425 /** ImageCanvas.paint() calls this method when the
422426 ImageProcessor has generated a new image. */
423427 public void updateImage() {
428 if (win==null) {
429 img = null;
430 return;
431 }
424432 if (ip!=null)
425433 img = ip.createImage();
426434 }
428436 /** Closes the window, if any, that is displaying this image. */
429437 public void hide() {
430438 if (win==null) {
439 img = null;
431440 Interpreter.removeBatchModeImage(this);
432441 return;
433442 }
542551 img = ip.createImage();
543552 return img;
544553 }
545
554
546555 /** Returns a copy of this image as an 8-bit or RGB BufferedImage.
547556 * @see ij.process.ShortProcessor#get16BitBufferedImage
548557 */
33463355 public void setBorderColor(Color borderColor) {
33473356 this.borderColor = borderColor;
33483357 }
3358
3359 public boolean windowActivated() {
3360 return this.activated;
3361 }
33493362
33503363 }
825825 /** Returns the specified ImageJ menu (e.g., "File>New") or null if it is not found. */
826826 public static Menu getImageJMenu(String menuPath) {
827827 if (menus==null)
828 IJ.init();
829 if (menus==null)
828830 return null;
829831 if (menus.get(menuPath)!=null)
830832 return getMenu(menuPath, false);
13321334
13331335 /** Returns the hashtable that associates commands with plugins. */
13341336 public static Hashtable getCommands() {
1337 if (pluginsTable==null)
1338 IJ.init();
13351339 return pluginsTable;
13361340 }
13371341
16601664
16611665 /** Called once when ImageJ quits. */
16621666 public static void savePreferences(Properties prefs) {
1667 if (pluginsPrefs==null)
1668 return;
16631669 int index = 0;
16641670 for (Enumeration en=pluginsPrefs.elements(); en.hasMoreElements();) {
16651671 String key = "plugin" + (index/10)%10 + index%10;
287287 public static String load(Object ij, Applet applet) {
288288 if (ImageJDir==null)
289289 ImageJDir = System.getProperty("user.dir");
290 InputStream f = null;
291 try { // Look for IJ_Props.txt in ImageJ folder
292 f = new FileInputStream(ImageJDir+"/"+PROPS_NAME);
293 propertiesPath = ImageJDir+"/"+PROPS_NAME;
294 } catch (FileNotFoundException e) {
295 f = null;
296 }
297 if (f==null) {
298 // Look in ij.jar if not found in ImageJ folder
299 f = ij.getClass().getResourceAsStream("/"+PROPS_NAME);
300 }
301 if (applet!=null)
302 return loadAppletProps(f, applet);
303 if (f==null)
304 return PROPS_NAME+" not found in ij.jar or in "+ImageJDir;
305 f = new BufferedInputStream(f);
306 try {
307 props.load(f);
308 f.close();
309 } catch (IOException e) {
310 return("Error loading "+PROPS_NAME);
311 }
312 imagesURL = props.getProperty(IJ.isJava18()?"images.location":"images.location2");
290 if (ij!=null) {
291 InputStream f = null;
292 try { // Look for IJ_Props.txt in ImageJ folder
293 f = new FileInputStream(ImageJDir+"/"+PROPS_NAME);
294 propertiesPath = ImageJDir+"/"+PROPS_NAME;
295 } catch (FileNotFoundException e) {
296 f = null;
297 }
298 if (f==null) {
299 // Look in ij.jar if not found in ImageJ folder
300 f = ij.getClass().getResourceAsStream("/"+PROPS_NAME);
301 }
302 if (applet!=null)
303 return loadAppletProps(f, applet);
304 if (f==null)
305 return PROPS_NAME+" not found in ij.jar or in "+ImageJDir;
306 f = new BufferedInputStream(f);
307 try {
308 props.load(f);
309 f.close();
310 } catch (IOException e) {
311 return("Error loading "+PROPS_NAME);
312 }
313 imagesURL = props.getProperty(IJ.isJava18()?"images.location":"images.location2");
314 }
313315 loadPreferences();
314316 loadOptions();
315317 guiScale = get(GUI_SCALE, 1.0);
461463 if (!IJ.isLinux()) dialogCancelButtonOnRight = false;
462464 saveOptions(prefs);
463465 savePluginPrefs(prefs);
464 IJ.getInstance().savePreferences(prefs);
466 ImageJ ij = IJ.getInstance();
467 if (ij!=null)
468 ij.savePreferences(prefs);
465469 Menus.savePreferences(prefs);
466470 ParticleAnalyzer.savePreferences(prefs);
467471 Analyzer.savePreferences(prefs);
721721 }
722722
723723 /** Adds one or two (side by side) text areas.
724 * @param text1 initial contents of the first text area
725 * @param text2 initial contents of the second text area or null
726 * @param rows the number of rows
727 * @param columns the number of columns
724 * Append "SCROLLBARS_VERTICAL_ONLY" to the text of
725 * the first text area to get vertical scrollbars
726 * and "SCROLLBARS_BOTH" to get both vertical and
727 * horizontal scrollbars.
728 * @param text1 initial contents of the first text area
729 * @param text2 initial contents of the second text area or null
730 * @param rows the number of rows
731 * @param columns the number of columns
728732 */
729733 public void addTextAreas(String text1, String text2, int rows, int columns) {
730734 if (textArea1!=null) return;
731735 Panel panel = new Panel();
736 int scrollbars = TextArea.SCROLLBARS_NONE;
737 if (text1.endsWith("SCROLLBARS_BOTH")) {
738 scrollbars = TextArea.SCROLLBARS_BOTH;
739 text1 = text1.substring(0, text1.length()-15);
740 }
741 if (text1.endsWith("SCROLLBARS_VERTICAL_ONLY")) {
742 scrollbars = TextArea.SCROLLBARS_VERTICAL_ONLY;
743 text1 = text1.substring(0, text1.length()-24);
744 }
732745 Font font = new Font("SansSerif", Font.PLAIN, (int)(14*Prefs.getGuiScale()));
733 textArea1 = new TextArea(text1,rows,columns,TextArea.SCROLLBARS_NONE);
746 textArea1 = new TextArea(text1,rows,columns,scrollbars);
734747 if (IJ.isLinux()) textArea1.setBackground(Color.white);
735748 textArea1.setFont(font);
736749 textArea1.addTextListener(this);
737750 panel.add(textArea1);
738751 if (text2!=null) {
739 textArea2 = new TextArea(text2,rows,columns,TextArea.SCROLLBARS_NONE);
752 textArea2 = new TextArea(text2,rows,columns,scrollbars);
740753 if (IJ.isLinux()) textArea2.setBackground(Color.white);
741754 textArea2.setFont(font);
742755 panel.add(textArea2);
7272 if (dialogD.height > 0.80*screenD.height && screenD.height>400) //max 80% of screen height
7373 dialogD.height = (int)(0.80*screenD.height);
7474 setSize(dialogD);
75 GUI.centerOnImageJScreen(this);
76 if (!modal) WindowManager.addWindow(this);
77 show();
75 GUI.centerOnImageJScreen(this);
76 if (!modal) {
77 WindowManager.addWindow(this);
78 show();
79 }
80 final JScrollBar verticalScrollBar = scrollPane.getVerticalScrollBar();
81 if (verticalScrollBar!=null) {
82 EventQueue.invokeLater(new Runnable() {
83 public void run() {
84 verticalScrollBar.setValue(verticalScrollBar.getMinimum()); //start scrollbar at top
85 }
86 });
87 }
88 if (modal) show();
7889 }
7990
8091 public void actionPerformed(ActionEvent e) {
993993 public void setLabel(int index, String label) {
994994 if (index < 0) index = allPlotObjects.size() + index;
995995 allPlotObjects.get(index).label = label;
996 }
997
998 /** Removes NaNs from the xValues and yValues arrays of all plot objects. */
999 public void removeNaNs() {
1000 for (PlotObject plotObj : allPlotObjects){
1001 if(plotObj != null && plotObj.xValues!= null && plotObj.yValues != null ){
1002 int oldSize = plotObj.xValues.length;
1003 float[] xVals = new float[oldSize];
1004 float[] yVals = new float[oldSize];
1005 int newSize = 0;
1006 for (int kk = 0; kk < oldSize; kk++) {
1007 if (!Float.isNaN(plotObj.xValues[kk] + plotObj.yValues[kk])) {
1008 xVals[newSize] = plotObj.xValues[kk];
1009 yVals[newSize] = plotObj.yValues[kk];
1010 newSize++;
1011 }
1012 }
1013 if (newSize < oldSize) {
1014 plotObj.xValues = new float[newSize];
1015 plotObj.yValues = new float[newSize];
1016 System.arraycopy(xVals, 0, plotObj.xValues, 0, newSize);
1017 System.arraycopy(yVals, 0, plotObj.yValues, 0, newSize);
1018 }
1019 }
1020 }
9961021 }
9971022
9981023 /** Returns an array of the available curve types ("Line", "Bar", "Circle", etc). */
365365 return this;
366366 }
367367
368 /** Adds a point at the specified stack position. */
369 public void addPoint(double x, double y, int position) {
370 if (counters==null) {
371 counters = new short[100];
372 positions = new int[100];
373 }
374 addPoint(null, x, y);
375 positions[nPoints-1] = position;
376 }
377
368378 protected void deletePoint(int index) {
369379 super.deletePoint(index);
370380 if (index>=0 && index<=nPoints && counters!=null) {
404414 if (rt!=null && WindowManager.getFrame(getCountsTitle())!=null)
405415 displayCounts();
406416 }
407
417
408418 /** Returns the index of the current counter. */
409419 public int getCounter() {
410420 return counter;
9595
9696 private static Color foregroundColor = Prefs.getColor(Prefs.FCOLOR,Color.white);
9797 private static Color backgroundColor = Prefs.getColor(Prefs.BCOLOR,Color.black);
98 private static double foregroundValue = Double.NaN;
99 private static double backgroundValue = Double.NaN;
98100 private static int ovalType = OVAL_ROI;
99101 private static int rectType = RECT_ROI;
100102 private static boolean multiPointMode = Prefs.multiPointMode;
935937 if (c==null)
936938 return;
937939 foregroundColor = c;
940 foregroundValue = Double.NaN;
938941 IJ.notifyEventListeners(IJEventListener.FOREGROUND_COLOR_CHANGED);
939942 if (instance==null)
940943 return;
953956 public static void setBackgroundColor(Color c) {
954957 if (c!=null) {
955958 backgroundColor = c;
959 backgroundValue = Double.NaN;
956960 repaintTool(DROPPER);
957961 IJ.notifyEventListeners(IJEventListener.BACKGROUND_COLOR_CHANGED);
958962 }
963 }
964
965 public static double getForegroundValue() {
966 return foregroundValue;
967 }
968
969 public static void setForegroundValue(double value) {
970 if (value>=0) {
971 int v = (int)value;
972 if (v>255) v=255;
973 setForegroundColor(new Color(v,v,v));
974 }
975 foregroundValue = value;
976 }
977
978 public static double getBackgroundValue() {
979 return backgroundValue;
980 }
981
982 public static void setBackgroundValue(double value) {
983 if (value>=0) {
984 int v = (int)value;
985 if (v>255) v=255;
986 setBackgroundColor(new Color(v,v,v));
987 }
988 backgroundValue = value;
959989 }
960990
961991 private static void setRoiColor(Color c) {
278278 case EXEC: str = exec(); break;
279279 case LIST: str = doList(); break;
280280 case DEBUG: str = debug(); break;
281 case IJ_CALL: str = ijCall(); break;
281 case IJ_CALL: str = doIJ(); break;
282282 case GET_RESULT_STRING: str = getResultString(null); break;
283283 case TRIM: str = trim(); break;
284284 default:
693693 IJ.setKeyUp(IJ.ALL_KEYS);
694694 shiftKeyDown = altKeyDown = false;
695695 }
696
696
697697 private void selectWindow() {
698698 String title = getStringArg();
699699 if (resultsPending && "Results".equals(title)) {
22182218 return getPlotLimits(currentPlot);
22192219 } else if (name.equals("freeze")) {
22202220 currentPlot.setFrozen(getBooleanArg());
2221 return Double.NaN;
2222 } else if (name.equals("removeNaNs")) {
2223 currentPlot.removeNaNs();
22212224 return Double.NaN;
22222225 } else if (name.equals("addLegend") || name.equals("setLegend")) {
22232226 return addPlotLegend(currentPlot);
38863889 }
38873890 }
38883891 }
3889
3892
38903893 String trim() {
38913894 if (interp.nextToken()=='=')
38923895 interp.error("'trim' is a reserved word");
51115114 return Toolbar.getForegroundColor().getRGB()&0xffffff;
51125115 else if (key.equals("rgb.background"))
51135116 return Toolbar.getBackgroundColor().getRGB()&0xffffff;
5114 else if (key.contains("foreground"))
5115 return getColorValue(Toolbar.getForegroundColor());
5116 else if (key.contains("background"))
5117 return getColorValue(Toolbar.getBackgroundColor());
5118 else if (key.equals("font.size")) {
5117 else if (key.contains("foreground")) {
5118 double value = Toolbar.getForegroundValue();
5119 if (Double.isNaN(value))
5120 return getColorValue(Toolbar.getForegroundColor());
5121 else
5122 return value;
5123 } else if (key.contains("background")) {
5124 double value = Toolbar.getBackgroundValue();
5125 if (Double.isNaN(value))
5126 return getColorValue(Toolbar.getBackgroundColor());
5127 else
5128 return value;
5129 } else if (key.equals("font.size")) {
51195130 resetImage();
51205131 ImageProcessor ip = getProcessor();
51215132 setFont(ip);
57405751 props = new Properties();
57415752 String name = interp.tokenString;
57425753 if (name.equals("doFit"))
5743 return fitCurve();
5754 return fitCurve(false);
5755 if (name.equals("doWeightedFit"))
5756 return fitCurve(true);
57445757 else if (name.equals("getEquation"))
57455758 return getEquation();
57465759 else if (name.equals("nEquations")) {
57765789 return Double.NaN;
57775790 }
57785791
5779 double fitCurve() {
5792 double fitCurve(boolean withWeights) {
57805793 interp.getLeftParen();
57815794 int fit = -1;
57825795 String name = null;
58005813 double[] x = getNextArray();
58015814 interp.getComma();
58025815 double[] y = getNumericArray();
5816 double[] weights = null;
5817 if (withWeights) {
5818 interp.getComma();
5819 weights = getNumericArray();
5820 }
58035821 if (interp.nextToken()==',') {
58045822 interp.getComma();
58055823 initialValues = getNumericArray();
58105828 if (x.length==0)
58115829 interp.error("Zero length array");
58125830 fitter = new CurveFitter(x, y);
5831 if (withWeights)
5832 fitter.setWeights(weights);
58135833 fitter.setStatusAndEsc(null, true);
58145834 if (fit==-1 && name!=null) {
58155835 Interpreter instance = Interpreter.getInstance();
59695989 contains = str.contains(filter);
59705990 if (contains)
59715991 list.add(a1[i]);
5972 }
5992 }
59735993 }
59745994 return (Variable[])list.toArray(new Variable[list.size()]);
59755995 }
5976
5996
59775997 Variable[] deleteArrayIndex() {
59785998 interp.getLeftParen();
59795999 Variable[] arr1 = getArray();
64866506 resetImage();
64876507 }
64886508
6489 private String ijCall() {
6509 private String doIJ() {
64906510 interp.getToken();
64916511 if (interp.token!='.')
64926512 interp.error("'.' expected");
65146534 renameResults();
65156535 else if (name.equals("getFullVersion"))
65166536 {interp.getParens(); return ""+IJ.getFullVersion();}
6537 else if (name.equals("checksum"))
6538 return checksum();
65176539 else
65186540 interp.error("Unrecognized IJ function name");
65196541 return null;
6542 }
6543
6544 private String checksum(){
6545 String method = getFirstString();
6546 String src = getLastString();
6547 method = method.toUpperCase();
6548 if (method.contains("FILE") && method.contains("MD5"))
6549 return Tools.getHash("MD5", true, src);
6550 if (method.contains("STRING") && method.contains("MD5"))
6551 return Tools.getHash("MD5", false, src);
6552 if (method.contains("FILE") && method.contains("SHA-256"))
6553 return Tools.getHash("SHA-256", true, src);
6554 if (method.contains("STRING") && method.contains("SHA-256"))
6555 return Tools.getHash("SHA-256", false, src);
6556 interp.error("must contain 'file' or 'string' and 'MD5' or 'SHA-256'");
6557 return "0";
65206558 }
65216559
65226560 private String pad() {
67356773 interp.error("Unrecognized function name");
67366774 return Double.NaN;
67376775 }
6738
6776
67396777 private double activateSelection(ImagePlus imp, Overlay overlay, boolean wait) {
67406778 int index = (int)getArg();
67416779 int size = overlay.size();
67646802 IJ.wait(5);
67656803 } while (ic!=null && ic.getPaintPending() && System.currentTimeMillis()-t0<50);
67666804 } else
6767 imp.setRoi(roi, !Interpreter.isBatchMode());
6805 imp.setRoi(roi, !Interpreter.isBatchMode());
67686806 if (Analyzer.addToOverlay())
67696807 ResultsTable.selectRow(roi);
67706808 return Double.NaN;
6771 }
6772
6809 }
6810
67736811 private double getOverlayElementBounds(Overlay overlay) {
67746812 int index = (int)getFirstArg();
67756813 Variable x = getNextVariable();
71867224 resultsPending = false;
71877225 return null;
71887226 }
7189
7227
71907228 private Variable resetTable() {
71917229 String title = getTitleArg();
71927230 ResultsTable rt = null;
79297967 interp.error("Unrecognized RoiManager function");
79307968 return null;
79317969 }
7932
7970
79337971 private Variable doProperty() {
79347972 interp.getToken();
79357973 if (interp.token!='.')
79898027 interp.error("Unrecognized Property function");
79908028 return null;
79918029 }
7992
8030
79938031 private void setPropertiesFromString(Properties props) {
79948032 String list = getStringArg();
79958033 props.clear();
80198057 }
80208058 return sb.toString();
80218059 }
8022
8060
80238061 static boolean isStringFunction(String name, int type) {
80248062 boolean isString = false;
80258063 switch (type) {
80588096 }
80598097 return isString;
80608098 }
8061
8099
80628100 private Variable doImage() {
80638101 interp.getToken();
80648102 if (interp.token!='.')
80788116 interp.getParens();
80798117 imp.copy();
80808118 return null;
8081 } else if (name.equals("paste")) {
8119 } else if (name.equals("paste")) {
80828120 int x = (int)getFirstArg();
80838121 int y = (int)getNextArg();
80848122 String mode = null;
81198157 return setForegroundOrBackground(true);
81208158 } else if (name.equals("setBackground")) {
81218159 return setForegroundOrBackground(false);
8160 } else if (name.equals("setForegroundValue")) {
8161 Toolbar.setForegroundValue(getArg());
8162 return null;
8163 } else if (name.equals("setBackgroundValue")) {
8164 Toolbar.setBackgroundValue(getArg());
8165 return null;
81228166 } else if (name.equals("toString")) {
81238167 int red = (int)getFirstArg();
81248168 int green = (int)getNextArg();
81438187 interp.error("Unrecognized Color function");
81448188 return null;
81458189 }
8146
8190
81478191 private Variable setForegroundOrBackground(boolean foreground) {
81488192 interp.getLeftParen();
81498193 Color color = null;
81578201 int blue = (int)getLastArg();
81588202 color = Colors.toColor(red, green, blue);
81598203 }
8160 if (foreground)
8204 if (foreground)
81618205 Toolbar.setForegroundColor(color);
81628206 else
81638207 Toolbar.setBackgroundColor(color);
81658209 }
81668210
81678211 } // class Functions
8168
830830 case Variable.STRING: doStringAssignment(); break;
831831 case Variable.ARRAY: doArrayAssignment(); break;
832832 case USER_FUNCTION: doUserFunctionAssignment(); break;
833 case STRING_FUNCTION: doNumericStringAssignment(); break;
833834 default:
834835 putTokenBack();
835836 double value = getAssignmentExpression();
4242 * 2016-11-28: added static getNumParams methods
4343 * 2018-03-23: fixes NullPointerException for custom fit without initialParamVariations
4444 * 2018-07-19: added error function erf (=integral over Gaussian)
45 * 2021-04-30: data points can have weights
4546 */
4647
4748 public class CurveFitter implements UserFunction{
9394 "y = a*(1-exp(-b*x))^c", //CHAPMAN
9495 "y = a+b*erf((x-c)/d)" //ERF; note that the c parameter is sqrt2 times the Gaussian
9596 };
96
97
9798 /** ImageJ Macro language code for the built-in functions */
9899 public static final String[] fMacro = {
99100 "y = a+x*b","y = a+x*(b+x*c)", //STRAIGHT_LINE,POLY2
122123
123124 private int fitType = -1; // Number of curve type to fit
124125 private double[] xData, yData; // x,y data to fit
126 private double[] weights; // weights for the data to fit
125127 private double[] xDataSave, yDataSave; //saved original data after fitting modified data
126128 private int numPoints; // number of data points in actual fit
127129 private double ySign = 0; // remember sign of y data for power-law fit via regression
128 private double sumY = Double.NaN, sumY2 = Double.NaN; // sum(y), sum(y^2) of the data used for fitting
130 private double sumY = Double.NaN, sumY2 = Double.NaN; // sum(y*w), sum(y^2*w) of the data used for fitting (w=weight, default 1)
131 private double sumWeights = Double.NaN; //sum of weights (or numPoints, if no weigths are given)
129132 private int numParams; // number of parameters
130133 private double[] initialParams; // user specified or estimated initial parameters
131134 private double[] initialParamVariations; // estimate of range of parameters
258261 }
259262
260263 /** Fit a function defined as a macro String like "y = a + b*x + c*x*x".
264 * When showSettings is true, pops up a dialog allowing the user to set the initial
265 * fit parameters and various numbers controlling the Minimizer
261266 * Returns the number of parameters, or 0 in case of a macro syntax error.
262267 *
263 * For good performance, it is advisable to set also the typical variation range
264 * of the initial parameters by the
265 * getMinimizer().setInitialParamVariations(double[]) method (especially if one or
266 * more of the initialParams are zero).
267268 * Use getStatus() and/or getStatusString() to see whether fitting was (probably) successful and
268269 * getParams() to access the result.
270 *
271 * For complicated fits and good performance, it is advisable to use the doCustomFit method with
272 * a (java) UserFunction, which also has more options.
273 *
269274 */
270275 public int doCustomFit(String equation, double[] initialParams, boolean showSettings) {
271276 customFormula = null;
297302 * Use getStatus() and/or getStatusString() to see whether fitting was (probably) successful and
298303 * getParams() to access the result.
299304 *
300 * @param userFunction A plugin where the fit function is defined by the
301 * userFunction(params, x) method.
302 * This function must allow simultaneous calls in multiple threads.
305 * For getter performance, if possible it is advisable to first call setOffsetMultiplySlopeParams,
306 * to avoid searching for one or two parameters that can be calculated directly by linear regression.
307 *
308 * @param userFunction A class instance implementing the userFunction interface. There, the
309 * fit function hould be defined by the method userFunction(params, x).
310 * This function must allow simultaneous calls in multiple threads.
303311 * @param numParams Number of parameters of the fit function.
304312 * @param formula A String describing the fit formula, may be null.
305 * @param initialParams Starting point for the parameters; may be null (than values
306 * of 0 are used). The fit function with these parameters must
307 * not return NaN for any of the data points given in the
308 * constructor (xData).
313 * @param initialParams Starting point for the parameters; the fit function with these parameters
314 * must not return NaN for any of the data points given in the constructor (xData).
315 * initialParams may be null, then random values are used,
316 * with repeated tries if the userFunction returns NaN.
309317 * @param initialParamVariations Each parameter is initially varied by up to +/- this value.
310 * If not given (null), initial variations are taken as
311 * 10% of initial parameter value or 0.01 for parameters that are zero.
312 * When this array is given, all elements must be positive (nonzero).
313 * See Minimizer.minimize for details.
314 * @param showSettings Displays a popup dialog for modifying the initial parameters and
315 * a few numbers controlling the minimizer.
318 * If not given (null), initial variations are taken as
319 * 10% of initial parameter value or 0.01 for parameters that are zero.
320 * When this array is given, all elements must be positive (nonzero).
321 * See Minimizer.minimize for details. Providing this array is
322 * especially valuable if one or more initial parameters have a value of 0.
323 * @param showSettings Displays a popup dialog for modifying the initial parameters and
324 * a few numbers controlling the minimizer.
316325 */
317326 public void doCustomFit(UserFunction userFunction, int numParams, String formula,
318327 double[] initialParams, double[] initialParamVariations, boolean showSettings) {
327336 /** Sets the initial parameters, which override the default initial parameters. */
328337 public void setInitialParameters(double[] initialParams) {
329338 this.initialParams = initialParams;
339 }
340
341 /** Sets weights of the data points. The 'weights' array must have the same length as the data arrays
342 * passed with the constructor. If the error bars of the data points are known, the weights
343 * should be proportional to 1/error^2.
344 * When weights are specified, note that 'getSumResidualsSqr' will return the weighted sum. */
345 public void setWeights(double[] weights) {
346 this.weights = weights;
330347 }
331348
332349 /** Returns a reference to the Minimizer used, for accessing Minimizer methods directly.
556573 return residuals;
557574 }
558575
559 /* Get the sum of the residuals (may be NaN if the minimizer could not start properly
576 /** Returns the sum of the residuals (may be NaN if the minimizer could not start properly
560577 * i.e., if getStatus() returns Minimizer.INITILIZATION_FAILURE).
578 * If weights have been specified, each of the residuals is multiplied by the corresponding
579 * weight before summing.
561580 */
562581 public double getSumResidualsSqr() {
563582 return getParams()[numParams]; // value is stored as last element by the minimizer
566585 /** Returns the standard deviation of the residuals.
567586 * Here, the standard deviation is defined here as the root-mean-square of the residuals
568587 * times sqrt(n/(n-1)); where n is the number of points.
588 * If weights are provided, the standard deviation does not take the weights into account.
589 * With weights, the standard deviation and getSumResidualsSqr (which uses weights)
590 * are not related the usual way.
569591 */
570592 public double getSD() {
571593 double[] residuals = getResiduals();
579601 return Math.sqrt(stdDev/(n-1.0));
580602 }
581603
582 /** Returns R^2, where 1.0 is best.
604 /** Returns R^2, where 1.0 is best. For unweighted data,
583605 <pre>
584606 r^2 = 1 - SSE/SSD
585607
586 where: SSE = sum of the squared errors
587 SSD = sum of the squared deviations about the mean.
608 where: SSE = sum of the squared errors
609 SSD = sum of the squared deviations about the mean.
588610 </pre>
589611 * For power, exp by linear regression and 'Rodbard NIH Image', this is calculated for the
590612 * fit actually done, not for the residuals of the original data.
591 */
613 */
592614 public double getRSquared() {
593615 if (Double.isNaN(sumY)) calculateSumYandY2();
594 double sumMeanDiffSqr = sumY2 - sumY*sumY/numPoints;
616 double sumMeanDiffSqr = sumY2 - sumY*sumY/sumWeights;
595617 double rSquared = 0.0;
596618 if (sumMeanDiffSqr > 0.0)
597619 rSquared = 1.0 - getSumResidualsSqr()/sumMeanDiffSqr;
600622
601623 /** Get a measure of "goodness of fit" where 1.0 is best.
602624 * Approaches R^2 if the number of points is much larger than the number of fit parameters.
625 * Assumes that the data points are independent (i.e., each point having a different x value).
603626 * For power, exp by linear regression and 'Rodbard NIH Image', this is calculated for the
604627 * fit actually done, not for the residuals of the original data.
605628 */
606629 public double getFitGoodness() {
607630 if (Double.isNaN(sumY)) calculateSumYandY2();
608 double sumMeanDiffSqr = sumY2 - sumY*sumY/numPoints;
631 double sumMeanDiffSqr = sumY2 - sumY*sumY/sumWeights;
609632 double fitGoodness = 0.0;
610633 int degreesOfFreedom = numPoints - getNumParams();
611634 if (sumMeanDiffSqr > 0.0 && degreesOfFreedom > 0)
739762 fitType = RODBARD;
740763 return fList[fitType];
741764 }
742
765
743766 /** Returns macro code of the form "y = ...x" for the fit function used.
744767 * Note that this is not neccessarily the equation acutally used for the fit
745768 * (for the various "linear regression" types and RODBARD2, the fit is done
790813 if (numRegressionParams == 0) { // simply calculate sum of residuals
791814 for (int i=0; i<numPoints; i++) {
792815 double fValue = f(params,xData[i]);
793 sumResidualsSqr += sqr(fValue-yData[i]);
816 double resSqr = sqr(fValue-yData[i]);
817 if (weights != null) resSqr *= weights[i];
818 sumResidualsSqr += resSqr;
794819 }
795820 //IJ.log(IJ.d2s(params[0],3,5)+","+IJ.d2s(params[1],3,5)+": r="+IJ.d2s(sumResidualsSqr,3,5)+Thread.currentThread().getName() );
796821 } else { // handle simple linear dependencies by linear regression:
845870 private void doRegression(double[] params) {
846871 double sumX=0, sumX2=0, sumXY=0; //sums for regression; here 'x' are function values
847872 double sumY=0, sumY2=0; //only calculated for 'slope', otherwise we use the values calculated already
873 double sumWeights=0;
848874 for (int i=0; i<numPoints; i++) {
849875 double fValue = fitType == STRAIGHT_LINE ? 0 : f(params, xData[i]); // function value
850876 if (Double.isNaN(fValue)) { //check for NaN now; later we need NaN checking for division-by-zero check.
851877 params[numParams] = Double.NaN;
852878 return; //sum of squared residuals is NaN if any value is NaN
853879 }
880 double w = weights==null ? 1 : weights[i];
881 sumWeights += w;
854882 //if(getIterations()==0)IJ.log(xData[i]+"\t"+yData[i]+"\t"+fValue); //x,y,function
855883 if (hasSlopeParam) { // fit y = offset + slope*x + function(of other params)
856884 double x = xData[i];
857885 double y = yData[i] - fValue;
858 sumX += x;
859 sumX2 += x*x;
860 sumXY += x*y;
861 sumY2 += y*y;
862 sumY += y;
886 sumX += x*w;
887 sumX2 += x*x*w;
888 sumXY += x*y*w;
889 sumY2 += y*y*w;
890 sumY += y*w;
863891 } else { // fit y = offset + factor * function(of other params)
864892 double x = fValue;
865893 double y = yData[i];
866 sumX += fValue;
867 sumX2 += fValue*fValue;
868 sumXY += fValue*yData[i];
894 sumX += fValue*w;
895 sumX2 += fValue*fValue*w;
896 sumXY += fValue*yData[i]*w;
869897 }
870898 }
871899 if (!hasSlopeParam) {
883911 sumResidualsSqr = 2e-15*sumY2;
884912 } else { // full linear regression or offset only. Slope is named 'factor' here
885913 if (factorParam >= 0) {
886 factor = (sumXY-sumX*sumY/numPoints)/(sumX2-sumX*sumX/numPoints);
914 factor = (sumXY-sumX*sumY/sumWeights)/(sumX2-sumX*sumX/sumWeights);
887915 if (restrictPower & factor<=0) // power-law fit with (0,0) point: power must be >0
888916 factor = 1e-100;
889917 else if (Double.isNaN(factor) || Double.isInfinite(factor))
890918 factor = 0; // all 'x' values are equal, any factor (slope) will fit
891919 }
892 double offset = (sumY-factor*sumX)/numPoints;
920 double offset = (sumY-factor*sumX)/sumWeights;
893921 params[offsetParam] = offset;
894 sumResidualsSqr = sqr(factor)*sumX2 + numPoints*sqr(offset) + sumY2 +
922 sumResidualsSqr = sqr(factor)*sumX2 + sumWeights*sqr(offset) + sumY2 +
895923 2*factor*offset*sumX - 2*factor*sumXY - 2*offset*sumY;
896924 // check for accuracy problem: large difference of small numbers?
897925 // Don't report unrealistic or even negative values, otherwise minimization could lead
898926 // into parameters where we have a numeric problem
899 if (sumResidualsSqr < 2e-15*(sqr(factor)*sumX2 + numPoints*sqr(offset) + sumY2))
900 sumResidualsSqr = 2e-15*(sqr(factor)*sumX2 + numPoints*sqr(offset) + sumY2);
927 if (sumResidualsSqr < 2e-15*(sqr(factor)*sumX2 + sumWeights*sqr(offset) + sumY2))
928 sumResidualsSqr = 2e-15*(sqr(factor)*sumX2 + sumWeights*sqr(offset) + sumY2);
901929 //if(){IJ.log("sumX="+sumX+" sumX2="+sumX2+" sumXY="+sumXY+" factor="+factor+" offset=="+offset);}
902930 }
903931 params[numParams] = sumResidualsSqr;
12151243 }
12161244
12171245
1218 /** calculates the sum of y and y^2 */
1246 /** calculates the sum of y and y^2 (weighted sum if we have weights) */
12191247 private void calculateSumYandY2() {
1220 sumY = 0.0; sumY2 = 0.0;
1248 sumY = 0.0; sumY2 = 0.0; sumWeights = 0.0;
1249 double w = 1.0;
12211250 for (int i=0; i<numPoints; i++) {
12221251 double y = yData[i];
1223 sumY += y;
1224 sumY2 += y*y;
1252 if (weights != null) w = weights[i];
1253 sumY += y*w;
1254 sumY2 += y*y*w;
1255 sumWeights += w;
12251256 }
12261257 }
12271258
11 import ij.*;
22 import ij.process.*;
33 import ij.gui.*;
4 import ij.measure.ResultsTable;
5 import ij.util.Tools;
46
57 /** Implements the Plugins/Utilities/Run Benchmark command.
68 * Suppresses subordinate status bar messages by using
911 * IJ.showProgress(-currentIndex,finalIndex).
1012 */
1113 public class Benchmark implements PlugIn {
12 int size = 5000;
13 int ops = 62;
14 int counter;
14 private String[] results = {
15 "10.9|MacBook Air (M1, 2020, Native)",
16 "17.2|iMac Pro (2017)",
17 "18.1|MacBook Air (M1, 2020, Rosetta)",
18 "22.8|Dell T7920 (Dual Xeon, 282GB RAM, 2018)",
19 "24.7|27\" iMac (Early 2015)",
20 "29.7|13\" MacBook Pro (Late 2015)",
21 "29.7|15\" MacBook Pro (Early 2013)",
22 "62.3|Acer Aspire laptop (Core i5, 2014)"
23 };
24 private int size = 5000;
25 private int ops = 62;
26 private int counter;
1527
1628 public void run(String arg) {
1729 ImagePlus cImp = WindowManager.getCurrentImage();
5567 scale = scale*1.2;
5668 }
5769 double time = (System.currentTimeMillis()-t0)/1000.0;
70 ResultsTable rt = new ResultsTable();
71 rt.showRowNumbers(true);
72 for (int i=0; i<results.length; i++) {
73 String[] columns = Tools.split(results[i],"|");
74 rt.addRow();
75 rt.addValue("Time", columns[0]);
76 rt.addValue("Computer", columns[1]);
77 }
78 rt.addRow();
79 String t = IJ.d2s(time,1);
80 if (t.length()<4) t=" "+t;
81 rt.addValue("Time", t);
82 rt.addValue("Computer", "<<THIS MACHINE ("+Prefs.getThreads()+" THREADS)>>");
83 rt.sort("Time");
84 rt.show("Benchmark Results");
5885 IJ.showStatus("!"+IJ.d2s(time,1)+" seconds to perform "+counter+" operations on a "+size+"x"+size+" 16-bit image");
5986 }
6087
9797
9898 public ImageStack expandStack(ImageStack stackOld, int wNew, int hNew, int xOff, int yOff) {
9999 int nFrames = stackOld.getSize();
100 ImageProcessor ipOld = stackOld.getProcessor(1);
101 java.awt.Color colorBack = Toolbar.getBackgroundColor();
102
100 ImageProcessor ipOld = stackOld.getProcessor(1);
103101 ImageStack stackNew = new ImageStack(wNew, hNew, stackOld.getColorModel());
104102 ImageProcessor ipNew;
105103
109107 if (zeroFill)
110108 ipNew.setValue(0.0);
111109 else
112 ipNew.setColor(colorBack);
110 ipNew.setGlobalBackgroundColor();
113111 ipNew.fill();
114112 ipNew.insert(stackOld.getProcessor(i), xOff, yOff);
115113 stackNew.addSlice(stackOld.getSliceLabel(i), ipNew);
122120 if (zeroFill)
123121 ipNew.setValue(0.0);
124122 else
125 ipNew.setColor(Toolbar.getBackgroundColor());
123 ipNew.setGlobalBackgroundColor();
126124 ipNew.fill();
127125 ipNew.insert(ipOld, xOff, yOff);
128126 return ipNew;
4141 ImagePlus rImp = new ImagePlus(title+" (red)", channels[0]);
4242 rImp.setCalibration(cal);
4343 rImp.setIJMenuBar(false);
44 rImp.setBorderColor(new Color(255,180,180));
4544 rImp.show();
4645 rImp.setSlice(pos);
4746 if (IJ.isMacOSX()) IJ.wait(500);
4847 ImagePlus gImp = new ImagePlus(title+" (green)", channels[1]);
4948 gImp.setCalibration(cal);
5049 gImp.setIJMenuBar(false);
51 gImp.setBorderColor(new Color(180,255,180));
5250 gImp.show();
5351 gImp.setSlice(pos);
5452 if (IJ.isMacOSX()) IJ.wait(500);
5553 ImagePlus bImp = new ImagePlus(title+" (blue)", channels[2]);
5654 bImp.setCalibration(cal);
57 bImp.setBorderColor(new Color(180,180,255));
5855 bImp.show();
5956 bImp.setSlice(pos);
6057 }
257257 private static final int AE=0x4145, AS=0x4153, AT=0x4154, CS=0x4353, DA=0x4441, DS=0x4453, DT=0x4454,
258258 FD=0x4644, FL=0x464C, IS=0x4953, LO=0x4C4F, LT=0x4C54, PN=0x504E, SH=0x5348, SL=0x534C,
259259 SS=0x5353, ST=0x5354, TM=0x544D, UI=0x5549, UL=0x554C, US=0x5553, UT=0x5554,
260 OB=0x4F42, OW=0x4F57, SQ=0x5351, UN=0x554E, QQ=0x3F3F;
260 OB=0x4F42, OW=0x4F57, SQ=0x5351, UN=0x554E, QQ=0x3F3F,
261 OF=0x4F46, OL=0x4F4C, OD=0x4F44, UC=0x5543, UR=0x5552, OV=0x4F56, SV=0x5356, UV=0x5556;
262
261263
262264 private static Properties dictionary;
263265
460462
461463 switch (vr) {
462464 case OB: case OW: case SQ: case UN: case UT:
465 case OF: case OL: case OD: case UC: case UR:
466 case OV: case SV: case UV:
463467 // Explicit VR with 32-bit length if other two bytes are zero
464468 if ( (b2 == 0) || (b3 == 0) ) return getInt();
465469 // Implicit VR with 32-bit length
467471 if (littleEndian)
468472 return ((b3<<24) + (b2<<16) + (b1<<8) + b0);
469473 else
470 return ((b0<<24) + (b1<<16) + (b2<<8) + b3);
474 return ((b0<<24) + (b1<<16) + (b2<<8) + b3);
471475 case AE: case AS: case AT: case CS: case DA: case DS: case DT: case FD:
472476 case FL: case IS: case LO: case LT: case PN: case SH: case SL: case SS:
473 case ST: case TM:case UI: case UL: case US: case QQ:
477 case ST: case TM: case UI: case UL: case US: case QQ:
474478 // Explicit vr with 16-bit length
475479 if (littleEndian)
476480 return ((b3<<8) + b2);
17161720 };
17171721
17181722 }
1719
280280 * @see ij.ImagePlus#crop(String)
281281 */
282282 public ImagePlus crop(ImagePlus imp) {
283 //if (imp!=null) throw new IllegalArgumentException();
284283 if (imp.getNChannels()>1 && imp.getCompositeMode()==IJ.COMPOSITE) {
285284 int z = imp.getSlice();
286285 int t = imp.getFrame();
1717 private static final int MAX_SEPARATE = 40;
1818 private static final String DIR_KEY = "import.sequence.dir";
1919 private static final String[] types = {"default", "16-bit", "32-bit", "RGB"};
20 private static String[] excludedTypes = {".txt", ".lut", ".roi", ".pty", ".hdr", ".java", ".ijm", ".py", ".js", ".bsh", ".xml"};
20 private static String[] excludedTypes = {".txt",".lut",".roi",".pty",".hdr",".java",".ijm",".py",".js",".bsh",".xml",".rar",".h5",".doc",".xls"};
2121 private static boolean staticSortFileNames = true;
2222 private static boolean staticOpenAsVirtualStack;
2323 private boolean convertToRGB;
421421 }
422422 }
423423 if (imp2.getStackSize()==1) {
424 imp2.setProperty("Label", list[0]);
424 int idx = this.start-1;
425 if (idx<0 || idx>=list.length)
426 idx = 0;
427 imp2.setProperty("Label", list[idx]);
425428 if (info1!=null)
426429 imp2.setProperty("Info", info1);
427430 }
9191 gd.addChoice("Method:", methods, methods[staticMethod]);
9292 }
9393 gd.addStringField("Name:", name, 12);
94 gd.addStringField("Title Contains:", "", 12);
94 gd.addStringField("Title contains:", "", 12);
9595 if (sizesDiffer)
96 gd.addCheckbox("Bicubic Interpolation", staticBicubic);
97 gd.addCheckbox("Use Titles as Labels", staticTitlesAsLabels);
98 gd.addCheckbox("Keep Source Images", staticKeep);
96 gd.addCheckbox("Bicubic interpolation", staticBicubic);
97 gd.addCheckbox("Use titles as labels", staticTitlesAsLabels);
98 gd.addCheckbox("Keep source images", staticKeep);
9999 gd.showDialog();
100100 if (gd.wasCanceled()) return;
101101 if (sizesDiffer)
149149 if (ip.getMin()<min) min = ip.getMin();
150150 if (ip.getMax()>max) max = ip.getMax();
151151 String label = titlesAsLabels?images[i].getTitle():null;
152 if (label==null)
153 label = (String)images[i].getProperty("Label");
152154 if (label!=null) {
153155 String info = (String)images[i].getProperty("Info");
154156 if (info!=null) label += "\n" + info;
181181 bgColor = Color.white;
182182 }
183183 }
184 montage.setColor(bgColor);
184 if (Double.isNaN(Toolbar.getBackgroundValue()))
185 montage.setColor(bgColor);
186 else
187 montage.setGlobalBackgroundColor();
185188 montage.fill();
186 montage.setColor(fgColor);
189 if (Double.isNaN(Toolbar.getForegroundValue()))
190 montage.setColor(fgColor);
191 else
192 montage.setGlobalForegroundColor();
187193 montage.setFont(new Font("SansSerif", Font.PLAIN, fontSize));
188194 montage.setAntialiasedText(true);
189195 ImageStack stack = imp.getStack();
409409 public static void listRois(Roi[] rois) {
410410 ImagePlus imp = WindowManager.getCurrentImage();
411411 ResultsTable rt = new ResultsTable();
412 rt.showRowNumbers(true);
412413 for (int i=0; i<rois.length; i++) {
413414 if (rois[i]==null)
414415 continue;
437438 Rectangle2D.Double bounds = rois[i].getFloatBounds();
438439 rt.setValue("X", i, (int)Math.round(bounds.x));
439440 rt.setValue("Y", i, (int)Math.round(bounds.y));
441 } else if (rois[i] instanceof Arrow) {
442 Polygon p = ((Arrow)rois[i]).getPoints();
443 rt.setValue("X", i, p.xpoints[1]);
444 rt.setValue("Y", i, p.ypoints[1]);
440445 } else {
441446 rt.setValue("X", i, r.x);
442447 rt.setValue("Y", i, r.y);
3636 msg = ""+e;
3737 msg = "An error occured writing the file.\n \n" + msg;
3838 if (msg.contains("NullPointerException"))
39 msg = "Incorrect file path: \""+path+"\"";
39 msg = "Incorrect file path:";
40 msg += "\n \n"+path;
4041 IJ.error("PNG Writer", msg);
4142 }
4243 IJ.showStatus("");
44 import ij.measure.Calibration;
55 import ij.plugin.filter.EDM;
66 import ij.plugin.filter.ThresholdToSelection;
7 import ij.plugin.frame.Recorder;
78 import java.awt.*;
9 import java.util.Vector;
810
911 /** This plugin, which enlarges or shrinks selections, implements the Edit/Selection/Enlarge command. */
10 public class RoiEnlarger implements PlugIn {
11 private static double defaultDistance = 15; // pixels
12 public class RoiEnlarger implements PlugIn, DialogListener {
13 private static final String DISTANCE_KEY = "enlarger.distance";
14 private static final String USE_PIXELS_KEY = "enlarger.pixels";
15 private double defaultDistance = Prefs.get(DISTANCE_KEY, 15); // pixels
16 private boolean defaultUsePixels = Prefs.get(USE_PIXELS_KEY, false);
17 private Calibration cal;
18 private Label unitsLabel;
1219
1320 public void run(String arg) {
1421 ImagePlus imp = IJ.getImage();
2027 if (!imp.okToDeleteRoi())
2128 return;
2229 double n = showDialog(imp, defaultDistance);
23 if (n==Double.NaN)
24 return;
30 if (Double.isNaN(n))
31 return;
32 Prefs.set(DISTANCE_KEY, defaultDistance);
33 Prefs.set(USE_PIXELS_KEY, defaultUsePixels);
2534 Roi roi2 = Math.abs(n)<256?enlarge255(roi,n):enlarge(roi,n);
2635 if (roi2!=null) {
2736 imp.setRoi(roi2);
2837 Roi.setPreviousRoi(roi);
2938 defaultDistance = n;
3039 }
31 }
32
40 int pixels = (int)Math.round(n);
41 Recorder.recordCall("RoiEnlarger.enlarge(imp, "+pixels+");");
42 }
43
44 public static void enlarge(ImagePlus imp, int pixels) {
45 Roi roi = imp.getRoi();
46 if (roi==null || roi.isLine() || (roi instanceof PointRoi))
47 return;
48 Roi roi2 = Math.abs(pixels)<256?enlarge255(roi,pixels):enlarge(roi,pixels);
49 if (roi2!=null)
50 imp.setRoi(roi2);
51 }
52
3353 public double showDialog(ImagePlus imp, double pixels) {
34 Calibration cal = imp.getCalibration();
54 cal = imp.getCalibration();
3555 boolean scaled = cal.scaled();
36 boolean usePixels = false;
37 double n = pixels*cal.pixelWidth;
56 double pixelWidth = cal.pixelWidth;
57 boolean xyScaleDifferent = scaled && cal.pixelWidth != cal.pixelHeight;
58 boolean usePixels = defaultUsePixels;
59 double n = pixels;
3860 int decimalPlaces = 0;
39 if (Math.floor(n)!=n)
40 decimalPlaces = 2;
61 if (scaled && !usePixels) {
62 n *= pixelWidth;
63 decimalPlaces = getDecimalPlaces(pixelWidth, n);
64 }
4165 GenericDialog gd = new GenericDialog("Enlarge Selection");
42 gd.addNumericField("Enlarge by", n, decimalPlaces, 4, cal.getUnits());
66 gd.addNumericField("Enlarge by", n, decimalPlaces);
67 String units = scaled && !usePixels ? cal.getUnits()+" " : "pixels ";
68 gd.addToSameRow();
69 gd.addMessage(units.replace('\n', ' ')); //just in case of a newline character, which would make it a MultiLineLabel
70 unitsLabel = (Label)gd.getMessage();
4371 if (scaled) {
44 gd.setInsets(0, 20, 0);
72 gd.setInsets(0, 20, 0); //top left bottom
4573 gd.addCheckbox("Pixel units", usePixels);
4674 }
4775 gd.setInsets(10, 0, 0);
4876 gd.addMessage("Enter negative number to shrink", null, Color.darkGray);
77 if (xyScaleDifferent) {
78 gd.setInsets(5, 0, 0);
79 gd.addMessage(" \n ", null, Color.RED);
80 }
81 gd.addDialogListener(this);
82 if (xyScaleDifferent && Macro.getOptions()==null)
83 updateWarning(gd); //in interactive mode only
4984 gd.showDialog();
5085 if (gd.wasCanceled())
5186 return Double.NaN;
5287 n = gd.getNextNumber();
5388 if (scaled)
5489 usePixels = gd.getNextBoolean();
55 pixels = usePixels?n:n/cal.pixelWidth;
90 pixels = usePixels ? n : n/pixelWidth;
91 defaultDistance = pixels;
92 defaultUsePixels = usePixels;
5693 return pixels;
5794 }
58
95
96 public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
97 Vector checkboxes = gd.getCheckboxes();
98 Checkbox usePixelsCbx = checkboxes == null ? null : (Checkbox)checkboxes.get(0);
99 double n = gd.getNextNumber();
100 boolean usePixels = cal.scaled() ? gd.getNextBoolean() : true; //getNextBoolean also needed for macro recorded
101 if (e != null && e.getSource() == usePixelsCbx) {
102 double pixelWidth = cal.pixelWidth;
103 int decimalPlaces = 0;
104 if (usePixels) {
105 n /= pixelWidth; //scaled to pixels
106 } else {
107 n *= pixelWidth; //pixels to scaled
108 decimalPlaces = getDecimalPlaces(pixelWidth, n);
109 }
110 TextField numberField = (TextField)gd.getNumericFields().get(0);
111 numberField.setText(IJ.d2s(n, decimalPlaces));
112 if (unitsLabel != null) unitsLabel.setText(usePixels ? "pixels" : cal.getUnits());
113 boolean xyScaleDifferent = cal.scaled() && cal.pixelWidth != cal.pixelHeight;
114 if (xyScaleDifferent && usePixelsCbx != null) updateWarning(gd);
115 }
116 return !gd.invalidNumber();
117 }
118
119 private void updateWarning(GenericDialog gd) {
120 Checkbox usePixelsCbx = (Checkbox)gd.getCheckboxes().get(0);
121 MultiLineLabel warningLabel = (MultiLineLabel)gd.getMessage();
122 boolean showWarning = !usePixelsCbx.getState(); //warn if not pixels units
123 warningLabel.setText(showWarning ? "WARNING: x & y scales differ\nConversion to pixels uses x scale" : " \n ");
124 }
125
126 //decimal places for displaying the scaled enlarge/shrink value
127 private static int getDecimalPlaces(double pixelWidth, double number) {
128 if (number == (int)number || pixelWidth == 1) return 0;
129 int decimalPlaces = (int)(-Math.log10(pixelWidth)+1.9);
130 if (decimalPlaces < 0) decimalPlaces = 0;
131 if (decimalPlaces >9) decimalPlaces = 9;
132 return decimalPlaces;
133 }
134
59135 public static Roi enlarge(Roi roi, double pixels) {
60136 if (pixels==0)
61137 return roi;
85161 edm.setThreshold(0, n, ImageProcessor.NO_LUT_UPDATE);
86162 roi2 = (new ThresholdToSelection()).convert(edm);
87163 if (roi2==null)
88 return roi;
164 return roi;
89165 roi2.copyAttributes(roi);
90166 roi2.setLocation(bounds.x-n+xoffset, bounds.y-n+yoffset);
91167 if (roi.getStroke()!=null)
92168 roi2.setStroke(roi.getStroke());
93169 return roi2;
94170 }
95
171
96172 private static Roi enlargeRectOrOval(Roi roi, int n) {
97173 Rectangle bounds = roi.getBounds();
98174 bounds.x -= n;
109185 roi2.copyAttributes(roi);
110186 return roi2;
111187 }
112
188
113189 private static Roi shrink(Roi roi, int n) {
114190 Rectangle bounds = roi.getBounds();
115191 int width = bounds.width + 2;
119195 ip.setColor(255);
120196 ip.fill(roi);
121197 roi.setLocation(bounds.x, bounds.y);
122 FloatProcessor edm = new EDM().makeFloatEDM (ip, 0, false);
198 FloatProcessor edm = new EDM().makeFloatEDM (ip, 0, false);
123199 edm.setThreshold(n+1, Float.MAX_VALUE, ImageProcessor.NO_LUT_UPDATE);
124200 Roi roi2 = (new ThresholdToSelection()).convert(edm);
125201 if (roi2==null)
131207 roi2.setLocation(bounds.x+bounds2.x-1, bounds.y+bounds2.y-1);
132208 return roi2;
133209 }
134
210
135211 public static Roi enlarge255(Roi roi, double pixels) {
136212 if (pixels==0)
137213 return roi;
164240 ip.setThreshold(0, n, ImageProcessor.NO_LUT_UPDATE);
165241 roi2 = (new ThresholdToSelection()).convert(ip);
166242 if (roi2==null)
167 return roi;
243 return roi;
168244 roi2.copyAttributes(roi);
169245 roi2.setLocation(bounds.x-n+xoffset, bounds.y-n+yoffset);
170246 if (roi.getStroke()!=null)
171247 roi2.setStroke(roi.getStroke());
172248 return roi2;
173249 }
174
250
175251 private static Roi shrink255(Roi roi, int n) {
176252 Rectangle bounds = roi.getBounds();
177253 int width = bounds.width + 2;
2424 Zoom zoom = new Zoom();
2525 zoom.setZoom(imp, magnification, x, y);
2626 }
27
28 public static void in(ImagePlus imp) {
29 ImageCanvas ic = imp.getCanvas();
30 if (ic==null) return;
31 waitUntilActivated(imp);
32 int x = ic.screenX(imp.getWidth()/2);
33 int y = ic.screenY(imp.getHeight()/2);
34 ic.zoomIn(x, y);
35 if (ic.getMagnification()<=1.0)
36 imp.repaintWindow();
37 }
38
39 public static void out(ImagePlus imp) {
40 ImageCanvas ic = imp.getCanvas();
41 if (ic==null) return;
42 waitUntilActivated(imp);
43 int x = ic.screenX(imp.getWidth()/2);
44 int y = ic.screenY(imp.getHeight()/2);
45 ic.zoomOut(x, y);
46 if (ic.getMagnification()<=1.0)
47 imp.repaintWindow();
48 }
49
50 public static void unzoom(ImagePlus imp) {
51 ImageCanvas ic = imp.getCanvas();
52 if (ic!=null) {
53 waitUntilActivated(imp);
54 ic.unzoom();
55 }
56 }
57
58 public static void maximize(ImagePlus imp) {
59 ImageWindow win = imp.getWindow();
60 if (win!=null) {
61 waitUntilActivated(imp);
62 win.maximize();
63 IJ.wait(100);
64 }
65 }
66
67 private static void waitUntilActivated(ImagePlus imp) {
68 int count = 0;
69 boolean isCanvas = imp.getCanvas()!=null;
70 if (isCanvas) {
71 long t0 = System.currentTimeMillis();
72 while (!imp.windowActivated() && (System.currentTimeMillis()-t0)<=1000) {
73 IJ.wait(10);
74 count++;
75 }
76 }
77 if (IJ.debugMode)
78 IJ.log("Zoom: "+ count+" "+imp.windowActivated()+" "+isCanvas+" "+imp);
79 }
2780
2881 public void run(String arg) {
2982 ImagePlus imp = WindowManager.getCurrentImage();
30 if (imp==null)
31 {IJ.noImage(); return;}
83 if (imp==null) {
84 IJ.noImage();
85 return;
86 }
3287 ImageCanvas ic = imp.getCanvas();
3388 if (ic==null) return;
3489 if (ic instanceof PlotCanvas && !((PlotCanvas)ic).isFrozen()) {
4499 int x = ic.screenX(loc.x);
45100 int y = ic.screenY(loc.y);
46101 if (arg.equals("in")) {
47 ic.zoomIn(x, y);
48 if (ic.getMagnification()<=1.0) imp.repaintWindow();
102 waitUntilActivated(imp);
103 ic.zoomIn(x, y);
104 if (ic.getMagnification()<=1.0)
105 imp.repaintWindow();
106 Recorder.recordCall("Zoom.in(imp);");
49107 } else if (arg.equals("out")) {
108 waitUntilActivated(imp);
50109 ic.zoomOut(x, y);
51 if (ic.getMagnification()<1.0) imp.repaintWindow();
52 } else if (arg.equals("orig"))
53 ic.unzoom();
54 else if (arg.equals("100%"))
110 if (ic.getMagnification()<1.0)
111 imp.repaintWindow();
112 Recorder.recordCall("Zoom.out(imp);");
113 } else if (arg.equals("orig")) {
114 unzoom(imp);
115 Recorder.recordCall("Zoom.unzoom(imp);");
116 } else if (arg.equals("100%")) {
117 waitUntilActivated(imp);
55118 ic.zoom100Percent();
56 else if (arg.equals("to")) {
119 } else if (arg.equals("to")) {
57120 zoomToSelection(imp, ic);
58121 Recorder.recordCall("Zoom.toSelection(imp);");
59 } else if (arg.equals("set"))
122 } else if (arg.equals("set")) {
60123 setZoom(imp, -1, -1, -1);
61 else if (arg.equals("max")) {
62 ImageWindow win = imp.getWindow();
63 if (win!=null) {
64 win.maximize();
65 IJ.wait(100);
66 }
124 } else if (arg.equals("max")) {
125 maximize(imp);
126 Recorder.recordCall("Zoom.maximize(imp);");
67127 } else if (arg.equals("scale"))
68128 scaleToFit(imp);
69129 }
70130
71131 void zoomToSelection(ImagePlus imp, ImageCanvas ic) {
132 waitUntilActivated(imp);
72133 Roi roi = imp.getRoi();
73134 ic.unzoom();
74135 if (roi==null) return;
80141 int x = r.x+r.width/2;
81142 int y = r.y+r.height/2;
82143 mag = ic.getHigherZoomLevel(mag);
83 while(r.width*mag<w.width - marginw && r.height*mag<w.height - marginh) {
144 while (r.width*mag<w.width-marginw && r.height*mag<w.height-marginh) {
84145 ic.zoomIn(ic.screenX(x), ic.screenY(y));
85146 double cmag = ic.getMagnification();
86147 if (cmag==32.0) break;
92153 /** Based on Albert Cardona's ZoomExact plugin:
93154 http://albert.rierol.net/software.html */
94155 void setZoom(ImagePlus imp, double mag, int x, int y) {
156 waitUntilActivated(imp);
95157 ImageCanvas ic = imp.getCanvas();
96158 if (ic==null)
97159 return;
155217 int canvasHeight = (int)(srcHeight*mag+insets.top+insets.bottom+ImageWindow.VGAP*2+win.getSliderHeight());
156218 ic.setSourceRect(new Rectangle(x-srcWidth/2,y-srcHeight/2,srcWidth,srcHeight));
157219 ic.setMagnification(mag);
220 ic.setSize(new Dimension((int)(srcWidth*mag), (int)(srcHeight*mag)));
158221 win.setSize(canvasWidth, canvasHeight);
159222 return;
160223 }
193256 }
194257
195258 private void scaleToFit(ImagePlus imp) {
259 waitUntilActivated(imp);
196260 ImageCanvas ic = imp.getCanvas();
197261 if (ic==null)
198262 return;
7676 }
7777
7878 public void clear(ImageProcessor ip) {
79 ip.setColor(Toolbar.getBackgroundColor());
79 ip.setGlobalBackgroundColor();
8080 if (isLineSelection()) {
8181 if (isStraightLine() && roi.getStrokeWidth()>1)
8282 ip.fillPolygon(roi.getPolygon());
8686 ((TextRoi)roi).clear(ip);
8787 else
8888 ip.fill(); // fill with background color
89 ip.setColor(Toolbar.getForegroundColor());
89 ip.setGlobalForegroundColor();
9090 }
9191
9292 /**
9595 */
9696 public void fill(ImageProcessor ip) {
9797 if (!IJ.isMacro() || !ip.fillValueSet())
98 ip.setColor(Toolbar.getForegroundColor());
98 ip.setGlobalForegroundColor();
9999 if (isLineSelection()) {
100100 if (isStraightLine() && roi.getStrokeWidth()>1 && !(roi instanceof Arrow)) {
101101 Roi roi2=Roi.convertLineToArea(roi);
113113 * replaced by ImageProcessor.draw(Roi)
114114 */
115115 public void draw(ImageProcessor ip) {
116 ip.setColor(Toolbar.getForegroundColor());
116 ip.setGlobalForegroundColor();
117117 roi.drawPixels(ip);
118118 if (IJ.altKeyDown())
119119 drawLabel(ip);
215215 Rectangle r = ip.getRoi();
216216 if (mask==null)
217217 makeMask(ip, r);
218 ip.setColor(Toolbar.getBackgroundColor());
218 ip.setGlobalBackgroundColor();
219219 int stackSize = imp.getStackSize();
220220 if (stackSize>1)
221221 ip.snapshot();
233233 ip.fill();
234234 ip.setRoi(r); // restore original ROI
235235 if (sliceCount==stackSize) {
236 ip.setColor(Toolbar.getForegroundColor());
236 ip.setGlobalForegroundColor();
237237 Roi roi = imp.getRoi();
238238 imp.deleteRoi();
239239 imp.updateAndDraw();
10321032 overlay.add(roi2);
10331033 } else {
10341034 Rectangle r = roi.getBounds();
1035 int nPoints = ((PolygonRoi)roi).getNCoordinates();
1036 int[] xp = ((PolygonRoi)roi).getXCoordinates();
1037 int[] yp = ((PolygonRoi)roi).getYCoordinates();
1038 int x=r.x, y=r.y;
10391035 if (!inSituShow)
10401036 ip.setValue(0.0);
1041 ip.moveTo(x+xp[0], y+yp[0]);
1042 for (int i=1; i<nPoints; i++)
1043 ip.lineTo(x+xp[i], y+yp[i]);
1044 ip.lineTo(x+xp[0], y+yp[0]);
1037 if (roi instanceof PolygonRoi) {
1038 int nPoints = ((PolygonRoi)roi).getNCoordinates();
1039 int[] xp = ((PolygonRoi)roi).getXCoordinates();
1040 int[] yp = ((PolygonRoi)roi).getYCoordinates();
1041 int x=r.x, y=r.y;
1042 ip.moveTo(x+xp[0], y+yp[0]);
1043 for (int i=1; i<nPoints; i++)
1044 ip.lineTo(x+xp[i], y+yp[i]);
1045 ip.lineTo(x+xp[0], y+yp[0]);
1046 } else
1047 roi.drawPixels(ip);
10451048 if (showChoice!=BARE_OUTLINES) {
10461049 String s = ResultsTable.d2s(count,0);
10471050 ip.moveTo(r.x+r.width/2-ip.getStringWidth(s)/2, r.y+r.height/2+fontSize/2);
105105 ((ExtendedPlugInFilter)theFilter).setNPasses(nPasses);
106106 if ((flags&PlugInFilter.NO_CHANGES)==0) { // for filters modifying the image
107107 boolean disableUndo = Prefs.disableUndo || (flags&PlugInFilter.NO_UNDO)!=0;
108 if (!disableUndo) {
108 if (!disableUndo || ((ip instanceof ColorProcessor)&&WindowManager.getWindow("B&C")!=null)) {
109109 ip.snapshot();
110110 snapshotPixels = ip.getSnapshotPixels();
111111 }
2222 private String[] methods = ImageProcessor.getInterpolationMethods();
2323 private static int interpolationMethod = ImageProcessor.BILINEAR;
2424 private Overlay overlay;
25 private boolean done;
2526
2627 public int setup(String arg, ImagePlus imp) {
2728 this.imp = imp;
8081 imp.updateAndDraw();
8182 Undo.setup(Undo.COMPOUND_FILTER_DONE, imp);
8283 }
84 if (done) { // remove grid
85 Overlay ovly = imp.getOverlay();
86 if (ovly!=null) {
87 ovly.remove(GRID);
88 if (ovly.size()==0) imp.setOverlay(null);
89 }
90 }
8391 }
8492
8593 void enlargeCanvas() {
8694 imp.unlock();
87 IJ.run("Select All");
88 IJ.run("Rotate...", "angle="+angle);
95 IJ.run(imp, "Select All", "");
96 IJ.run(imp, "Rotate...", "angle="+angle);
8997 Roi roi = imp.getRoi();
9098 Rectangle r = roi.getBounds();
9199 if (r.width<imp.getWidth()) r.width = imp.getWidth();
93101 IJ.showStatus("Rotate: Enlarging...");
94102 if (imp.getStackSize()==1)
95103 Undo.setup(Undo.COMPOUND_FILTER, imp);
96 IJ.run("Canvas Size...", "width="+r.width+" height="+r.height+" position=Center "+(fillWithBackground?"":"zero"));
104 IJ.run(imp, "Canvas Size...", "width="+r.width+" height="+r.height+" position=Center "+(fillWithBackground?"":"zero"));
97105 IJ.showStatus("Rotating...");
98106 }
99107
100108 void drawGridLines(int lines) {
101 //if (overlay.size()>0 && GRID.equals(overlay.get(0).getName()))
102 // overlay.remove(0);
109 if (overlay==null)
110 return;
103111 overlay.remove(GRID);
104112 if (lines==0)
105113 return;
153161 return DONE;
154162 }
155163 Overlay ovly = imp.getOverlay();
156 if (ovly!=null) ovly.remove(GRID);
157 if (!enlarge)
164 if (ovly!=null) {
165 ovly.remove(GRID);
166 if (ovly.size()==0) imp.setOverlay(null);
167 }
168 if (enlarge)
169 flags |= NO_CHANGES; // undoable as a "compound filter"
170 else if (imp.getStackSize()==1)
158171 flags |= KEEP_PREVIEW; // standard filter without enlarge
159 else if (imp.getStackSize()==1)
160 flags |= NO_CHANGES; // undoable as a "compound filter"
172 done = true;
161173 return IJ.setupDialog(imp, flags);
162174 }
163175
704704 //IJ.log("restore: "+roi.getPosition()+" "+roi.getZPosition()+" "+imp.getNSlices()+" "+imp.getStackSize());
705705 if (setSlice) {
706706 boolean hyperstack = imp.isHyperStack();
707 int position = roi.getPosition();
707708 if (hyperstack && roi.hasHyperStackPosition())
708709 imp.setPosition(roi.getCPosition(), roi.getZPosition(), roi.getTPosition());
710 else if (hyperstack && imp.getNSlices()==1)
711 imp.setPosition(imp.getChannel(), 1, position);
712 else if (hyperstack)
713 imp.setPosition(imp.getChannel(), position, imp.getChannel());
709714 else if (roi.getZPosition()>0 && imp.getNSlices()==imp.getStackSize())
710 imp.setSlice(roi.getZPosition());
711 else if (roi.getPosition()>0 && roi.getPosition()<=imp.getStackSize())
712 imp.setSlice(roi.getPosition());
715 imp.setSlice(roi.getZPosition());
716 else if (position>0 && position<=imp.getStackSize())
717 imp.setSlice(position);
713718 else {
714719 String label = (String)listModel.getElementAt(index);
715720 int n = getSliceNumber(roi, label);
429429
430430 /** Returns the background fill value. */
431431 public abstract double getBackgroundValue();
432
433 /** Sets the global (Color Picker) foreground color
434 * as the fill/draw color.
435 * @see ij.gui.Toolbar#setForegroundColor(Color)
436 * @see ij.gui.Toolbar#setForegroundValue(double)
437 */
438 public void setGlobalForegroundColor() {
439 double value = Toolbar.getForegroundValue();
440 if (Double.isNaN(value))
441 setColor(Toolbar.getForegroundColor());
442 else
443 setValue(value);
444 }
445
446 /** Sets the global (Color Picker) background color
447 * as the fill/draw color.
448 * @see ij.gui.Toolbar#setBackgroundColor(Color)
449 * @see ij.gui.Toolbar#setBackgroundValue(double)
450 */
451 public void setGlobalBackgroundColor() {
452 double value = Toolbar.getBackgroundValue();
453 if (Double.isNaN(value))
454 setColor(Toolbar.getBackgroundColor());
455 else
456 setValue(value);
457 }
432458
433459 /** Returns the smallest displayed pixel value. */
434460 public abstract double getMin();
0 package ij.text;
1
2 /** Plugins that implement this interface are notified when
3 a table is opened, closed or updated. The
4 Plugins/Utilities/Monitor Events command uses this interface.
5 */
6 public interface TableListener {
7
8 public void TableUpdated(TextPanel table, String event, int row);
9
10 }
44 import java.io.*;
55 import java.util.Comparator;
66 import java.nio.channels.FileChannel;
7 import java.nio.file.*;
8 import java.security.MessageDigest;
9
710
811 /** This class contains static utility methods. */
912 public class Tools {
417420 default: return c;
418421 }
419422 }
423
424 /** Returns the checksum of a string or file, or "0" if no success.
425 The 'method' argument must be "MD5" or "SHA-256".
426 */
427 public static String getHash(String method, boolean fromFile, String pathOrString) {
428 method = method.toUpperCase();
429 boolean md5 = method.contains("MD5");
430 boolean sha_256 = method.contains("SHA-256");
431 try {
432 MessageDigest digest = null;
433 if (md5)
434 digest = MessageDigest.getInstance("MD5");
435 else if(sha_256)
436 digest = MessageDigest.getInstance("SHA-256");
437 else
438 return "0";
439 Path path = Paths.get(pathOrString);
440 byte[] encodedhash;
441 if (fromFile)
442 encodedhash = digest.digest(Files.readAllBytes(path));
443 else
444 encodedhash = digest.digest(pathOrString.getBytes());
445
446 return bytesToHex(encodedhash);
447
448 } catch (Exception e) {}
449 return "0";
450 }
451
452 private static String bytesToHex(byte[] hash) {
453 StringBuilder hexString = new StringBuilder(2 * hash.length);
454 for (int i = 0; i < hash.length; i++) {
455 String hex = Integer.toHexString(0xff & hash[i]);
456 if (hex.length() == 1) {
457 hexString.append('0');
458 }
459 hexString.append(hex);
460 }
461 return hexString.toString();
462 }
420463
421464 }
33 <title>Release Notes</title>
44 </head>
55 <body>
6
7 <li> <u>1.53j 13 May 2021</u>
8 <ul>
9 <li> Thanks to 'VolkerH', the table created by
10 <i>Image&gt;Overlay&gt;List Elements</i> now
11 displays row numbers and arrow selection 'X' and 'Y'
12 values are the coordinates of the arrow tip.
13 <li> Thanks to Stein Rorvik, added the Color.setForegroundValue()
14 and Color.setBackgroundValue() macro functions and the
15 Toolbar.setForegroundValue(), Toolbar.setBackgroundValue(),
16 ImageProcessor.setGlobalForegroundColor() and
17 ImageProcessor.setGlobalBackgroundColor() methods.
18 <li> Thanks to Norbert Vischer, added the IJ.checksum() macro
19 function, which returns the MD5 (or SHA-256) checksum from
20 a string or file
21 (<a href="http://wsr.imagej.net/macros/ChecksumTest.txt">example</a>).
22 <li> Thanks to Michael Schmid, added the
23 Fit.doWeightedFit(equation,x,y,weights[,initialGuesses])
24 macro function.
25 <li> Thanks to Norbert Vischer, added the Plot.removeNaNs macro function.
26 <li> Thanks to Laurent Thomas, added support for scrollbars in
27 GenericDialog TextAreas.
28 <li> Thanks to Fred Damen, added the Zoom.in(imp), Zoom.out(imp),
29 Zoom.unzoom(imp) and Zoom.maximize(imp) methods.
30 <li> Thanks to John Dunsmuir, added the PointRoi.addPoint(x,y,position) method.
31 <li> Thanks to Fred Damen, fixed bugs that caused programmatic image
32 window zooming to not work reliably
33 (<a href="http://wsr.imagej.net/macros/js/ZoomTest.js">example</a>).
34 <li> Thanks to Michael Schmid, fixed a bug with HTMLDialogs that
35 caused the initial scroll position to be at the end when displaying
36 more text than what fits in the window.
37 <li> Thanks to 'Sethur', fixed bugs that caused DICOM
38 files using newer VRs (from 2014 and later), such as
39 UC and UR, to fail.
40 <li> Thanks to Bruno Vellutini, fixed a bug that caused images rotated
41 interactively using the "Enlarge image" and "Preview" options to not
42 have the grid lines removed after the rotation.
43 <li> Thanks to Jerome Mutterer, fixed a bug that caused the
44 Prefs.savePreferences() method to throw a null pointer
45 exception if the "ImageJ" window was not open.
46 <li> Thanks to Stein Rorvik, fixed a bug that caused the slice
47 label to be incorrect after importing an image sequence and
48 "Start" was greater than 1 and "Count" was 1.
49 <li> Thanks to Stein Rorvik, fixed a bug that caused
50 the <i>Images to Stack</i> command to ignore slice labels
51 when the "Use titles as labels" option was not enabled.
52 <li> Thanks to 'ghf', worked around a Fiji bug that caused the
53 <i>File&gt;Import&gt;Image Sequence</i> command to fail
54 if the folder contained a ".h5" file.
55 <li> Thanks to Jerome Mutterer, fixed bugs that caused the
56 Stack.setDisplayMode(), Stack.setSlice(), Stack.setFrame()
57 and Stack.setPosition() macro functions to not work as expected
58 in batch mode, and the ImagePlus.setDisplayMode(),
59 ImagePlus.setZ(), ImagePlus.setSetT() and
60 ImagePlus.setPosition() methods to not work as expected when
61 the image was not displayed.
62 <li> Thanks to Nicolas Montes, fixed a bug that caused the
63 particle analyzer to throw an exception when both the
64 "Composite ROIs" and "Show: Outlines" options where used.
65 <li> Thanks to Christian Kremser, fixed a 1.53i regression
66 that caused macro statements like "n=Dialog.getNumber()+1"
67 to generate and error.
68 <li> Thanks to Christian Tischer, fixed a regression that
69 caused the ROI Manager to not set the hyperstack position
70 of ROIs without a c,z,t position.
71
72 </ul>
673
774 <li> <u>1.53i 24 March 2021</u>
875 <ul>
1481 is displayed in the status bar. The total number of lines is
1582 displayed after <i>Select All</i>.
1683 <li> Thanks to Norbert Vischer, ImageJ now corrects the orientation of
17 phone camera photos. This does not work on Fiji because it is
84 phone camera photos. Does not work on Fiji because it is
1885 missing Exif_Reader.jar.
1986 <li> Improved the Plugins>Utilities>Benchmark command. It now
2087 suppresses subordinate status bar messages and displays
2491 in the Log window if it was not called from a macro and a
2592 threshold was not set.
2693 <li> Thanks to Laurent Thomas, <i>File&gt;Save As&gt;Image Sequence</i>,
27 with "Use slice labels as names" enabled, now supports file names as
94 when "Use slice labels as names" is enabled, now supports file names as
2895 long as 111 characters, excluding the extension.
29 <li> Thanks to Michael Schmid, ImageJ displays “horizontal” in the
30 image info line of column average plots and “vertical” for
96 <li> Thanks to Michael Schmid, ImageJ displays "horizontal" in the
97 image info line of column average plots and "vertical" with
3198 row average plots.
3299 <li> Thanks to Jerome Mutterer, added the showStatus(message,options)
33100 macro function and the IJ.showStatus(message,options) method
34101 (<a href="http://wsr.imagej.net/macros/FlashingStatusMessages.txt">example</a>).
35 <li> Added the Overlay.update(index) macro function. DOCUMENT
102 <li> Added the Overlay.update(index) macro function.
36103 <li> Added the ImagePlus.setBorderColor() method,
37104 used by <i>Image&gt;Color&gt;Split Channels</i> to
38105 colorize image borders.
41108 methods.
42109 <li> Thanks to Herbie Gluender, fixed a bug that caused the status bar
43110 to stop being updated after activating an overlay selection.
44 <li> Thanks to Fred Damen, fixed a bug with one slice stacks where the slice label
45 is not displayed on the image window info line or in the <i>Image&gt;Show Info</i>
46 window.
111 <li> Thanks to Fred Damen, fixed a bug with one slice stacks that caused the
112 slice label to not be displayed on the image info line or in the
113 <i>Image&gt;Show Info</i> window.
47114 <li> Thanks to Antoneta, fixed a bug with the <i>Flatten</i> command that caused
48115 multi-point selections on stacks to lose counter information.
49116 <li> Thanks to Herbie Gluender, fixed a bug that caused unexpected overlay
63130 WaitForUserDialogs to not be scaled on high-resolution
64131 screens.
65132 <li> Thanks to Stein Rorvik, fixed a macro interpreter bug that caused
66 if statements using built in string functions to fail
133 if statements using string functions to sometimes fail
67134 (e.g., "if (getTitle.length>10) ...").
68135 <li> Thanks to Norbert Vischer, fixed a bug that caused the
69136 first column of tables copied to the clipboard to be missing
74141 the "Properties..." command in the ROI Manager to not work as
75142 expected when changing the stroke color.
76143 <li> Thanks to Stein Rorvik, fixed a 1.53i regression that caused
77 the str.trim() macro function to fail.
144 the str.trim() macro function to sometimes fail.
78145 </ul>
79146
80147 <li> <u>1.53h 04 February 2021</u>