001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 *  image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause 
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 
006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 
007 * Visit http://imagingbook.com for additional details.
008 *******************************************************************************/
009
010package imagingbook.lib.ij;
011
012import ij.ImagePlus;
013import ij.WindowManager;
014import ij.gui.GenericDialog;
015import ij.io.OpenDialog;
016import ij.process.ColorProcessor;
017import ij.process.FloatProcessor;
018import ij.process.ImageProcessor;
019
020import java.util.Arrays;
021import java.util.Comparator;
022import java.util.LinkedList;
023import java.util.List;
024
025
026public abstract class IjUtils {
027        
028        /**
029         * Returns a (possibly empty) array of ImagePlus objects that are
030         * sorted by their titles if the 'sortByTitle' flag is set.
031         * 
032         * @param sortByTitle flag, result is sorted if true.
033         * @return an array of currently open images.
034         */
035        public static ImagePlus[] getOpenImages(boolean sortByTitle) {
036                return getOpenImages(sortByTitle, null);
037        }
038        
039
040        /**
041         * Returns an array of strings containing the short titles
042         * of the images supplied.
043         * 
044         * @param images array of images.
045         * @return array of names.
046         */
047        public static String[] getImageShortTitles(ImagePlus[] images) {
048                String[] imageNames = new String[images.length];
049                for (int i = 0; i < images.length; i++) {
050                        imageNames[i] = images[i].getShortTitle();
051                }
052                return imageNames;
053        }
054        
055        /**
056         * Opens a dialog to let the user select one of the currently open images.
057         * @param title string to show in the dialog
058         * @return An ImagePlus object, use the getProcessor method to obtain the associated ImageProcessor
059         */
060        public static ImagePlus selectOpenImage(String title) {
061                ImagePlus[] openImages = getOpenImages(true, null);
062                String[] imageNames = getImageShortTitles(openImages);
063                if (title == null) {
064                        title = "image:";
065                }
066                GenericDialog gd = new GenericDialog("Select image");
067                gd.addChoice(title, imageNames, imageNames[0]);
068                gd.showDialog(); 
069                if (gd.wasCanceled()) 
070                        return null;
071                else {
072                        return openImages[gd.getNextChoiceIndex()];
073                }
074        }
075        
076        
077        /**
078         * Returns a (possibly empty) array of {@link ImagePlus} objects that are
079         * sorted by their titles if the sortByTitle flag is set.
080         * The image "exclude" (typically the current image) is not included 
081         * in the returned array (pass null to exclude no image).
082         * 
083         * @param sortByTitle set {@code true} to return images sorted by title
084         * @param exclude reference to an image to be excluded (may be {@code null})
085         * @return a (possibly empty) array of {@link ImagePlus} objects
086         */
087        public static ImagePlus[] getOpenImages(boolean sortByTitle, ImagePlus exclude) {
088                List<ImagePlus> imgList = new LinkedList<ImagePlus>();
089                int[] wList = WindowManager.getIDList();
090        if (wList != null) {
091                for (int i : wList) {
092                    ImagePlus imp = WindowManager.getImage(i);
093                    if (imp != null && imp != exclude) {
094                        imgList.add(imp);
095                    }
096                }
097        }
098        ImagePlus[] impArr = imgList.toArray(new ImagePlus[0]);
099        if (sortByTitle) {
100                Comparator<ImagePlus> cmp = new Comparator<ImagePlus>() {
101                        public int compare(ImagePlus impA, ImagePlus impB) {
102                                return impA.getTitle().compareTo(impB.getTitle());
103                        }
104                };
105                Arrays.sort(impArr, cmp);
106        }
107                return impArr;
108        }
109        
110
111        /**
112         *  Queries the user for an arbitrary file to be opened.
113         *  
114         * @param title string to be shown in the interaction window.
115         * @return path of the selected resource.
116         */
117        public static String askForOpenPath(String title) {
118                OpenDialog od = new OpenDialog(title, "");
119                String dir = od.getDirectory();
120                String name = od.getFileName();
121                if (name == null)
122                        return null;
123                return encodeURL(dir + name);
124        }
125        
126        private static String encodeURL(String url) {
127                //url = url.replaceAll(" ","%20");      // this doesn't work with spaces
128                url = url.replace('\\','/');
129                return url;
130        }
131        
132        //----------------------------------------------------------------------
133        
134
135        /**
136         * Creates an ImageJ {@link ImagePlus} image for the matrix {@code M[r][c]} (2D array),
137         * where {@code r} is treated as the row (vertical) coordinate and
138         * {@code c} is treated as the column (horizontal) coordinate.
139         * Use {@code show()} to display the resulting image.
140         * 
141         * @param title image title
142         * @param M 2D array
143         * @return a new {@link ImagePlus} image
144         */
145        public static ImagePlus createImage(String title, float[][] M) {
146                FloatProcessor fp = new FloatProcessor(M[0].length, M.length);
147                for (int u = 0; u < M[0].length; u++) {
148                        for (int v = 0; v < M.length; v++) {
149                                fp.setf(u, v, M[v][u]);
150                        }
151                }
152                return new ImagePlus(title, fp);
153        }
154        
155
156        /**
157         * Creates an ImageJ {@link ImagePlus} image for the matrix {@code M[r][c]} (2D array),
158         * where {@code r} is treated as the row (vertical) coordinate and
159         * {@code c} is treated as the column (horizontal) coordinate.
160         * Use {@code show()} to display the resulting image.
161         * 
162         * @param title the image title
163         * @param M a 2D array holding the image data
164         * @return a new {@link ImagePlus} instance
165         */
166        public static ImagePlus createImage(String title, double[][] M) {
167                FloatProcessor fp = new FloatProcessor(M[0].length, M.length);
168                for (int u = 0; u < M[0].length; u++) {
169                        for (int v = 0; v < M.length; v++) {
170                                fp.setf(u, v, (float) M[v][u]);
171                        }
172                }
173                return new ImagePlus(title, fp);
174        }
175        
176        /**
177         * Sets the weighing factors for the color components used
178         * in RGB-to-grayscale conversion for the specified image {@code ip}.
179         * Note that this method can be applied to any {@link ImageProcessor}
180         * instance but has no effect unless {@code ip} is of type
181         * {@link ColorProcessor}. Applies standard (ITU-709) weights.
182         * 
183         * @param ip The affected image
184         */
185        public static void setRgbConversionWeights(ImageProcessor ip) {
186                setRgbConversionWeights(ip, 0.299, 0.587, 0.114);
187        }
188        
189        /**
190         * Sets the weighing factors for the color components used
191         * in RGB-to-grayscale conversion for the specified image {@code ip}.
192         * Note that this method can be applied to any {@link ImageProcessor}
193         * instance but has no effect unless {@code ip} is of type
194         * {@link ColorProcessor}.
195         * 
196         * @param ip The affected image
197         * @param wr Red weight
198         * @param wg Green weight
199         * @param wb Blue weight
200         */
201        public static void setRgbConversionWeights(ImageProcessor ip, double wr, double wg, double wb) {
202                if (ip instanceof ColorProcessor) {
203                        ((ColorProcessor) ip).setRGBWeights(wr, wg, wb);
204                }
205        }
206
207}