001: /*
002: * $RCSfile: SubsampleAverageOpImage.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.4 $
009: * $Date: 2007/08/28 23:25:55 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.Rectangle;
015: import java.awt.geom.Point2D;
016: import java.awt.image.DataBuffer;
017: import java.awt.image.Raster;
018: import java.awt.image.RenderedImage;
019: import java.awt.image.WritableRaster;
020: import java.util.Map;
021: import javax.media.jai.GeometricOpImage;
022: import javax.media.jai.ImageLayout;
023: import javax.media.jai.Interpolation;
024: import javax.media.jai.RasterAccessor;
025: import javax.media.jai.RasterFormatTag;
026: import com.sun.media.jai.util.ImageUtil;
027: import com.sun.media.jai.util.InterpAverage;
028:
029: public class SubsampleAverageOpImage extends GeometricOpImage {
030: /* XXX
031: public static void main(String[] args) throws Throwable {
032: javax.media.jai.PlanarImage source =
033: javax.media.jai.JAI.create("fileload", args[0]);
034: double scaleX = args.length > 1 ?
035: Double.valueOf(args[1]).doubleValue() : 0.25;
036: double scaleY = args.length > 2 ?
037: Double.valueOf(args[2]).doubleValue() : scaleX;
038:
039: source.getTiles();
040:
041: javax.media.jai.PlanarImage dest =
042: new SubsampleAverageOpImage(source, null, null,
043: scaleX, scaleY);
044: long t1 = System.currentTimeMillis();
045: dest.getTiles();
046: long t2 = System.currentTimeMillis();
047: System.out.println("Java time = "+(t2 - t1));
048:
049: javax.media.jai.PlanarImage destML =
050: new MlibSubsampleAverageOpImage(source, null, null,
051: scaleX, scaleY);
052: long t3 = System.currentTimeMillis();
053: destML.getTiles();
054: long t4 = System.currentTimeMillis();
055: System.out.println("Mlib time = "+(t4 - t3));
056:
057: RenderedImage diff = javax.media.jai.JAI.create("subtract",
058: javax.media.jai.JAI.create("format", dest,
059: DataBuffer.TYPE_SHORT),
060: javax.media.jai.JAI.create("format", destML,
061: DataBuffer.TYPE_SHORT));
062: RenderedImage absDiff = javax.media.jai.JAI.create("absolute", diff);
063: double[] maxima =
064: (double[])javax.media.jai.JAI.create("extrema", absDiff).getProperty("maximum");
065: for(int i = 0; i < maxima.length; i++) {
066: System.out.println(maxima[i]);
067: }
068:
069: System.out.println(source.getClass().getName()+": "+
070: new ImageLayout(source));
071: System.out.println(dest.getClass().getName()+": "+
072: new ImageLayout(dest));
073: System.out.println(destML.getClass().getName()+": "+
074: new ImageLayout(destML));
075:
076: java.awt.Frame frame = new java.awt.Frame("Mlib Sub-average Test");
077: frame.setLayout(new java.awt.GridLayout(1, 2));
078: javax.media.jai.widget.ScrollingImagePanel ps =
079: new javax.media.jai.widget.ScrollingImagePanel(dest,
080: 512, 512);
081: javax.media.jai.widget.ScrollingImagePanel pd =
082: new javax.media.jai.widget.ScrollingImagePanel(destML,
083: 512, 512);
084: frame.add(ps);
085: frame.add(pd);
086: frame.pack();
087: frame.show();
088: }
089: */
090:
091: /** The horizontal scale factor. */
092: protected double scaleX;
093:
094: /** The vertical scale factor. */
095: protected double scaleY;
096:
097: /** Horizontal size of an averaging block. */
098: protected int blockX;
099:
100: /** Vertical size of an averaging block. */
101: protected int blockY;
102:
103: /** Source image minimum x coordinate. */
104: protected int sourceMinX;
105:
106: /** Source image minimum y coordinate. */
107: protected int sourceMinY;
108:
109: private static ImageLayout layoutHelper(RenderedImage source,
110: double scaleX, double scaleY, ImageLayout il) {
111:
112: if (scaleX <= 0.0 || scaleX > 1.0) {
113: throw new IllegalArgumentException(JaiI18N
114: .getString("SubsampleAverageOpImage0"));
115: } else if (scaleY <= 0.0 || scaleY > 1.0) {
116: throw new IllegalArgumentException(JaiI18N
117: .getString("SubsampleAverageOpImage1"));
118: }
119:
120: ImageLayout layout = (il == null) ? new ImageLayout()
121: : (ImageLayout) il.clone();
122:
123: layout.setMinX((int) Math.floor(source.getMinX() * scaleX));
124: layout.setMinY((int) Math.floor(source.getMinY() * scaleY));
125: layout.setWidth((int) (source.getWidth() * scaleX));
126: layout.setHeight((int) (source.getHeight() * scaleY));
127:
128: return layout;
129: }
130:
131: public SubsampleAverageOpImage(RenderedImage source,
132: ImageLayout layout, Map config, double scaleX, double scaleY) {
133: super (vectorize(source), layoutHelper(source, scaleX, scaleY,
134: layout), config, true, // cobbleSources,
135: null, // BorderExtender
136: new InterpAverage((int) Math.ceil(1.0 / scaleX),
137: (int) Math.ceil(1.0 / scaleY)), null);
138:
139: this .scaleX = scaleX;
140: this .scaleY = scaleY;
141:
142: this .blockX = (int) Math.ceil(1.0 / scaleX);
143: this .blockY = (int) Math.ceil(1.0 / scaleY);
144:
145: this .sourceMinX = source.getMinX();
146: this .sourceMinY = source.getMinY();
147: }
148:
149: public Point2D mapDestPoint(Point2D destPt) {
150: if (destPt == null) {
151: throw new IllegalArgumentException("destPt == null!");
152: }
153:
154: Point2D pt = (Point2D) destPt.clone();
155: pt.setLocation(sourceMinX + (destPt.getX() + 0.5 - minX)
156: / scaleX - 0.5, sourceMinY
157: + (destPt.getY() + 0.5 - minY) / scaleY - 0.5);
158:
159: return pt;
160: }
161:
162: public Point2D mapSourcePoint(Point2D sourcePt) {
163: if (sourcePt == null) {
164: throw new IllegalArgumentException("sourcePt == null!");
165: }
166:
167: Point2D pt = (Point2D) sourcePt.clone();
168: pt.setLocation(minX + (sourcePt.getX() + 0.5 - sourceMinX)
169: * scaleX - 0.5, minY
170: + (sourcePt.getY() + 0.5 - sourceMinY) * scaleY - 0.5);
171:
172: return pt;
173: }
174:
175: protected Rectangle backwardMapRect(Rectangle destRect,
176: int sourceIndex) {
177: if (destRect == null) {
178: throw new IllegalArgumentException(JaiI18N
179: .getString("Generic0"));
180: } else if (sourceIndex != 0) {
181: throw new IllegalArgumentException(JaiI18N
182: .getString("Generic1"));
183: }
184:
185: // Map the upper left pixel.
186: Point2D p1 = mapDestPoint(new Point2D.Double(destRect.x,
187: destRect.y));
188:
189: // Map the lower right pixel.
190: Point2D p2 = mapDestPoint(new Point2D.Double(destRect.x
191: + destRect.width - 1, destRect.y + destRect.height - 1));
192:
193: // Determine the integral positions.
194: int x1 = (int) Math.floor(p1.getX());
195: int y1 = (int) Math.floor(p1.getY());
196: int x2 = (int) Math.ceil(p2.getX());
197: int y2 = (int) Math.ceil(p2.getY());
198:
199: // Return rectangle based on integral positions.
200: return new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
201: }
202:
203: protected Rectangle forwardMapRect(Rectangle sourceRect,
204: int sourceIndex) {
205: if (sourceRect == null) {
206: throw new IllegalArgumentException(JaiI18N
207: .getString("Generic0"));
208: } else if (sourceIndex != 0) {
209: throw new IllegalArgumentException(JaiI18N
210: .getString("Generic1"));
211: }
212:
213: // Map the upper left pixel.
214: Point2D p1 = mapSourcePoint(new Point2D.Double(sourceRect.x,
215: sourceRect.y));
216:
217: // Map the lower right pixel.
218: Point2D p2 = mapSourcePoint(new Point2D.Double(sourceRect.x
219: + sourceRect.width - 1, sourceRect.y
220: + sourceRect.height - 1));
221:
222: // Determine the integral positions.
223: int x1 = (int) Math.floor(p1.getX());
224: int y1 = (int) Math.floor(p1.getY());
225: int x2 = (int) Math.ceil(p2.getX());
226: int y2 = (int) Math.ceil(p2.getY());
227:
228: // Return rectangle based on integral positions.
229: return new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
230: }
231:
232: /**
233: * Performs a subsampling operation on a specified rectangle.
234: * The sources are cobbled.
235: *
236: * @param sources an array of source Rasters, guaranteed to provide all
237: * necessary source data for computing the output.
238: * @param dest a WritableRaster containing the area to be computed.
239: * @param destRect the rectangle within dest to be processed.
240: */
241: protected void computeRect(Raster[] sources, WritableRaster dest,
242: Rectangle destRect) {
243: // Get RasterAccessor tags (initialized in OpImage superclass).
244: RasterFormatTag[] formatTags = getFormatTags();
245:
246: // Get destination accessor.
247: RasterAccessor dst = new RasterAccessor(dest, destRect,
248: formatTags[1], getColorModel());
249:
250: // Backward map destination rectangle to source and clip to the
251: // source image bounds (mapDestRect() does not clip automatically).
252: Rectangle srcRect = mapDestRect(destRect, 0).intersection(
253: sources[0].getBounds());
254:
255: // Get source accessor.
256: RasterAccessor src = new RasterAccessor(sources[0], srcRect,
257: formatTags[0], getSourceImage(0).getColorModel());
258:
259: switch (dst.getDataType()) {
260: case DataBuffer.TYPE_BYTE:
261: computeRectByte(src, dst);
262: break;
263: case DataBuffer.TYPE_USHORT:
264: computeRectUShort(src, dst);
265: break;
266: case DataBuffer.TYPE_SHORT:
267: computeRectShort(src, dst);
268: break;
269: case DataBuffer.TYPE_INT:
270: computeRectInt(src, dst);
271: break;
272: case DataBuffer.TYPE_FLOAT:
273: computeRectFloat(src, dst);
274: break;
275: case DataBuffer.TYPE_DOUBLE:
276: computeRectDouble(src, dst);
277: break;
278: default:
279: throw new RuntimeException(JaiI18N.getString("Generic3"));
280: }
281:
282: // If the RasterAccessor set up a temporary write buffer for the
283: // operator, tell it to copy that data to the destination Raster.
284: if (dst.isDataCopy()) {
285: dst.clampDataArrays();
286: dst.copyDataToRaster();
287: }
288: }
289:
290: private void computeRectByte(RasterAccessor src, RasterAccessor dst) {
291: // Get dimensions.
292: int dwidth = dst.getWidth();
293: int dheight = dst.getHeight();
294: int dnumBands = dst.getNumBands();
295:
296: // Get destination data array references and strides.
297: byte[][] dstDataArrays = dst.getByteDataArrays();
298: int[] dstBandOffsets = dst.getBandOffsets();
299: int dstPixelStride = dst.getPixelStride();
300: int dstScanlineStride = dst.getScanlineStride();
301:
302: // Get source data array references and strides.
303: byte[][] srcDataArrays = src.getByteDataArrays();
304: int[] srcBandOffsets = src.getBandOffsets();
305: int srcPixelStride = src.getPixelStride();
306: int srcScanlineStride = src.getScanlineStride();
307:
308: // Compute scaled source strides.
309: int[] srcPixelStrideScaled = new int[dwidth];
310: for (int i = 0; i < dwidth; i++)
311: srcPixelStrideScaled[i] = (int) Math.floor(i / scaleX)
312: * srcPixelStride;
313:
314: int[] srcScanlineStrideScaled = new int[dheight];
315: for (int i = 0; i < dheight; i++)
316: srcScanlineStrideScaled[i] = (int) Math.floor(i / scaleY)
317: * srcScanlineStride;
318:
319: // Cache the product of the block dimensions.
320: float denom = blockX * blockY;
321:
322: for (int k = 0; k < dnumBands; k++) {
323: byte[] dstData = dstDataArrays[k];
324: byte[] srcData = srcDataArrays[k];
325: int srcScanlineOffset0 = srcBandOffsets[k];
326: int dstScanlineOffset = dstBandOffsets[k];
327: int srcScanlineOffset = srcScanlineOffset0;
328:
329: for (int j = 0; j < dheight; j++) {
330: int srcPixelOffset0 = srcScanlineOffset;
331: int dstPixelOffset = dstScanlineOffset;
332: int srcPixelOffset = srcPixelOffset0;
333:
334: for (int i = 0; i < dwidth; i++) {
335: int imageVerticalOffset = srcPixelOffset;
336:
337: // Average the source over the scale-dependent window.
338: int sum = 0;
339: for (int u = 0; u < blockY; u++) {
340: int imageOffset = imageVerticalOffset;
341: for (int v = 0; v < blockX; v++) {
342: sum += (int) (srcData[imageOffset] & 0xff);
343: imageOffset += srcPixelStride;
344: }
345: imageVerticalOffset += srcScanlineStride;
346: }
347:
348: dstData[dstPixelOffset] = ImageUtil
349: .clampRoundByte(sum / denom);
350:
351: srcPixelOffset = srcPixelOffset0
352: + srcPixelStrideScaled[i];
353: dstPixelOffset += dstPixelStride;
354: }
355: srcScanlineOffset = srcScanlineOffset0
356: + srcScanlineStrideScaled[j];
357: dstScanlineOffset += dstScanlineStride;
358: }
359: }
360: }
361:
362: private void computeRectUShort(RasterAccessor src,
363: RasterAccessor dst) {
364: // Get dimensions.
365: int dwidth = dst.getWidth();
366: int dheight = dst.getHeight();
367: int dnumBands = dst.getNumBands();
368:
369: // Get destination data array references and strides.
370: short[][] dstDataArrays = dst.getShortDataArrays();
371: int[] dstBandOffsets = dst.getBandOffsets();
372: int dstPixelStride = dst.getPixelStride();
373: int dstScanlineStride = dst.getScanlineStride();
374:
375: // Get source data array references and strides.
376: short[][] srcDataArrays = src.getShortDataArrays();
377: int[] srcBandOffsets = src.getBandOffsets();
378: int srcPixelStride = src.getPixelStride();
379: int srcScanlineStride = src.getScanlineStride();
380:
381: // Compute scaled source strides.
382: int[] srcPixelStrideScaled = new int[dwidth];
383: for (int i = 0; i < dwidth; i++)
384: srcPixelStrideScaled[i] = (int) Math.floor(i / scaleX)
385: * srcPixelStride;
386:
387: int[] srcScanlineStrideScaled = new int[dheight];
388: for (int i = 0; i < dheight; i++)
389: srcScanlineStrideScaled[i] = (int) Math.floor(i / scaleY)
390: * srcScanlineStride;
391:
392: // Cache the product of the block dimensions.
393: float denom = blockX * blockY;
394:
395: for (int k = 0; k < dnumBands; k++) {
396: short[] dstData = dstDataArrays[k];
397: short[] srcData = srcDataArrays[k];
398: int srcScanlineOffset0 = srcBandOffsets[k];
399: int dstScanlineOffset = dstBandOffsets[k];
400: int srcScanlineOffset = srcScanlineOffset0;
401:
402: for (int j = 0; j < dheight; j++) {
403: int srcPixelOffset0 = srcScanlineOffset;
404: int dstPixelOffset = dstScanlineOffset;
405: int srcPixelOffset = srcPixelOffset0;
406:
407: for (int i = 0; i < dwidth; i++) {
408: int imageVerticalOffset = srcPixelOffset;
409:
410: // Average the source over the scale-dependent window.
411: long sum = 0;
412: for (int u = 0; u < blockY; u++) {
413: int imageOffset = imageVerticalOffset;
414: for (int v = 0; v < blockX; v++) {
415: sum += (long) (srcData[imageOffset] & 0xffff);
416: imageOffset += srcPixelStride;
417: }
418: imageVerticalOffset += srcScanlineStride;
419: }
420:
421: dstData[dstPixelOffset] = ImageUtil
422: .clampRoundUShort(sum / denom);
423:
424: srcPixelOffset = srcPixelOffset0
425: + srcPixelStrideScaled[i];
426: dstPixelOffset += dstPixelStride;
427: }
428: srcScanlineOffset = srcScanlineOffset0
429: + srcScanlineStrideScaled[j];
430: dstScanlineOffset += dstScanlineStride;
431: }
432: }
433: }
434:
435: private void computeRectShort(RasterAccessor src, RasterAccessor dst) {
436: // Get dimensions.
437: int dwidth = dst.getWidth();
438: int dheight = dst.getHeight();
439: int dnumBands = dst.getNumBands();
440:
441: // Get destination data array references and strides.
442: short[][] dstDataArrays = dst.getShortDataArrays();
443: int[] dstBandOffsets = dst.getBandOffsets();
444: int dstPixelStride = dst.getPixelStride();
445: int dstScanlineStride = dst.getScanlineStride();
446:
447: // Get source data array references and strides.
448: short[][] srcDataArrays = src.getShortDataArrays();
449: int[] srcBandOffsets = src.getBandOffsets();
450: int srcPixelStride = src.getPixelStride();
451: int srcScanlineStride = src.getScanlineStride();
452:
453: // Compute scaled source strides.
454: int[] srcPixelStrideScaled = new int[dwidth];
455: for (int i = 0; i < dwidth; i++)
456: srcPixelStrideScaled[i] = (int) Math.floor(i / scaleX)
457: * srcPixelStride;
458:
459: int[] srcScanlineStrideScaled = new int[dheight];
460: for (int i = 0; i < dheight; i++)
461: srcScanlineStrideScaled[i] = (int) Math.floor(i / scaleY)
462: * srcScanlineStride;
463:
464: // Cache the product of the block dimensions.
465: float denom = blockX * blockY;
466:
467: for (int k = 0; k < dnumBands; k++) {
468: short[] dstData = dstDataArrays[k];
469: short[] srcData = srcDataArrays[k];
470: int srcScanlineOffset0 = srcBandOffsets[k];
471: int dstScanlineOffset = dstBandOffsets[k];
472: int srcScanlineOffset = srcScanlineOffset0;
473:
474: for (int j = 0; j < dheight; j++) {
475: int srcPixelOffset0 = srcScanlineOffset;
476: int dstPixelOffset = dstScanlineOffset;
477: int srcPixelOffset = srcPixelOffset0;
478:
479: for (int i = 0; i < dwidth; i++) {
480: int imageVerticalOffset = srcPixelOffset;
481:
482: // Average the source over the scale-dependent window.
483: long sum = 0;
484: for (int u = 0; u < blockY; u++) {
485: int imageOffset = imageVerticalOffset;
486: for (int v = 0; v < blockX; v++) {
487: sum += srcData[imageOffset];
488: imageOffset += srcPixelStride;
489: }
490: imageVerticalOffset += srcScanlineStride;
491: }
492:
493: dstData[dstPixelOffset] = ImageUtil
494: .clampRoundShort(sum / denom);
495:
496: srcPixelOffset = srcPixelOffset0
497: + srcPixelStrideScaled[i];
498: dstPixelOffset += dstPixelStride;
499: }
500: srcScanlineOffset = srcScanlineOffset0
501: + srcScanlineStrideScaled[j];
502: dstScanlineOffset += dstScanlineStride;
503: }
504: }
505: }
506:
507: private void computeRectInt(RasterAccessor src, RasterAccessor dst) {
508: // Get dimensions.
509: int dwidth = dst.getWidth();
510: int dheight = dst.getHeight();
511: int dnumBands = dst.getNumBands();
512:
513: // Get destination data array references and strides.
514: int[][] dstDataArrays = dst.getIntDataArrays();
515: int[] dstBandOffsets = dst.getBandOffsets();
516: int dstPixelStride = dst.getPixelStride();
517: int dstScanlineStride = dst.getScanlineStride();
518:
519: // Get source data array references and strides.
520: int[][] srcDataArrays = src.getIntDataArrays();
521: int[] srcBandOffsets = src.getBandOffsets();
522: int srcPixelStride = src.getPixelStride();
523: int srcScanlineStride = src.getScanlineStride();
524:
525: // Compute scaled source strides.
526: int[] srcPixelStrideScaled = new int[dwidth];
527: for (int i = 0; i < dwidth; i++)
528: srcPixelStrideScaled[i] = (int) Math.floor(i / scaleX)
529: * srcPixelStride;
530:
531: int[] srcScanlineStrideScaled = new int[dheight];
532: for (int i = 0; i < dheight; i++)
533: srcScanlineStrideScaled[i] = (int) Math.floor(i / scaleY)
534: * srcScanlineStride;
535:
536: // Cache the product of the block dimensions.
537: float denom = blockX * blockY;
538:
539: for (int k = 0; k < dnumBands; k++) {
540: int[] dstData = dstDataArrays[k];
541: int[] srcData = srcDataArrays[k];
542: int srcScanlineOffset0 = srcBandOffsets[k];
543: int dstScanlineOffset = dstBandOffsets[k];
544: int srcScanlineOffset = srcScanlineOffset0;
545:
546: for (int j = 0; j < dheight; j++) {
547: int srcPixelOffset0 = srcScanlineOffset;
548: int dstPixelOffset = dstScanlineOffset;
549: int srcPixelOffset = srcPixelOffset0;
550:
551: for (int i = 0; i < dwidth; i++) {
552: int imageVerticalOffset = srcPixelOffset;
553:
554: // Average the source over the scale-dependent window.
555: double sum = 0;
556: for (int u = 0; u < blockY; u++) {
557: int imageOffset = imageVerticalOffset;
558: for (int v = 0; v < blockX; v++) {
559: sum += srcData[imageOffset];
560: imageOffset += srcPixelStride;
561: }
562: imageVerticalOffset += srcScanlineStride;
563: }
564:
565: dstData[dstPixelOffset] = ImageUtil
566: .clampRoundInt(sum / denom);
567:
568: srcPixelOffset = srcPixelOffset0
569: + srcPixelStrideScaled[i];
570: dstPixelOffset += dstPixelStride;
571: }
572: srcScanlineOffset = srcScanlineOffset0
573: + srcScanlineStrideScaled[j];
574: dstScanlineOffset += dstScanlineStride;
575: }
576: }
577: }
578:
579: private void computeRectFloat(RasterAccessor src, RasterAccessor dst) {
580: // Get dimensions.
581: int dwidth = dst.getWidth();
582: int dheight = dst.getHeight();
583: int dnumBands = dst.getNumBands();
584:
585: // Get destination data array references and strides.
586: float[][] dstDataArrays = dst.getFloatDataArrays();
587: int[] dstBandOffsets = dst.getBandOffsets();
588: int dstPixelStride = dst.getPixelStride();
589: int dstScanlineStride = dst.getScanlineStride();
590:
591: // Get source data array references and strides.
592: float[][] srcDataArrays = src.getFloatDataArrays();
593: int[] srcBandOffsets = src.getBandOffsets();
594: int srcPixelStride = src.getPixelStride();
595: int srcScanlineStride = src.getScanlineStride();
596:
597: // Compute scaled source strides.
598: int[] srcPixelStrideScaled = new int[dwidth];
599: for (int i = 0; i < dwidth; i++)
600: srcPixelStrideScaled[i] = (int) Math.floor(i / scaleX)
601: * srcPixelStride;
602:
603: int[] srcScanlineStrideScaled = new int[dheight];
604: for (int i = 0; i < dheight; i++)
605: srcScanlineStrideScaled[i] = (int) Math.floor(i / scaleY)
606: * srcScanlineStride;
607:
608: // Cache the product of the block dimensions.
609: float denom = blockX * blockY;
610:
611: for (int k = 0; k < dnumBands; k++) {
612: float[] dstData = dstDataArrays[k];
613: float[] srcData = srcDataArrays[k];
614: int srcScanlineOffset0 = srcBandOffsets[k];
615: int dstScanlineOffset = dstBandOffsets[k];
616: int srcScanlineOffset = srcScanlineOffset0;
617:
618: for (int j = 0; j < dheight; j++) {
619: int srcPixelOffset0 = srcScanlineOffset;
620: int dstPixelOffset = dstScanlineOffset;
621: int srcPixelOffset = srcPixelOffset0;
622:
623: for (int i = 0; i < dwidth; i++) {
624: int imageVerticalOffset = srcPixelOffset;
625:
626: // Average the source over the scale-dependent window.
627: double sum = 0;
628: for (int u = 0; u < blockY; u++) {
629: int imageOffset = imageVerticalOffset;
630: for (int v = 0; v < blockX; v++) {
631: sum += srcData[imageOffset];
632: imageOffset += srcPixelStride;
633: }
634: imageVerticalOffset += srcScanlineStride;
635: }
636:
637: dstData[dstPixelOffset] = ImageUtil.clampFloat(sum
638: / denom);
639:
640: srcPixelOffset = srcPixelOffset0
641: + srcPixelStrideScaled[i];
642: dstPixelOffset += dstPixelStride;
643: }
644: srcScanlineOffset = srcScanlineOffset0
645: + srcScanlineStrideScaled[j];
646: dstScanlineOffset += dstScanlineStride;
647: }
648: }
649: }
650:
651: private void computeRectDouble(RasterAccessor src,
652: RasterAccessor dst) {
653: // Get dimensions.
654: int dwidth = dst.getWidth();
655: int dheight = dst.getHeight();
656: int dnumBands = dst.getNumBands();
657:
658: // Get destination data array references and strides.
659: double[][] dstDataArrays = dst.getDoubleDataArrays();
660: int[] dstBandOffsets = dst.getBandOffsets();
661: int dstPixelStride = dst.getPixelStride();
662: int dstScanlineStride = dst.getScanlineStride();
663:
664: // Get source data array references and strides.
665: double[][] srcDataArrays = src.getDoubleDataArrays();
666: int[] srcBandOffsets = src.getBandOffsets();
667: int srcPixelStride = src.getPixelStride();
668: int srcScanlineStride = src.getScanlineStride();
669:
670: // Compute scaled source strides.
671: int[] srcPixelStrideScaled = new int[dwidth];
672: for (int i = 0; i < dwidth; i++)
673: srcPixelStrideScaled[i] = (int) Math.floor(i / scaleX)
674: * srcPixelStride;
675:
676: int[] srcScanlineStrideScaled = new int[dheight];
677: for (int i = 0; i < dheight; i++)
678: srcScanlineStrideScaled[i] = (int) Math.floor(i / scaleY)
679: * srcScanlineStride;
680:
681: // Cache the product of the block dimensions.
682: double denom = blockX * blockY;
683:
684: for (int k = 0; k < dnumBands; k++) {
685: double[] dstData = dstDataArrays[k];
686: double[] srcData = srcDataArrays[k];
687: int srcScanlineOffset0 = srcBandOffsets[k];
688: int dstScanlineOffset = dstBandOffsets[k];
689: int srcScanlineOffset = srcScanlineOffset0;
690:
691: for (int j = 0; j < dheight; j++) {
692: int srcPixelOffset0 = srcScanlineOffset;
693: int dstPixelOffset = dstScanlineOffset;
694: int srcPixelOffset = srcPixelOffset0;
695:
696: for (int i = 0; i < dwidth; i++) {
697: int imageVerticalOffset = srcPixelOffset;
698:
699: // Average the source over the scale-dependent window.
700: double sum = 0;
701: for (int u = 0; u < blockY; u++) {
702: int imageOffset = imageVerticalOffset;
703: for (int v = 0; v < blockX; v++) {
704: sum += srcData[imageOffset];
705: imageOffset += srcPixelStride;
706: }
707: imageVerticalOffset += srcScanlineStride;
708: }
709:
710: dstData[dstPixelOffset] = sum / denom;
711:
712: srcPixelOffset = srcPixelOffset0
713: + srcPixelStrideScaled[i];
714: dstPixelOffset += dstPixelStride;
715: }
716: srcScanlineOffset = srcScanlineOffset0
717: + srcScanlineStrideScaled[j];
718: dstScanlineOffset += dstScanlineStride;
719: }
720: }
721: }
722: }
|