001: /*
002: * $RCSfile: MeanOpImage.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:33 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.Image;
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.util.Hashtable;
020: import java.util.LinkedList;
021: import java.util.ListIterator;
022: import javax.media.jai.ImageLayout;
023: import javax.media.jai.OpImage;
024: import javax.media.jai.PixelAccessor;
025: import javax.media.jai.PlanarImage;
026: import javax.media.jai.RasterAccessor;
027: import javax.media.jai.RasterFormatTag;
028: import javax.media.jai.ROI;
029: import javax.media.jai.StatisticsOpImage;
030: import javax.media.jai.UnpackedImageData;
031:
032: /**
033: * An <code>OpImage</code> implementing the "Mean" operation as
034: * described in <code>javax.media.jai.operator.MeanDescriptor</code>.
035: *
036: * @since EA2
037: * @see javax.media.jai.operator.MeanDescriptor
038: * @see MeanCRIF
039: *
040: */
041: public class MeanOpImage extends StatisticsOpImage {
042:
043: private boolean isInitialized = false;
044:
045: /**
046: * Note: For very large images, these two variables may be overflowed.
047: * An alternative would be to have a set for each tile. But then, the
048: * user could specify very large tile size.
049: */
050: private double[] totalPixelValue;
051: private int totalPixelCount;
052:
053: private PixelAccessor srcPA;
054:
055: private int srcSampleType;
056:
057: private final boolean tileIntersectsROI(int tileX, int tileY) {
058: if (roi == null) { // ROI is entire tile
059: return true;
060: } else {
061: return roi.intersects(tileXToX(tileX), tileYToY(tileY),
062: tileWidth, tileHeight);
063: }
064: }
065:
066: /**
067: * Constructs an <code>MeanOpImage</code>.
068: *
069: * @param source The source image.
070: */
071: public MeanOpImage(RenderedImage source, ROI roi, int xStart,
072: int yStart, int xPeriod, int yPeriod) {
073: super (source, roi, xStart, yStart, xPeriod, yPeriod);
074: }
075:
076: protected String[] getStatisticsNames() {
077: return new String[] { "mean" };
078: }
079:
080: protected Object createStatistics(String name) {
081: Object stats;
082:
083: if (name.equalsIgnoreCase("mean")) {
084: stats = new double[sampleModel.getNumBands()];
085: } else {
086: stats = java.awt.Image.UndefinedProperty;
087: }
088: return stats;
089: }
090:
091: private final int startPosition(int pos, int start, int period) {
092: int t = (pos - start) % period;
093: if (t == 0) {
094: return pos;
095: } else {
096: return (pos + (period - t));
097: }
098: }
099:
100: protected void accumulateStatistics(String name, Raster source,
101: Object stats) {
102: if (!isInitialized) {
103: srcPA = new PixelAccessor(getSourceImage(0));
104: srcSampleType = srcPA.sampleType == PixelAccessor.TYPE_BIT ? DataBuffer.TYPE_BYTE
105: : srcPA.sampleType;
106:
107: totalPixelValue = new double[srcPA.numBands];
108: totalPixelCount = 0;
109: isInitialized = true;
110: }
111:
112: Rectangle srcBounds = getSourceImage(0).getBounds()
113: .intersection(source.getBounds());
114:
115: LinkedList rectList;
116: if (roi == null) { // ROI is the whole Raster
117: rectList = new LinkedList();
118: rectList.addLast(srcBounds);
119: } else {
120: rectList = roi.getAsRectangleList(srcBounds.x, srcBounds.y,
121: srcBounds.width, srcBounds.height);
122: if (rectList == null) {
123: return; // ROI does not intersect with Raster boundary.
124: }
125: }
126: ListIterator iterator = rectList.listIterator(0);
127:
128: while (iterator.hasNext()) {
129: Rectangle rect = srcBounds
130: .intersection((Rectangle) iterator.next());
131: int tx = rect.x;
132: int ty = rect.y;
133:
134: /* Find the actual ROI based on start and period. */
135: rect.x = startPosition(tx, xStart, xPeriod);
136: rect.y = startPosition(ty, yStart, yPeriod);
137: rect.width = tx + rect.width - rect.x;
138: rect.height = ty + rect.height - rect.y;
139:
140: if (rect.isEmpty()) {
141: continue; // no pixel to count in this rectangle
142: }
143:
144: UnpackedImageData uid = srcPA.getPixels(source, rect,
145: srcSampleType, false);
146:
147: switch (uid.type) {
148: case DataBuffer.TYPE_BYTE:
149: accumulateStatisticsByte(uid);
150: break;
151: case DataBuffer.TYPE_USHORT:
152: accumulateStatisticsUShort(uid);
153: break;
154: case DataBuffer.TYPE_SHORT:
155: accumulateStatisticsShort(uid);
156: break;
157: case DataBuffer.TYPE_INT:
158: accumulateStatisticsInt(uid);
159: break;
160: case DataBuffer.TYPE_FLOAT:
161: accumulateStatisticsFloat(uid);
162: break;
163: case DataBuffer.TYPE_DOUBLE:
164: accumulateStatisticsDouble(uid);
165: break;
166: }
167: }
168:
169: if (name.equalsIgnoreCase("mean")) {
170: // This is a totally disgusting hack but no worse than the
171: // code was before ... bpb 1 September 2000
172: double[] mean = (double[]) stats;
173: if (totalPixelCount != 0) {
174: for (int i = 0; i < srcPA.numBands; i++) {
175: mean[i] = totalPixelValue[i]
176: / (double) totalPixelCount;
177: }
178: }
179: }
180: }
181:
182: private void accumulateStatisticsByte(UnpackedImageData uid) {
183: Rectangle rect = uid.rect;
184: byte[][] data = uid.getByteData();
185: int lineStride = uid.lineStride;
186: int pixelStride = uid.pixelStride;
187:
188: int lineInc = lineStride * yPeriod;
189: int pixelInc = pixelStride * xPeriod;
190:
191: for (int b = 0; b < srcPA.numBands; b++) {
192: byte[] d = data[b];
193: int lastLine = uid.bandOffsets[b] + rect.height
194: * lineStride;
195:
196: for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) {
197: int lastPixel = lo + rect.width * pixelStride;
198:
199: for (int po = lo; po < lastPixel; po += pixelInc) {
200: totalPixelValue[b] += d[po] & 0xff;
201: }
202: }
203: }
204: totalPixelCount += (int) Math.ceil((double) rect.height
205: / yPeriod)
206: * (int) Math.ceil((double) rect.width / xPeriod);
207: }
208:
209: private void accumulateStatisticsUShort(UnpackedImageData uid) {
210: Rectangle rect = uid.rect;
211: short[][] data = uid.getShortData();
212: int lineStride = uid.lineStride;
213: int pixelStride = uid.pixelStride;
214:
215: int lineInc = lineStride * yPeriod;
216: int pixelInc = pixelStride * xPeriod;
217:
218: for (int b = 0; b < srcPA.numBands; b++) {
219: short[] d = data[b];
220: int lastLine = uid.bandOffsets[b] + rect.height
221: * lineStride;
222:
223: for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) {
224: int lastPixel = lo + rect.width * pixelStride;
225:
226: for (int po = lo; po < lastPixel; po += pixelInc) {
227: totalPixelValue[b] += d[po] & 0xffff;
228: }
229: }
230: }
231: totalPixelCount += (int) Math.ceil((double) rect.height
232: / yPeriod)
233: * (int) Math.ceil((double) rect.width / xPeriod);
234: }
235:
236: private void accumulateStatisticsShort(UnpackedImageData uid) {
237: Rectangle rect = uid.rect;
238: short[][] data = uid.getShortData();
239: int lineStride = uid.lineStride;
240: int pixelStride = uid.pixelStride;
241:
242: int lineInc = lineStride * yPeriod;
243: int pixelInc = pixelStride * xPeriod;
244:
245: for (int b = 0; b < srcPA.numBands; b++) {
246: short[] d = data[b];
247: int lastLine = uid.bandOffsets[b] + rect.height
248: * lineStride;
249:
250: for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) {
251: int lastPixel = lo + rect.width * pixelStride;
252:
253: for (int po = lo; po < lastPixel; po += pixelInc) {
254: totalPixelValue[b] += d[po];
255: }
256: }
257: }
258: totalPixelCount += (int) Math.ceil((double) rect.height
259: / yPeriod)
260: * (int) Math.ceil((double) rect.width / xPeriod);
261: }
262:
263: private void accumulateStatisticsInt(UnpackedImageData uid) {
264: Rectangle rect = uid.rect;
265: int[][] data = uid.getIntData();
266: int lineStride = uid.lineStride;
267: int pixelStride = uid.pixelStride;
268:
269: int lineInc = lineStride * yPeriod;
270: int pixelInc = pixelStride * xPeriod;
271:
272: for (int b = 0; b < srcPA.numBands; b++) {
273: int[] d = data[b];
274: int lastLine = uid.bandOffsets[b] + rect.height
275: * lineStride;
276:
277: for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) {
278: int lastPixel = lo + rect.width * pixelStride;
279:
280: for (int po = lo; po < lastPixel; po += pixelInc) {
281: totalPixelValue[b] += d[po];
282: }
283: }
284: }
285: totalPixelCount += (int) Math.ceil((double) rect.height
286: / yPeriod)
287: * (int) Math.ceil((double) rect.width / xPeriod);
288: }
289:
290: private void accumulateStatisticsFloat(UnpackedImageData uid) {
291: Rectangle rect = uid.rect;
292: float[][] data = uid.getFloatData();
293: int lineStride = uid.lineStride;
294: int pixelStride = uid.pixelStride;
295:
296: int lineInc = lineStride * yPeriod;
297: int pixelInc = pixelStride * xPeriod;
298:
299: for (int b = 0; b < srcPA.numBands; b++) {
300: float[] d = data[b];
301: int lastLine = uid.bandOffsets[b] + rect.height
302: * lineStride;
303:
304: for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) {
305: int lastPixel = lo + rect.width * pixelStride;
306:
307: for (int po = lo; po < lastPixel; po += pixelInc) {
308: totalPixelValue[b] += d[po];
309: }
310: }
311: }
312: totalPixelCount += (int) Math.ceil((double) rect.height
313: / yPeriod)
314: * (int) Math.ceil((double) rect.width / xPeriod);
315: }
316:
317: private void accumulateStatisticsDouble(UnpackedImageData uid) {
318: Rectangle rect = uid.rect;
319: double[][] data = uid.getDoubleData();
320: int lineStride = uid.lineStride;
321: int pixelStride = uid.pixelStride;
322:
323: int lineInc = lineStride * yPeriod;
324: int pixelInc = pixelStride * xPeriod;
325:
326: for (int b = 0; b < srcPA.numBands; b++) {
327: double[] d = data[b];
328: int lastLine = uid.bandOffsets[b] + rect.height
329: * lineStride;
330:
331: for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) {
332: int lastPixel = lo + rect.width * pixelStride;
333:
334: for (int po = lo; po < lastPixel; po += pixelInc) {
335: totalPixelValue[b] += d[po];
336: }
337: }
338: }
339: totalPixelCount += (int) Math.ceil((double) rect.height
340: / yPeriod)
341: * (int) Math.ceil((double) rect.width / xPeriod);
342: }
343: }
|