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.IJ;
013import ij.process.ImageProcessor;
014import ij.process.LUT;
015
016import java.awt.Color;
017import java.awt.image.ColorModel;
018import java.awt.image.IndexColorModel;
019
020
021/**
022 * This class holds utility methods for lookup-tables and implementations
023 * of various standard ImageJ lookup tables (originally defined in class
024 * {@link ij.plugin.LutLoader}.
025 * 
026 * @author WB
027 * @version 2016/12/19
028 */
029public abstract class LookupTables {
030        
031        /**
032         * Create a new lookup-table from three RGB arrays of length 256.
033         * @param r Red component values.
034         * @param g Green component values.
035         * @param b Blue component values.
036         * @return A new instance of type {@link ij.process.LUT}.
037         */
038        public static LUT create(byte[] r, byte[] g, byte[] b) {
039                if (r.length != 256 || g.length != 256 || b.length != 256) {
040                        throw new IllegalArgumentException("Component arrays must be of length 256");
041                }
042                return new LUT(r, g, b);
043        }
044
045
046        /**
047         * ImageJ's 'fire' LUT, as originally defined in class {@link ij.plugin.LutLoader}.
048         * @return A new instance of type {@link ij.process.LUT}.
049         */
050        public static LUT fire() {
051                int[] r = { 0, 0, 1, 25, 49, 73, 98, 122, 146, 162, 173, 184, 195, 207, 217, 229, 240, 252,
052                                255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
053                int[] g = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 35, 57, 79, 101, 117, 133, 147, 161,
054                                175, 190, 205, 219, 234, 248, 255, 255, 255, 255 };
055                int[] b = { 0, 61, 96, 130, 165, 192, 220, 227, 210, 181, 151, 122, 93, 64, 35, 5, 0, 0, 0, 0,
056                                0, 0, 0, 0, 0, 0, 0, 35, 98, 160, 223, 255 };
057
058                return create(interpolateTo256(r), interpolateTo256(g), interpolateTo256(b));
059        }
060
061
062        /**
063         * ImageJ's 'grays' LUT, as originally defined in class {@link ij.plugin.LutLoader}.
064         * @return A new instance of type {@link ij.process.LUT}.
065         */
066        public static LUT grays() {
067                byte[] r = new byte[256];
068                byte[] g = new byte[256];
069                byte[] b = new byte[256];
070                for (int i = 0; i < r.length; i++) {
071                        r[i] = (byte) i;
072                        g[i] = (byte) i;
073                        b[i] = (byte) i;
074                }
075                return create(r, g, b);
076        }
077
078        /**
079         * ImageJ's 'ice' LUT, as originally defined in class {@link ij.plugin.LutLoader}.
080         * @return A new instance of type {@link ij.process.LUT}.
081         */
082        public static LUT ice() {
083                int[] r = { 0, 0, 0, 0, 0, 0, 19, 29, 50, 48, 79, 112, 134, 158, 186, 201, 217, 229, 242, 250, 250, 250, 250,
084                                251, 250, 250, 250, 250, 251, 251, 243, 230 };
085                int[] g = { 156, 165, 176, 184, 190, 196, 193, 184, 171, 162, 146, 125, 107, 93, 81, 87, 92, 97, 95, 93, 93, 90,
086                                85, 69, 64, 54, 47, 35, 19, 0, 4, 0 };
087                int[] b = { 140, 147, 158, 166, 170, 176, 209, 220, 234, 225, 236, 246, 250, 251, 250, 250, 245, 230, 230, 222,
088                                202, 180, 163, 142, 123, 114, 106, 94, 84, 64, 26, 27 };
089
090                return new LUT(interpolateTo256(r), interpolateTo256(g), interpolateTo256(b));
091        }
092
093        /**
094         * ImageJ's 'spectrum' LUT, as originally defined in class {@link ij.plugin.LutLoader}.
095         * @return A new instance of type {@link ij.process.LUT}.
096         */
097        public static LUT spectrum() {
098                byte[] r = new byte[256];
099                byte[] g = new byte[256];
100                byte[] b = new byte[256];
101                for (int i = 0; i < r.length; i++) {
102                        Color c = Color.getHSBColor(i/255f, 1.0f, 1.0f);
103                        r[i] = (byte) c.getRed();
104                        g[i] = (byte) c.getGreen();
105                        b[i] = (byte) c.getBlue();
106                }
107                return new LUT(r, g, b);
108        }
109
110        /**
111         * ImageJ's 'rgb332' LUT, as originally defined in class {@link ij.plugin.LutLoader}.
112         * @return A new instance of type {@link ij.process.LUT}.
113         */
114        public static LUT rgb332() {
115                byte[] r = new byte[256];
116                byte[] g = new byte[256];
117                byte[] b = new byte[256];
118                for (int i = 0; i < r.length; i++) {
119                        r[i] = (byte) (i & 0xE0);
120                        g[i] = (byte) ((i << 3) & 0xE0);
121                        b[i] = (byte) ((i << 6) & 0xC0);
122                }
123                return new LUT(r, g, b);
124        }
125        
126        /**
127         * ImageJ's 'redgreen' LUT, as originally defined in class {@link ij.plugin.LutLoader}.
128         * @return A new instance of type {@link ij.process.LUT}.
129         */
130        public static LUT redgreen() {
131                byte[] r = new byte[256];
132                byte[] g = new byte[256];
133                byte[] b = new byte[256];
134                for (int i = 0; i < 128; i++) {
135                        r[i] = (byte) (i * 2);
136                        g[i] = (byte) 0;
137                        b[i] = (byte) 0;
138                }
139                for (int i = 128; i < 256; i++) {
140                        r[i] = (byte) 0;
141                        g[i] = (byte) (i * 2);
142                        b[i] = (byte) 0;
143                }
144
145                return new LUT(r, g, b);
146        }
147
148        // --------------------------------------------------------------
149
150        private static byte[] interpolateTo256(int[] samples) {
151                final int nColors = 256;
152                int nSamples = samples.length;
153                byte[] component = new byte[nColors];
154                double scale = (double) nSamples / nColors;
155                for (int i = 0; i < component.length; i++) {
156                        int i1 = (int) Math.floor(i * scale);
157                        int i2 = i1 + 1;
158                        if (i2 >= nSamples)
159                                i2 = nSamples - 1;
160                        double frac = i * scale - i1;   // frac is in [0,1]
161                        int val = (int) Math.round((1.0 - frac) * samples[i1] + frac * samples[i2]);
162                        if (val < 0)
163                                val = 0;
164                        else if (val > 255)
165                                val = 255;
166                        component[i] = (byte) val;
167                        //component[i] = (byte) ((1.0 - frac) * (samples[i1] & 0xFF) + frac * (samples[i2] & 0xFF));
168                }
169                return component;
170        }
171        
172        // ----------------------------------------------------------------------
173        
174        /**
175         * Lists the contents of the lookup-table currently associated
176         * with the specified image.
177         * 
178         * @param ip The image.
179         */
180        public static void listCurrentLut(ImageProcessor ip) {
181                ColorModel cm = ip.getCurrentColorModel();
182                IndexColorModel icm = (IndexColorModel) cm;
183                int mapSize = icm.getMapSize();
184                byte[] reds = new byte[mapSize];
185                byte[] grns = new byte[mapSize];
186                byte[] blus = new byte[mapSize];
187                icm.getReds(reds);
188                icm.getGreens(grns);
189                icm.getBlues(blus);
190                for (int i = 0; i < mapSize; i++) {
191                        IJ.log(String.format("%3d: %3d %3d %3d", i, reds[i] & 0xFF, grns[i] & 0xFF, blus[i] & 0xFF));
192                }
193        }
194        
195        
196        /**
197         * Modifies the lookup table to display a bright image with gray values
198         * in the range minGray ... 255. Does nothing if ip is of type
199         * ColorProcessor.
200         * 
201         * @param ip The target image.
202         * @param minGray Minimum gray value.
203         */
204        public static void brightLut(ImageProcessor ip, int minGray) {
205                if (minGray < 0 || minGray >= 255)
206                        return;
207                ColorModel cm = ip.getColorModel();
208                if (!(cm instanceof IndexColorModel))
209                        return;
210                IndexColorModel icm = (IndexColorModel) cm;
211                int mapSize = icm.getMapSize();
212                byte[] reds = new byte[mapSize];
213                byte[] grns = new byte[mapSize];
214                byte[] blus = new byte[mapSize];
215                float scale = (255 - minGray) / 255f;
216                for (int i = 0; i < mapSize; i++) {
217                        byte g = (byte) (Math.round(minGray + scale * i) & 0xFF);
218                        reds[i] = g;
219                        grns[i] = g;
220                        blus[i] = g;
221                }
222                ip.setColorModel(new IndexColorModel(8, mapSize, reds, grns, blus));
223        }
224
225}