View Javadoc

1   package de.desy.acop.video.displayer;
2   
3   import java.util.Arrays;
4   
5   /**
6    * <code>ColorLookup</code> creates, prepares and maintains a false color table
7    * necessary to decode pure grayscale image data to true color display. Three
8    * false color tables (mappings) are supported at the moment:
9    * <ul>
10   * <li>PITZ false color (was invented at PITZ Video System v2, Velizar Miltchev)
11   * <li>MATLAB jet false color (taken from Matlab)
12   * <li>GRAYSCALE simple grayscale conversion
13   * </ul>
14   * 
15   * An important criteria to mention is that these mappings support scaling to
16   * physical and effective bits per pixel settings. For example if source
17   * grayscale data is 16bpp physically encoded (for performance reason) but only
18   * 12 of these bits are effectively used, the false color table is designed to
19   * support 0 as darkest and 4195 (12 bit max) as brightest value. All other
20   * value (for 16 bit: 4096 to 65535) are encoded in magenta to easily detect
21   * them as being illegal. In comparison to that, the output format is always
22   * java TYPE_INT_ARGB for sake of simplicity.<br>
23   * The main use is to generate a 1-dimensional false-color-mapping table that
24   * accepts as index any physically valid grayscale number and returns the
25   * matched pixel ready for being placed to the output drawing buffer.
26   * 
27   * @author sweisse, mdavid
28   * @deprecated replaced by LookUpTable
29   */
30  
31  public final class ColorLookupTable {
32  
33  	/**
34  	 * current color map
35  	 */
36  	private ColorMap colorMap;
37  
38  	/**
39  	 * physical bytes per pixel inside
40  	 */
41  	private int bytesPerPixel;
42  
43  	/**
44  	 * effective bits per pixel inside
45  	 */
46  	private int effBitsPerPixel;
47  
48  	/**
49  	 * array for false color mapping table
50  	 */
51  	private int[] rgbs;
52  
53  	/**
54  	 * Constructs a false color lookup table
55  	 * 
56  	 * @param colorMap
57  	 *            color map (allowed values are ColorMap.GRAYSCALE,
58  	 *            ColorMap.PITZ, ColorMap.JET)
59  	 * @param bytesPerPixel
60  	 *            physical bytes per pixel (allowed values are 1, 2, 3)
61  	 * @param effBitsPerPixel
62  	 *            effective bits per pixel (effective bits must fit inside
63  	 *            physical bits per pixel)
64  	 * 
65  	 * @see ColorMap
66  	 */
67  	public ColorLookupTable(ColorMap colorMap, int bytesPerPixel, int effBitsPerPixel) {
68  		if (colorMap == null)
69  			throw new NullPointerException("colorMap == null!");
70  
71  		if (bytesPerPixel < 1 || bytesPerPixel > 3)
72  			throw new IllegalArgumentException("bytesPerPixel = " + bytesPerPixel);
73  
74  		if (effBitsPerPixel < 1 || effBitsPerPixel > (bytesPerPixel * 8))
75  			throw new IllegalArgumentException("effBitsPerPixel = " + effBitsPerPixel);
76  
77  		this.colorMap = colorMap;
78  		this.bytesPerPixel = bytesPerPixel;
79  		this.effBitsPerPixel = effBitsPerPixel;
80  
81  		createLUT();
82  	}
83  
84  	/**
85  	 * Returns the lookup table data by reference.
86  	 * 
87  	 * @return the data array of this <code>ColorLookup</code>.
88  	 */
89  	public int[] getRGB() {
90  		return rgbs;
91  	}
92  
93  	/**
94  	 * @return physical bytes per pixel
95  	 */
96  	public int getBytesPerPixel() {
97  		return bytesPerPixel;
98  	}
99  
100 	/**
101 	 * @return effective bits per Pixel
102 	 */
103 	public int getEffBitsPerPixel() {
104 		return effBitsPerPixel;
105 	}
106 
107 	/**
108 	 * Fills false color table (Alpha:24 Red:16 Green:8 Blue:0).
109 	 */
110 	private void createLUT() {
111 		rgbs = new int[1 << (bytesPerPixel * 8)];
112 
113 		switch (colorMap) {
114 		case PITZ:
115 			fillPITZ();
116 			break;
117 
118 		case JET:
119 			fillJET();
120 			break;
121 
122 		case GRAYSCALE:
123 			fillGrayscale();
124 			break;
125 
126 		default:
127 			throw new AssertionError("Unsupportted color map: " + colorMap);
128 		}
129 
130 		/*
131 		 * Fills left colors (if effective bpp < physical bpp) with Magenta
132 		 * (0xffff00ff) for spotting of illegal values
133 		 */
134 		Arrays.fill(rgbs, 1 << effBitsPerPixel, rgbs.length, 0xffff00ff);
135 	}
136 
137 	/**
138 	 * Fills the lookup table using PITZ false colors based on current private
139 	 * class variables
140 	 */
141 	private void fillPITZ() {
142 		int dec = 1 << effBitsPerPixel;
143 
144 		// black 0-0-0
145 		rgbs[0] = 0xff000000;
146 
147 		// white 255-255-255
148 		rgbs[dec - 1] = 0xffffffff;
149 
150 		int step1 = (dec / 3) + 1;
151 		int step2 = (dec * 293 / 500) + 1;
152 		int step3 = (dec * 2 / 3) + 1;
153 		int step4 = dec - 1;
154 
155 		int i = 1;
156 		for (; i < step1; i++)
157 			rgbs[i] = 0xff000000 | ((int) ((-0.5608 / (dec / 3 - 1.0) * (i - 1) + 1.0) * 255.0) & 0xff);
158 
159 		for (; i < step2; i++) {
160 			double m1 = 0.561 / ((dec * 293 / 500) - (dec / 3));
161 			double n1 = 0.263 - (m1 * (dec / 3));
162 			double m2 = -0.4314 / ((dec * 293 / 500) - (dec / 3));
163 			double n2 = 0 - (m2 * (dec * 293 / 500));
164 			rgbs[i] = 0xff000000 | (((int) ((m1 * i + n1) * 255d) & 0xff) << 8) | ((int) ((m2 * i + n2) * 255d) & 0xff);
165 		}
166 
167 		for (; i < step3; i++) {
168 			double m1 = 0.176 / ((dec * 2 / 3) - (dec * 293 / 500));
169 			double n1 = 1 - (m1 * (dec * 2 / 3));
170 			rgbs[i] = 0xff000000 | (((int) ((m1 * i + n1) * 255.0) & 0xff) << 8);
171 		}
172 
173 		for (; i < step4; i++) {
174 			double m1 = 0.737 / (dec - (dec * 2 / 3));
175 			double n1 = 1 - (m1 * dec);
176 			rgbs[i] = 0xff000000 | (((int) ((m1 * i + n1) * 255.0) & 0xff) << 16);
177 		}
178 	}
179 
180 	/**
181 	 * Fills the lookup table using MATLAB Jet false colors based on current
182 	 * private class variables
183 	 */
184 	private void fillJET() {
185 		int dec = 1 << effBitsPerPixel;
186 
187 		int step1 = dec / 8;
188 		int step2 = dec * 3 / 8;
189 		int step3 = dec * 5 / 8;
190 		int step4 = dec * 7 / 8 + 1;
191 		int step5 = dec - 1;
192 
193 		// white 255-255-255
194 		rgbs[dec - 1] = 0xffffffff;
195 
196 		int i = 0;
197 
198 		// blue
199 		for (; i < step1; i++) {
200 			rgbs[i] = 0xff000000 | ((int) ((i / (step1 * 2.0) + 0.5) * 255.0) & 0xff);
201 		}
202 
203 		// green
204 		for (; i < step2; i++) {
205 			rgbs[i] = 0xff000000 | (((int) ((i / (step1 * 2.0) - 0.5) * 255.0) & 0xff) << 8) | 0xff;
206 		}
207 
208 		for (; i < step3; i++) {
209 			double red = (i / (step1 * 2.0) - 1.5) * 255.0;
210 			double blue = (1.0 - (i / (step1 * 2.0) - 1.5)) * 255.0;
211 			rgbs[i] = 0xff000000 | (((int) red & 0xff) << 16) | 0xff00 | ((int) blue & 0xff);
212 		}
213 
214 		// green
215 		for (; i < step4; i++) {
216 			rgbs[i] = 0xff000000 | 0xff0000 | (((int) ((i / (-step1 * 2.0) + 3.5) * 255.0) & 0xff) << 8);
217 		}
218 
219 		// red
220 		for (; i < step5; i++) {
221 			rgbs[i] = 0xff000000 | (((int) ((i / (-step1 * 2.0) + 4.5) * 255.0) & 0xff) << 16);
222 		}
223 	}
224 
225 	/**
226 	 * Fills the lookup table using grayscale based on current private class
227 	 * variables
228 	 */
229 	private void fillGrayscale() {
230 		int dec = 1 << effBitsPerPixel;
231 		int gray;
232 		for (int i = 0; i < dec; i++) {
233 			gray = 255 * i / (dec - 1);
234 			rgbs[i] = 0xff000000 | ((gray & 0xff) << 16) | ((gray & 0xff) << 8) | (gray & 0xff); // argb
235 		}
236 	}
237 
238 	@Override
239 	public String toString() {
240 		StringBuilder sb = new StringBuilder();
241 		sb.append("colorMap = ").append(colorMap);
242 		sb.append(", bytesPerPixel = ").append(bytesPerPixel);
243 		sb.append(", effBitsPerPixel = ").append(effBitsPerPixel);
244 		sb.append(", rgbs.length = ").append(rgbs.length);
245 		return sb.toString();
246 	}
247 }