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}