001: /*
002: * $RCSfile: ThresholdOpImage.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:56:45 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import javax.media.jai.ColormapOpImage;
015: import java.awt.Rectangle;
016: import java.awt.image.DataBuffer;
017: import java.awt.image.Raster;
018: import java.awt.image.RenderedImage;
019: import java.awt.image.SampleModel;
020: import java.awt.image.WritableRaster;
021: import javax.media.jai.ImageLayout;
022: import javax.media.jai.OpImage;
023: import javax.media.jai.RasterAccessor;
024: import javax.media.jai.RasterFormatTag;
025: import java.util.Map;
026:
027: /**
028: * An <code>OpImage</code> implementing the "Threshold" operation as
029: * described in <code>javax.media.jai.operator.ThresholdDescriptor</code>.
030: *
031: * <p>This <code>OpImage</code> maps all the pixels of an image
032: * whose value falls within a given range to a constant on a per-band basis.
033: * Each of the lower bound, upper bound, and constant arrays may have only
034: * one value in it. If that is the case, that value is used for all bands.
035: *
036: * @see javax.media.jai.operator.ThresholdDescriptor
037: * @see ThresholdCRIF
038: *
039: *
040: * @since EA2
041: */
042: final class ThresholdOpImage extends ColormapOpImage {
043:
044: /** The lower bound, one for each band. */
045: private double[] low;
046:
047: /** The upper bound, one for each band. */
048: private double[] high;
049:
050: /** The constants to be mapped, one for each band. */
051: private double[] constants;
052:
053: /** Lookup table for byte data */
054: private byte[][] byteTable = null;
055:
056: /**
057: * Constructor.
058: *
059: * @param source The source image.
060: * @param layout The destination image layout.
061: * @param low The lower bound of the threshold.
062: * @param high The upper bound of the threshold.
063: * @param constants The constants to be mapped within the threshold.
064: */
065: public ThresholdOpImage(RenderedImage source, Map config,
066: ImageLayout layout, double[] low, double[] high,
067: double[] constants) {
068: super (source, layout, config, true);
069:
070: int numBands = getSampleModel().getNumBands();
071: this .low = new double[numBands];
072: this .high = new double[numBands];
073: this .constants = new double[numBands];
074:
075: for (int i = 0; i < numBands; i++) {
076: if (low.length < numBands) {
077: this .low[i] = low[0];
078: } else {
079: this .low[i] = low[i];
080: }
081: if (high.length < numBands) {
082: this .high[i] = high[0];
083: } else {
084: this .high[i] = high[i];
085: }
086: if (constants.length < numBands) {
087: this .constants[i] = constants[0];
088: } else {
089: this .constants[i] = constants[i];
090: }
091: }
092:
093: // Set flag to permit in-place operation.
094: permitInPlaceOperation();
095:
096: // Initialize the colormap if necessary.
097: initializeColormapOperation();
098: }
099:
100: /**
101: * Transform the colormap according to the rescaling parameters.
102: */
103: protected void transformColormap(byte[][] colormap) {
104: initByteTable(); // only create lookup table when necessary
105:
106: for (int b = 0; b < 3; b++) {
107: byte[] map = colormap[b];
108: byte[] luTable = byteTable[b >= byteTable.length ? 0 : b];
109: int mapSize = map.length;
110:
111: for (int i = 0; i < mapSize; i++) {
112: map[i] = luTable[(map[i] & 0xFF)];
113: }
114: }
115: }
116:
117: /**
118: * Map the pixels inside a specified rectangle whose value is within a
119: * rang to a constant on a per-band basis.
120: *
121: * @param sources Cobbled sources, guaranteed to provide all the
122: * source data necessary for computing the rectangle.
123: * @param dest The tile containing the rectangle to be computed.
124: * @param destRect The rectangle within the tile to be computed.
125: */
126: protected void computeRect(Raster[] sources, WritableRaster dest,
127: Rectangle destRect) {
128: // Retrieve format tags.
129: RasterFormatTag[] formatTags = getFormatTags();
130:
131: Rectangle srcRect = mapDestRect(destRect, 0);
132:
133: RasterAccessor src = new RasterAccessor(sources[0], srcRect,
134: formatTags[0], getSource(0).getColorModel());
135: RasterAccessor dst = new RasterAccessor(dest, destRect,
136: formatTags[1], getColorModel());
137:
138: int srcPixelStride = src.getPixelStride();
139: int srcLineStride = src.getScanlineStride();
140: int[] srcBandOffsets = src.getBandOffsets();
141:
142: int dstPixelStride = dst.getPixelStride();
143: int dstLineStride = dst.getScanlineStride();
144: int[] dstBandOffsets = dst.getBandOffsets();
145:
146: int width = dst.getWidth() * dstPixelStride;
147: int height = dst.getHeight() * dstLineStride;
148: int bands = dst.getNumBands();
149:
150: switch (dst.getDataType()) {
151: case DataBuffer.TYPE_BYTE:
152: byteLoop(width, height, bands, srcPixelStride,
153: srcLineStride, srcBandOffsets, src
154: .getByteDataArrays(), dstPixelStride,
155: dstLineStride, dstBandOffsets, dst
156: .getByteDataArrays());
157: break;
158:
159: case DataBuffer.TYPE_SHORT:
160: shortLoop(width, height, bands, srcPixelStride,
161: srcLineStride, srcBandOffsets, src
162: .getShortDataArrays(), dstPixelStride,
163: dstLineStride, dstBandOffsets, dst
164: .getShortDataArrays());
165: break;
166:
167: case DataBuffer.TYPE_USHORT:
168: ushortLoop(width, height, bands, srcPixelStride,
169: srcLineStride, srcBandOffsets, src
170: .getShortDataArrays(), dstPixelStride,
171: dstLineStride, dstBandOffsets, dst
172: .getShortDataArrays());
173: break;
174:
175: case DataBuffer.TYPE_INT:
176: intLoop(width, height, bands, srcPixelStride,
177: srcLineStride, srcBandOffsets, src
178: .getIntDataArrays(), dstPixelStride,
179: dstLineStride, dstBandOffsets, dst
180: .getIntDataArrays());
181: break;
182:
183: case DataBuffer.TYPE_FLOAT:
184: floatLoop(width, height, bands, srcPixelStride,
185: srcLineStride, srcBandOffsets, src
186: .getFloatDataArrays(), dstPixelStride,
187: dstLineStride, dstBandOffsets, dst
188: .getFloatDataArrays());
189: break;
190:
191: case DataBuffer.TYPE_DOUBLE:
192: doubleLoop(width, height, bands, srcPixelStride,
193: srcLineStride, srcBandOffsets, src
194: .getDoubleDataArrays(), dstPixelStride,
195: dstLineStride, dstBandOffsets, dst
196: .getDoubleDataArrays());
197: break;
198: }
199:
200: if (dst.isDataCopy()) {
201: dst.clampDataArrays();
202: dst.copyDataToRaster();
203: }
204: }
205:
206: private void byteLoop(int width, int height, int bands,
207: int srcPixelStride, int srcLineStride,
208: int[] srcBandOffsets, byte[][] srcData, int dstPixelStride,
209: int dstLineStride, int[] dstBandOffsets, byte[][] dstData) {
210:
211: initByteTable();
212:
213: for (int b = 0; b < bands; b++) {
214: byte[] s = srcData[b];
215: byte[] d = dstData[b];
216: byte[] t = byteTable[b];
217:
218: int heightEnd = dstBandOffsets[b] + height;
219:
220: for (int dstLineOffset = dstBandOffsets[b], srcLineOffset = srcBandOffsets[b]; dstLineOffset < heightEnd; dstLineOffset += dstLineStride, srcLineOffset += srcLineStride) {
221:
222: int widthEnd = dstLineOffset + width;
223:
224: for (int dstPixelOffset = dstLineOffset, srcPixelOffset = srcLineOffset; dstPixelOffset < widthEnd; dstPixelOffset += dstPixelStride, srcPixelOffset += srcPixelStride) {
225:
226: d[dstPixelOffset] = t[s[srcPixelOffset] & 0xFF];
227: }
228: }
229: }
230: }
231:
232: private void shortLoop(int width, int height, int bands,
233: int srcPixelStride, int srcLineStride,
234: int[] srcBandOffsets, short[][] srcData,
235: int dstPixelStride, int dstLineStride,
236: int[] dstBandOffsets, short[][] dstData) {
237: for (int b = 0; b < bands; b++) {
238: short[] s = srcData[b];
239: short[] d = dstData[b];
240:
241: double l = low[b];
242: double h = high[b];
243: short c = (short) constants[b];
244:
245: int heightEnd = dstBandOffsets[b] + height;
246:
247: for (int dstLineOffset = dstBandOffsets[b], srcLineOffset = srcBandOffsets[b]; dstLineOffset < heightEnd; dstLineOffset += dstLineStride, srcLineOffset += srcLineStride) {
248:
249: int widthEnd = dstLineOffset + width;
250:
251: for (int dstPixelOffset = dstLineOffset, srcPixelOffset = srcLineOffset; dstPixelOffset < widthEnd; dstPixelOffset += dstPixelStride, srcPixelOffset += srcPixelStride) {
252:
253: short p = s[srcPixelOffset];
254:
255: if (p >= l && p <= h) {
256: d[dstPixelOffset] = c;
257: } else {
258: d[dstPixelOffset] = p;
259: }
260: }
261: }
262: }
263: }
264:
265: private void ushortLoop(int width, int height, int bands,
266: int srcPixelStride, int srcLineStride,
267: int[] srcBandOffsets, short[][] srcData,
268: int dstPixelStride, int dstLineStride,
269: int[] dstBandOffsets, short[][] dstData) {
270:
271: for (int b = 0; b < bands; b++) {
272: short[] s = srcData[b];
273: short[] d = dstData[b];
274:
275: double l = low[b];
276: double h = high[b];
277: short c = (short) constants[b];
278:
279: int heightEnd = dstBandOffsets[b] + height;
280:
281: for (int dstLineOffset = dstBandOffsets[b], srcLineOffset = srcBandOffsets[b]; dstLineOffset < heightEnd; dstLineOffset += dstLineStride, srcLineOffset += srcLineStride) {
282:
283: int widthEnd = dstLineOffset + width;
284:
285: for (int dstPixelOffset = dstLineOffset, srcPixelOffset = srcLineOffset; dstPixelOffset < widthEnd; dstPixelOffset += dstPixelStride, srcPixelOffset += srcPixelStride) {
286:
287: int p = s[srcPixelOffset] & 0xFFFF;
288:
289: if (p >= l && p <= h) {
290: d[dstPixelOffset] = c;
291: } else {
292: d[dstPixelOffset] = (short) p;
293: }
294: }
295: }
296: }
297: }
298:
299: private void intLoop(int width, int height, int bands,
300: int srcPixelStride, int srcLineStride,
301: int[] srcBandOffsets, int[][] srcData, int dstPixelStride,
302: int dstLineStride, int[] dstBandOffsets, int[][] dstData) {
303:
304: for (int b = 0; b < bands; b++) {
305: int[] s = srcData[b];
306: int[] d = dstData[b];
307:
308: double l = low[b];
309: double h = high[b];
310: int c = (int) constants[b];
311:
312: int heightEnd = dstBandOffsets[b] + height;
313:
314: for (int dstLineOffset = dstBandOffsets[b], srcLineOffset = srcBandOffsets[b]; dstLineOffset < heightEnd; dstLineOffset += dstLineStride, srcLineOffset += srcLineStride) {
315:
316: int widthEnd = dstLineOffset + width;
317:
318: for (int dstPixelOffset = dstLineOffset, srcPixelOffset = srcLineOffset; dstPixelOffset < widthEnd; dstPixelOffset += dstPixelStride, srcPixelOffset += srcPixelStride) {
319:
320: int p = s[srcPixelOffset];
321:
322: if (p >= l && p <= h) {
323: d[dstPixelOffset] = c;
324: } else {
325: d[dstPixelOffset] = p;
326: }
327: }
328: }
329: }
330: }
331:
332: private void floatLoop(int width, int height, int bands,
333: int srcPixelStride, int srcLineStride,
334: int[] srcBandOffsets, float[][] srcData,
335: int dstPixelStride, int dstLineStride,
336: int[] dstBandOffsets, float[][] dstData) {
337:
338: for (int b = 0; b < bands; b++) {
339: float[] s = srcData[b];
340: float[] d = dstData[b];
341:
342: double l = low[b];
343: double h = high[b];
344: float c = (float) constants[b];
345:
346: int heightEnd = dstBandOffsets[b] + height;
347:
348: for (int dstLineOffset = dstBandOffsets[b], srcLineOffset = srcBandOffsets[b]; dstLineOffset < heightEnd; dstLineOffset += dstLineStride, srcLineOffset += srcLineStride) {
349:
350: int widthEnd = dstLineOffset + width;
351:
352: for (int dstPixelOffset = dstLineOffset, srcPixelOffset = srcLineOffset; dstPixelOffset < widthEnd; dstPixelOffset += dstPixelStride, srcPixelOffset += srcPixelStride) {
353:
354: float p = s[srcPixelOffset];
355:
356: if (p >= l && p <= h) {
357: d[dstPixelOffset] = c;
358: } else {
359: d[dstPixelOffset] = p;
360: }
361: }
362: }
363: }
364: }
365:
366: private void doubleLoop(int width, int height, int bands,
367: int srcPixelStride, int srcLineStride,
368: int[] srcBandOffsets, double[][] srcData,
369: int dstPixelStride, int dstLineStride,
370: int[] dstBandOffsets, double[][] dstData) {
371:
372: for (int b = 0; b < bands; b++) {
373: double[] s = srcData[b];
374: double[] d = dstData[b];
375:
376: double l = low[b];
377: double h = high[b];
378: double c = constants[b];
379:
380: int heightEnd = dstBandOffsets[b] + height;
381:
382: for (int dstLineOffset = dstBandOffsets[b], srcLineOffset = srcBandOffsets[b]; dstLineOffset < heightEnd; dstLineOffset += dstLineStride, srcLineOffset += srcLineStride) {
383:
384: int widthEnd = dstLineOffset + width;
385:
386: for (int dstPixelOffset = dstLineOffset, srcPixelOffset = srcLineOffset; dstPixelOffset < widthEnd; dstPixelOffset += dstPixelStride, srcPixelOffset += srcPixelStride) {
387:
388: double p = s[srcPixelOffset];
389:
390: if (p >= l && p <= h) {
391: d[dstPixelOffset] = c;
392: } else {
393: d[dstPixelOffset] = p;
394: }
395: }
396: }
397: }
398: }
399:
400: private synchronized void initByteTable() {
401:
402: if (byteTable != null)
403: return;
404:
405: /* Build a ramp lookup table for byte datatype. */
406: int numBands = getSampleModel().getNumBands();
407: byteTable = new byte[numBands][0x100];
408:
409: for (int b = 0; b < numBands; b++) {
410: double l = low[b];
411: double h = high[b];
412: byte c = (byte) constants[b];
413:
414: byte[] t = byteTable[b];
415:
416: for (int i = 0; i < 0x100; i++) {
417: if (i >= l && i <= h) {
418: t[i] = c;
419: } else {
420: t[i] = (byte) i;
421: }
422: }
423: }
424: }
425: }
|