001: /*
002: * $RCSfile: GradientOpImage.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:27 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.Rectangle;
015: import java.awt.image.DataBuffer;
016: import java.awt.image.SampleModel;
017: import java.awt.image.Raster;
018: import java.awt.image.RenderedImage;
019: import java.awt.image.WritableRaster;
020: import java.awt.image.renderable.ParameterBlock;
021: import java.awt.image.renderable.RenderedImageFactory;
022: import javax.media.jai.AreaOpImage;
023: import javax.media.jai.BorderExtender;
024: import javax.media.jai.ImageLayout;
025: import javax.media.jai.KernelJAI;
026: import javax.media.jai.OpImage;
027: import javax.media.jai.RasterAccessor;
028: import javax.media.jai.RasterFormatTag;
029: import java.util.Map;
030:
031: // import com.sun.media.jai.test.OpImageTester;
032:
033: /**
034: * An OpImage class to perform Gradient operation on a source image.
035: *
036: * <p> The Kernels cannot be bigger in any dimension than the image data.
037: *
038: *
039: * @see KernelJAI
040: */
041: final class GradientOpImage extends AreaOpImage {
042:
043: /**
044: * The kernel with which to do the gradient operation.
045: */
046: protected KernelJAI kernel_h, kernel_v;
047:
048: /** Kernel variables. */
049: private int kw, kh;
050:
051: /**
052: * Creates a GradientOpImage given the image source and
053: * the pair of orthogonal gradient kernels. The image dimensions are
054: * derived from the source image. The tile grid layout, SampleModel, and
055: * ColorModel may optionally be specified by an ImageLayout object.
056: *
057: * @param source a RenderedImage.
058: * @param extender a BorderExtender, or null.
059:
060: * @param layout an ImageLayout optionally containing the tile grid layout,
061: * SampleModel, and ColorModel, or null.
062: * @param kernel_h the horizontal kernel.
063: * @param kernel_v the vertical kernel
064: */
065: public GradientOpImage(RenderedImage source,
066: BorderExtender extender, Map config, ImageLayout layout,
067: KernelJAI kernel_h, KernelJAI kernel_v) {
068: super (source, layout, config, true, extender, kernel_h
069: .getLeftPadding(), kernel_h.getRightPadding(), kernel_h
070: .getTopPadding(), kernel_h.getBottomPadding());
071:
072: // Local copy of the kernels
073: this .kernel_h = kernel_h;
074: this .kernel_v = kernel_v;
075:
076: //
077: // At this point both kernels should be of same width & height
078: // so it's enough to get the information from one of them
079: //
080: kw = kernel_h.getWidth();
081: kh = kernel_h.getHeight();
082: }
083:
084: /**
085: * Performs gradient operation on a specified rectangle. The sources are
086: * cobbled.
087: *
088: * @param sources an array of source Rasters, guaranteed to provide all
089: * necessary source data for computing the output.
090: * @param dest a WritableRaster tile containing the area to be computed.
091: * @param destRect the rectangle within dest to be processed.
092: */
093: protected void computeRect(Raster[] sources, WritableRaster dest,
094: Rectangle destRect) {
095: // Retrieve format tags.
096: RasterFormatTag[] formatTags = getFormatTags();
097:
098: Raster source = sources[0];
099: Rectangle srcRect = mapDestRect(destRect, 0);
100:
101: RasterAccessor srcAccessor = new RasterAccessor(source,
102: srcRect, formatTags[0], getSourceImage(0)
103: .getColorModel());
104: RasterAccessor dstAccessor = new RasterAccessor(dest, destRect,
105: formatTags[1], getColorModel());
106:
107: switch (dstAccessor.getDataType()) {
108: case DataBuffer.TYPE_BYTE:
109: byteLoop(srcAccessor, dstAccessor);
110: break;
111: case DataBuffer.TYPE_INT:
112: intLoop(srcAccessor, dstAccessor);
113: break;
114: case DataBuffer.TYPE_SHORT:
115: shortLoop(srcAccessor, dstAccessor);
116: break;
117: case DataBuffer.TYPE_USHORT:
118: ushortLoop(srcAccessor, dstAccessor);
119: break;
120: case DataBuffer.TYPE_FLOAT:
121: floatLoop(srcAccessor, dstAccessor);
122: break;
123: case DataBuffer.TYPE_DOUBLE:
124: doubleLoop(srcAccessor, dstAccessor);
125: break;
126:
127: default:
128: }
129:
130: // If the RasterAccessor object set up a temporary buffer for the
131: // op to write to, tell the RasterAccessor to write that data
132: // to the raster no that we're done with it.
133: if (dstAccessor.isDataCopy()) {
134: dstAccessor.clampDataArrays();
135: dstAccessor.copyDataToRaster();
136: }
137: }
138:
139: private void byteLoop(RasterAccessor src, RasterAccessor dst) {
140: int dwidth = dst.getWidth();
141: int dheight = dst.getHeight();
142: int dnumBands = dst.getNumBands();
143:
144: float[] kdata_h = kernel_h.getKernelData();
145: float[] kdata_v = kernel_v.getKernelData();
146:
147: byte dstDataArrays[][] = dst.getByteDataArrays();
148: int dstBandOffsets[] = dst.getBandOffsets();
149: int dstPixelStride = dst.getPixelStride();
150: int dstScanlineStride = dst.getScanlineStride();
151:
152: byte srcDataArrays[][] = src.getByteDataArrays();
153: int srcBandOffsets[] = src.getBandOffsets();
154: int srcPixelStride = src.getPixelStride();
155: int srcScanlineStride = src.getScanlineStride();
156:
157: for (int k = 0; k < dnumBands; k++) {
158: byte dstData[] = dstDataArrays[k];
159: byte srcData[] = srcDataArrays[k];
160:
161: int srcScanlineOffset = srcBandOffsets[k];
162: int dstScanlineOffset = dstBandOffsets[k];
163:
164: for (int j = 0; j < dheight; j++) {
165: int srcPixelOffset = srcScanlineOffset;
166: int dstPixelOffset = dstScanlineOffset;
167:
168: for (int i = 0; i < dwidth; i++) {
169: float f_h = 0.0f;
170: float f_v = 0.0f;
171:
172: int kernelVerticalOffset = 0;
173: int imageVerticalOffset = srcPixelOffset;
174:
175: for (int u = 0; u < kh; u++) {
176: int imageOffset = imageVerticalOffset;
177:
178: for (int v = 0; v < kw; v++) {
179:
180: f_h += ((int) srcData[imageOffset] & 0xff)
181: * kdata_h[kernelVerticalOffset + v];
182: f_v += ((int) srcData[imageOffset] & 0xff)
183: * kdata_v[kernelVerticalOffset + v];
184:
185: imageOffset += srcPixelStride;
186: }
187:
188: kernelVerticalOffset += kw;
189: imageVerticalOffset += srcScanlineStride;
190: }
191:
192: // Do the Gradient
193: float sqr_f_h = f_h * f_h;
194: float sqr_f_v = f_v * f_v;
195: float result = (float) Math.sqrt(sqr_f_h + sqr_f_v);
196:
197: int val = (int) (result + 0.5f); // Round
198: if (val < 0) {
199: val = 0;
200: } else if (val > 255) {
201: val = 255;
202: }
203: dstData[dstPixelOffset] = (byte) val;
204: srcPixelOffset += srcPixelStride;
205: dstPixelOffset += dstPixelStride;
206: }
207: srcScanlineOffset += srcScanlineStride;
208: dstScanlineOffset += dstScanlineStride;
209: }
210: }
211: }
212:
213: private void shortLoop(RasterAccessor src, RasterAccessor dst) {
214: int dwidth = dst.getWidth();
215: int dheight = dst.getHeight();
216: int dnumBands = dst.getNumBands();
217:
218: float[] kdata_h = kernel_h.getKernelData();
219: float[] kdata_v = kernel_v.getKernelData();
220:
221: short dstDataArrays[][] = dst.getShortDataArrays();
222: int dstBandOffsets[] = dst.getBandOffsets();
223: int dstPixelStride = dst.getPixelStride();
224: int dstScanlineStride = dst.getScanlineStride();
225:
226: short srcDataArrays[][] = src.getShortDataArrays();
227: int srcBandOffsets[] = src.getBandOffsets();
228: int srcPixelStride = src.getPixelStride();
229: int srcScanlineStride = src.getScanlineStride();
230:
231: for (int k = 0; k < dnumBands; k++) {
232: short dstData[] = dstDataArrays[k];
233: short srcData[] = srcDataArrays[k];
234: int srcScanlineOffset = srcBandOffsets[k];
235: int dstScanlineOffset = dstBandOffsets[k];
236: for (int j = 0; j < dheight; j++) {
237: int srcPixelOffset = srcScanlineOffset;
238: int dstPixelOffset = dstScanlineOffset;
239: for (int i = 0; i < dwidth; i++) {
240: float f_h = 0.0f;
241: float f_v = 0.0f;
242: int kernelVerticalOffset = 0;
243: int imageVerticalOffset = srcPixelOffset;
244: for (int u = 0; u < kh; u++) {
245: int imageOffset = imageVerticalOffset;
246: for (int v = 0; v < kw; v++) {
247: f_h += (srcData[imageOffset])
248: * kdata_h[kernelVerticalOffset + v];
249: f_v += (srcData[imageOffset])
250: * kdata_v[kernelVerticalOffset + v];
251: imageOffset += srcPixelStride;
252: }
253: kernelVerticalOffset += kw;
254: imageVerticalOffset += srcScanlineStride;
255: }
256:
257: // Do the Gradient
258: float sqr_f_h = f_h * f_h;
259: float sqr_f_v = f_v * f_v;
260: float result = (float) Math.sqrt(sqr_f_h + sqr_f_v);
261:
262: int val = (int) (result + 0.5f); // Round
263: if (val < Short.MIN_VALUE) {
264: val = Short.MIN_VALUE;
265: } else if (val > Short.MAX_VALUE) {
266: val = Short.MAX_VALUE;
267: }
268:
269: dstData[dstPixelOffset] = (short) val;
270: srcPixelOffset += srcPixelStride;
271: dstPixelOffset += dstPixelStride;
272: }
273: srcScanlineOffset += srcScanlineStride;
274: dstScanlineOffset += dstScanlineStride;
275: }
276: }
277: }
278:
279: private void ushortLoop(RasterAccessor src, RasterAccessor dst) {
280: int dwidth = dst.getWidth();
281: int dheight = dst.getHeight();
282: int dnumBands = dst.getNumBands();
283:
284: float[] kdata_h = kernel_h.getKernelData();
285: float[] kdata_v = kernel_v.getKernelData();
286:
287: short dstDataArrays[][] = dst.getShortDataArrays();
288: int dstBandOffsets[] = dst.getBandOffsets();
289: int dstPixelStride = dst.getPixelStride();
290: int dstScanlineStride = dst.getScanlineStride();
291:
292: short srcDataArrays[][] = src.getShortDataArrays();
293: int srcBandOffsets[] = src.getBandOffsets();
294: int srcPixelStride = src.getPixelStride();
295: int srcScanlineStride = src.getScanlineStride();
296:
297: for (int k = 0; k < dnumBands; k++) {
298: short dstData[] = dstDataArrays[k];
299: short srcData[] = srcDataArrays[k];
300: int srcScanlineOffset = srcBandOffsets[k];
301: int dstScanlineOffset = dstBandOffsets[k];
302: for (int j = 0; j < dheight; j++) {
303: int srcPixelOffset = srcScanlineOffset;
304: int dstPixelOffset = dstScanlineOffset;
305: for (int i = 0; i < dwidth; i++) {
306: float f_h = 0.0f;
307: float f_v = 0.0f;
308: int kernelVerticalOffset = 0;
309: int imageVerticalOffset = srcPixelOffset;
310: for (int u = 0; u < kh; u++) {
311: int imageOffset = imageVerticalOffset;
312: for (int v = 0; v < kw; v++) {
313: f_h += (srcData[imageOffset] & 0xffff)
314: * kdata_h[kernelVerticalOffset + v];
315: f_v += (srcData[imageOffset] & 0xffff)
316: * kdata_v[kernelVerticalOffset + v];
317: imageOffset += srcPixelStride;
318: }
319: kernelVerticalOffset += kw;
320: imageVerticalOffset += srcScanlineStride;
321: }
322:
323: // Do the Gradient
324: float sqr_f_h = f_h * f_h;
325: float sqr_f_v = f_v * f_v;
326: float result = (float) Math.sqrt(sqr_f_h + sqr_f_v);
327:
328: int val = (int) (result + 0.5f); // Round
329: if (val < 0) {
330: val = 0;
331: } else if (val > 0xffff) {
332: val = 0xffff;
333: }
334:
335: dstData[dstPixelOffset] = (short) val;
336: srcPixelOffset += srcPixelStride;
337: dstPixelOffset += dstPixelStride;
338: }
339: srcScanlineOffset += srcScanlineStride;
340: dstScanlineOffset += dstScanlineStride;
341: }
342: }
343: }
344:
345: private void intLoop(RasterAccessor src, RasterAccessor dst) {
346: int dwidth = dst.getWidth();
347: int dheight = dst.getHeight();
348: int dnumBands = dst.getNumBands();
349:
350: float[] kdata_h = kernel_h.getKernelData();
351: float[] kdata_v = kernel_v.getKernelData();
352:
353: int dstDataArrays[][] = dst.getIntDataArrays();
354: int dstBandOffsets[] = dst.getBandOffsets();
355: int dstPixelStride = dst.getPixelStride();
356: int dstScanlineStride = dst.getScanlineStride();
357:
358: int srcDataArrays[][] = src.getIntDataArrays();
359: int srcBandOffsets[] = src.getBandOffsets();
360: int srcPixelStride = src.getPixelStride();
361: int srcScanlineStride = src.getScanlineStride();
362:
363: for (int k = 0; k < dnumBands; k++) {
364: int dstData[] = dstDataArrays[k];
365: int srcData[] = srcDataArrays[k];
366: int srcScanlineOffset = srcBandOffsets[k];
367: int dstScanlineOffset = dstBandOffsets[k];
368: for (int j = 0; j < dheight; j++) {
369: int srcPixelOffset = srcScanlineOffset;
370: int dstPixelOffset = dstScanlineOffset;
371: for (int i = 0; i < dwidth; i++) {
372: float f_h = 0.0f;
373: float f_v = 0.0f;
374: int kernelVerticalOffset = 0;
375: int imageVerticalOffset = srcPixelOffset;
376: for (int u = 0; u < kh; u++) {
377: int imageOffset = imageVerticalOffset;
378: for (int v = 0; v < kw; v++) {
379: f_h += ((int) srcData[imageOffset])
380: * kdata_h[kernelVerticalOffset + v];
381: f_v += ((int) srcData[imageOffset])
382: * kdata_v[kernelVerticalOffset + v];
383: imageOffset += srcPixelStride;
384: }
385: kernelVerticalOffset += kw;
386: imageVerticalOffset += srcScanlineStride;
387: }
388:
389: // Do the Gradient
390: float sqr_f_h = f_h * f_h;
391: float sqr_f_v = f_v * f_v;
392: float result = (float) Math.sqrt(sqr_f_h + sqr_f_v);
393:
394: dstData[dstPixelOffset] = (int) (result + 0.5f); // Round
395: srcPixelOffset += srcPixelStride;
396: dstPixelOffset += dstPixelStride;
397: }
398: srcScanlineOffset += srcScanlineStride;
399: dstScanlineOffset += dstScanlineStride;
400: }
401: }
402: }
403:
404: private void floatLoop(RasterAccessor src, RasterAccessor dst) {
405: int dwidth = dst.getWidth();
406: int dheight = dst.getHeight();
407: int dnumBands = dst.getNumBands();
408:
409: float[] kdata_h = kernel_h.getKernelData();
410: float[] kdata_v = kernel_v.getKernelData();
411:
412: float dstDataArrays[][] = dst.getFloatDataArrays();
413: int dstBandOffsets[] = dst.getBandOffsets();
414: int dstPixelStride = dst.getPixelStride();
415: int dstScanlineStride = dst.getScanlineStride();
416:
417: float srcDataArrays[][] = src.getFloatDataArrays();
418: int srcBandOffsets[] = src.getBandOffsets();
419: int srcPixelStride = src.getPixelStride();
420: int srcScanlineStride = src.getScanlineStride();
421:
422: for (int k = 0; k < dnumBands; k++) {
423: float dstData[] = dstDataArrays[k];
424: float srcData[] = srcDataArrays[k];
425: int srcScanlineOffset = srcBandOffsets[k];
426: int dstScanlineOffset = dstBandOffsets[k];
427: for (int j = 0; j < dheight; j++) {
428: int srcPixelOffset = srcScanlineOffset;
429: int dstPixelOffset = dstScanlineOffset;
430: for (int i = 0; i < dwidth; i++) {
431: float f_h = 0.0f;
432: float f_v = 0.0f;
433: int kernelVerticalOffset = 0;
434: int imageVerticalOffset = srcPixelOffset;
435: for (int u = 0; u < kh; u++) {
436: int imageOffset = imageVerticalOffset;
437: for (int v = 0; v < kw; v++) {
438: f_h += (srcData[imageOffset])
439: * kdata_h[kernelVerticalOffset + v];
440: f_v += (srcData[imageOffset])
441: * kdata_v[kernelVerticalOffset + v];
442: imageOffset += srcPixelStride;
443: }
444: kernelVerticalOffset += kw;
445: imageVerticalOffset += srcScanlineStride;
446: }
447:
448: // Do the Gradient
449: float sqr_f_h = f_h * f_h;
450: float sqr_f_v = f_v * f_v;
451: float result = (float) Math.sqrt(sqr_f_h + sqr_f_v);
452:
453: dstData[dstPixelOffset] = result;
454: srcPixelOffset += srcPixelStride;
455: dstPixelOffset += dstPixelStride;
456: }
457: srcScanlineOffset += srcScanlineStride;
458: dstScanlineOffset += dstScanlineStride;
459: }
460: }
461: }
462:
463: private void doubleLoop(RasterAccessor src, RasterAccessor dst) {
464: int dwidth = dst.getWidth();
465: int dheight = dst.getHeight();
466: int dnumBands = dst.getNumBands();
467:
468: float[] kdata_h = kernel_h.getKernelData();
469: float[] kdata_v = kernel_v.getKernelData();
470:
471: double dstDataArrays[][] = dst.getDoubleDataArrays();
472: int dstBandOffsets[] = dst.getBandOffsets();
473: int dstPixelStride = dst.getPixelStride();
474: int dstScanlineStride = dst.getScanlineStride();
475:
476: double srcDataArrays[][] = src.getDoubleDataArrays();
477: int srcBandOffsets[] = src.getBandOffsets();
478: int srcPixelStride = src.getPixelStride();
479: int srcScanlineStride = src.getScanlineStride();
480:
481: for (int k = 0; k < dnumBands; k++) {
482: double dstData[] = dstDataArrays[k];
483: double srcData[] = srcDataArrays[k];
484: int srcScanlineOffset = srcBandOffsets[k];
485: int dstScanlineOffset = dstBandOffsets[k];
486: for (int j = 0; j < dheight; j++) {
487: int srcPixelOffset = srcScanlineOffset;
488: int dstPixelOffset = dstScanlineOffset;
489:
490: for (int i = 0; i < dwidth; i++) {
491: double f_h = 0.0;
492: double f_v = 0.0;
493: int kernelVerticalOffset = 0;
494: int imageVerticalOffset = srcPixelOffset;
495: for (int u = 0; u < kh; u++) {
496: int imageOffset = imageVerticalOffset;
497: for (int v = 0; v < kw; v++) {
498: f_h += (srcData[imageOffset])
499: * kdata_h[kernelVerticalOffset + v];
500: f_v += (srcData[imageOffset])
501: * kdata_v[kernelVerticalOffset + v];
502: imageOffset += srcPixelStride;
503: }
504: kernelVerticalOffset += kw;
505: imageVerticalOffset += srcScanlineStride;
506: }
507:
508: // Do the Gradient
509: double sqr_f_h = f_h * f_h;
510: double sqr_f_v = f_v * f_v;
511: double result = Math.sqrt(sqr_f_h + sqr_f_v);
512:
513: dstData[dstPixelOffset] = result;
514: srcPixelOffset += srcPixelStride;
515: dstPixelOffset += dstPixelStride;
516: }
517: srcScanlineOffset += srcScanlineStride;
518: dstScanlineOffset += dstScanlineStride;
519: }
520: }
521: }
522:
523: // public static OpImage createTestImage(OpImageTester oit) {
524: // float data_h[] = {-1.0f, -2.0f, -1.0f,
525: // 0.0f, 0.0f, 0.0f,
526: // 1.0f, 2.0f, 1.0f};
527: // float data_v[] = {-1.0f, 0.0f, 1.0f,
528: // -2.0f, 0.0f, 2.0f,
529: // -1.0f, 0.0f, 1.0f};
530:
531: // KernelJAI kern_h = new KernelJAI(3,3,data_h);
532: // KernelJAI kern_v = new KernelJAI(3,3,data_v);
533:
534: // return new GradientOpImage(oit.getSource(), null, null,
535: // new ImageLayout(oit.getSource()),
536: // kern_h, kern_v);
537: // }
538:
539: // public static void main(String args[]) {
540: // String classname = "com.sun.media.jai.opimage.GradientOpImage";
541: // OpImageTester.performDiagnostics(classname,args);
542: // }
543: }
|