001: /*
002: * $RCSfile: MedianFilterSeparableOpImage.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:34 $
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.OpImage;
026: import javax.media.jai.RasterAccessor;
027: import java.util.Map;
028: import javax.media.jai.operator.MedianFilterDescriptor;
029: import com.sun.media.jai.opimage.MedianFilterOpImage;
030:
031: // import com.sun.media.jai.test.OpImageTester;
032:
033: /**
034: * An OpImage class to perform median filtering on a source image.
035: *
036: *
037: */
038: final class MedianFilterSeparableOpImage extends MedianFilterOpImage {
039:
040: /**
041: * Creates a MedianFilterSeperableOpImage with the given source and
042: * maskSize. The image dimensions are derived from the source
043: * image. The tile grid layout, SampleModel, and ColorModel may
044: * optionally be specified by an ImageLayout object.
045: *
046: * @param source a RenderedImage.
047: * @param extender a BorderExtender, or null.
048: * @param layout an ImageLayout optionally containing the tile grid layout,
049: * SampleModel, and ColorModel, or null.
050: * @param maskSize the mask size.
051: */
052: public MedianFilterSeparableOpImage(RenderedImage source,
053: BorderExtender extender, Map config, ImageLayout layout,
054: int maskSize) {
055: super (source, extender, config, layout,
056: MedianFilterDescriptor.MEDIAN_MASK_SQUARE, maskSize);
057: }
058:
059: protected void byteLoop(RasterAccessor src, RasterAccessor dst,
060: int filterSize) {
061: int dwidth = dst.getWidth();
062: int dheight = dst.getHeight();
063: int dnumBands = dst.getNumBands();
064:
065: byte dstDataArrays[][] = dst.getByteDataArrays();
066: int dstBandOffsets[] = dst.getBandOffsets();
067: int dstPixelStride = dst.getPixelStride();
068: int dstScanlineStride = dst.getScanlineStride();
069:
070: byte srcDataArrays[][] = src.getByteDataArrays();
071: int srcBandOffsets[] = src.getBandOffsets();
072: int srcPixelStride = src.getPixelStride();
073: int srcScanlineStride = src.getScanlineStride();
074:
075: int medianValues[] = new int[filterSize];
076: int tmpValues[] = new int[filterSize];
077: int wp = filterSize;
078: int tmpBuffer[] = new int[filterSize * dwidth];
079: int tmpBufferSize = filterSize * dwidth;
080:
081: for (int k = 0; k < dnumBands; k++) {
082: byte dstData[] = dstDataArrays[k];
083: byte srcData[] = srcDataArrays[k];
084: int srcScanlineOffset = srcBandOffsets[k];
085: int dstScanlineOffset = dstBandOffsets[k];
086:
087: int revolver = 0;
088: for (int j = 0; j < filterSize - 1; j++) {
089: int srcPixelOffset = srcScanlineOffset;
090:
091: for (int i = 0; i < dwidth; i++) {
092: int imageOffset = srcPixelOffset;
093: for (int v = 0; v < wp; v++) {
094: tmpValues[v] = srcData[imageOffset] & 0xff;
095: imageOffset += srcPixelStride;
096: }
097: tmpBuffer[revolver + i] = medianFilter(tmpValues);
098: srcPixelOffset += srcPixelStride;
099: }
100: revolver += dwidth;
101: srcScanlineOffset += srcScanlineStride;
102: }
103:
104: // srcScanlineStride already bumped by
105: // filterSize-1*scanlineStride
106:
107: for (int j = 0; j < dheight; j++) {
108: int srcPixelOffset = srcScanlineOffset;
109: int dstPixelOffset = dstScanlineOffset;
110:
111: for (int i = 0; i < dwidth; i++) {
112: int imageOffset = srcPixelOffset;
113: for (int v = 0; v < wp; v++) {
114: tmpValues[v] = srcData[imageOffset] & 0xff;
115: imageOffset += srcPixelStride;
116: }
117: tmpBuffer[revolver + i] = medianFilter(tmpValues);
118:
119: int a = 0;
120: for (int b = i; b < tmpBufferSize; b += dwidth) {
121: medianValues[a++] = tmpBuffer[b];
122: }
123: int val = medianFilter(medianValues);
124:
125: dstData[dstPixelOffset] = (byte) val;
126: srcPixelOffset += srcPixelStride;
127: dstPixelOffset += dstPixelStride;
128: }
129:
130: revolver += dwidth;
131: if (revolver == tmpBufferSize) {
132: revolver = 0;
133: }
134:
135: srcScanlineOffset += srcScanlineStride;
136: dstScanlineOffset += dstScanlineStride;
137: }
138: }
139: }
140:
141: protected void shortLoop(RasterAccessor src, RasterAccessor dst,
142: int filterSize) {
143: int dwidth = dst.getWidth();
144: int dheight = dst.getHeight();
145: int dnumBands = dst.getNumBands();
146:
147: short dstDataArrays[][] = dst.getShortDataArrays();
148: int dstBandOffsets[] = dst.getBandOffsets();
149: int dstPixelStride = dst.getPixelStride();
150: int dstScanlineStride = dst.getScanlineStride();
151:
152: short srcDataArrays[][] = src.getShortDataArrays();
153: int srcBandOffsets[] = src.getBandOffsets();
154: int srcPixelStride = src.getPixelStride();
155: int srcScanlineStride = src.getScanlineStride();
156:
157: int medianValues[] = new int[filterSize];
158: int tmpValues[] = new int[filterSize];
159: int wp = filterSize;
160: int tmpBuffer[] = new int[filterSize * dwidth];
161: int tmpBufferSize = filterSize * dwidth;
162:
163: for (int k = 0; k < dnumBands; k++) {
164: short dstData[] = dstDataArrays[k];
165: short srcData[] = srcDataArrays[k];
166: int srcScanlineOffset = srcBandOffsets[k];
167: int dstScanlineOffset = dstBandOffsets[k];
168:
169: int revolver = 0;
170: for (int j = 0; j < filterSize - 1; j++) {
171: int srcPixelOffset = srcScanlineOffset;
172:
173: for (int i = 0; i < dwidth; i++) {
174: int imageOffset = srcPixelOffset;
175: for (int v = 0; v < wp; v++) {
176: tmpValues[v] = srcData[imageOffset];
177: imageOffset += srcPixelStride;
178: }
179: tmpBuffer[revolver + i] = medianFilter(tmpValues);
180: srcPixelOffset += srcPixelStride;
181: }
182: revolver += dwidth;
183: srcScanlineOffset += srcScanlineStride;
184: }
185:
186: // srcScanlineStride already bumped by
187: // filterSize-1*scanlineStride
188:
189: for (int j = 0; j < dheight; j++) {
190: int srcPixelOffset = srcScanlineOffset;
191: int dstPixelOffset = dstScanlineOffset;
192:
193: for (int i = 0; i < dwidth; i++) {
194: int imageOffset = srcPixelOffset;
195: for (int v = 0; v < wp; v++) {
196: tmpValues[v] = srcData[imageOffset];
197: imageOffset += srcPixelStride;
198: }
199: tmpBuffer[revolver + i] = medianFilter(tmpValues);
200:
201: int a = 0;
202: for (int b = i; b < tmpBufferSize; b += dwidth) {
203: medianValues[a++] = tmpBuffer[b];
204: }
205: int val = medianFilter(medianValues);
206:
207: dstData[dstPixelOffset] = (short) val;
208: srcPixelOffset += srcPixelStride;
209: dstPixelOffset += dstPixelStride;
210: }
211: revolver += dwidth;
212: if (revolver == tmpBufferSize) {
213: revolver = 0;
214: }
215: srcScanlineOffset += srcScanlineStride;
216: dstScanlineOffset += dstScanlineStride;
217: }
218: }
219:
220: }
221:
222: protected void ushortLoop(RasterAccessor src, RasterAccessor dst,
223: int filterSize) {
224: int dwidth = dst.getWidth();
225: int dheight = dst.getHeight();
226: int dnumBands = dst.getNumBands();
227:
228: short dstDataArrays[][] = dst.getShortDataArrays();
229: int dstBandOffsets[] = dst.getBandOffsets();
230: int dstPixelStride = dst.getPixelStride();
231: int dstScanlineStride = dst.getScanlineStride();
232:
233: short srcDataArrays[][] = src.getShortDataArrays();
234: int srcBandOffsets[] = src.getBandOffsets();
235: int srcPixelStride = src.getPixelStride();
236: int srcScanlineStride = src.getScanlineStride();
237:
238: int medianValues[] = new int[filterSize];
239: int tmpValues[] = new int[filterSize];
240: int wp = filterSize;
241: int tmpBuffer[] = new int[filterSize * dwidth];
242: int tmpBufferSize = filterSize * dwidth;
243:
244: for (int k = 0; k < dnumBands; k++) {
245: short dstData[] = dstDataArrays[k];
246: short srcData[] = srcDataArrays[k];
247: int srcScanlineOffset = srcBandOffsets[k];
248: int dstScanlineOffset = dstBandOffsets[k];
249:
250: int revolver = 0;
251: for (int j = 0; j < filterSize - 1; j++) {
252: int srcPixelOffset = srcScanlineOffset;
253:
254: for (int i = 0; i < dwidth; i++) {
255: int imageOffset = srcPixelOffset;
256: for (int v = 0; v < wp; v++) {
257: tmpValues[v] = srcData[imageOffset] & 0xfff;
258: imageOffset += srcPixelStride;
259: }
260: tmpBuffer[revolver + i] = medianFilter(tmpValues);
261: srcPixelOffset += srcPixelStride;
262: }
263: revolver += dwidth;
264: srcScanlineOffset += srcScanlineStride;
265: }
266:
267: // srcScanlineStride already bumped by
268: // filterSize-1*scanlineStride
269:
270: for (int j = 0; j < dheight; j++) {
271: int srcPixelOffset = srcScanlineOffset;
272: int dstPixelOffset = dstScanlineOffset;
273:
274: for (int i = 0; i < dwidth; i++) {
275: int imageOffset = srcPixelOffset;
276: for (int v = 0; v < wp; v++) {
277: tmpValues[v] = srcData[imageOffset] & 0xffff;
278: imageOffset += srcPixelStride;
279: }
280: tmpBuffer[revolver + i] = medianFilter(tmpValues);
281:
282: int a = 0;
283: for (int b = i; b < tmpBufferSize; b += dwidth) {
284: medianValues[a++] = tmpBuffer[b];
285: }
286: int val = medianFilter(medianValues);
287:
288: dstData[dstPixelOffset] = (short) val;
289: srcPixelOffset += srcPixelStride;
290: dstPixelOffset += dstPixelStride;
291: }
292: revolver += dwidth;
293: if (revolver == tmpBufferSize) {
294: revolver = 0;
295: }
296: srcScanlineOffset += srcScanlineStride;
297: dstScanlineOffset += dstScanlineStride;
298: }
299: }
300: }
301:
302: protected void intLoop(RasterAccessor src, RasterAccessor dst,
303: int filterSize) {
304: int dwidth = dst.getWidth();
305: int dheight = dst.getHeight();
306: int dnumBands = dst.getNumBands();
307:
308: int dstDataArrays[][] = dst.getIntDataArrays();
309: int dstBandOffsets[] = dst.getBandOffsets();
310: int dstPixelStride = dst.getPixelStride();
311: int dstScanlineStride = dst.getScanlineStride();
312:
313: int srcDataArrays[][] = src.getIntDataArrays();
314: int srcBandOffsets[] = src.getBandOffsets();
315: int srcPixelStride = src.getPixelStride();
316: int srcScanlineStride = src.getScanlineStride();
317:
318: int medianValues[] = new int[filterSize];
319: int tmpValues[] = new int[filterSize];
320: int wp = filterSize;
321: int tmpBuffer[] = new int[filterSize * dwidth];
322: int tmpBufferSize = filterSize * dwidth;
323:
324: for (int k = 0; k < dnumBands; k++) {
325: int dstData[] = dstDataArrays[k];
326: int srcData[] = srcDataArrays[k];
327: int srcScanlineOffset = srcBandOffsets[k];
328: int dstScanlineOffset = dstBandOffsets[k];
329:
330: int revolver = 0;
331: for (int j = 0; j < filterSize - 1; j++) {
332: int srcPixelOffset = srcScanlineOffset;
333:
334: for (int i = 0; i < dwidth; i++) {
335: int imageOffset = srcPixelOffset;
336: for (int v = 0; v < wp; v++) {
337: tmpValues[v] = srcData[imageOffset];
338: imageOffset += srcPixelStride;
339: }
340: tmpBuffer[revolver + i] = medianFilter(tmpValues);
341: srcPixelOffset += srcPixelStride;
342: }
343: revolver += dwidth;
344: srcScanlineOffset += srcScanlineStride;
345: }
346:
347: // srcScanlineStride already bumped by
348: // filterSize-1*scanlineStride
349:
350: for (int j = 0; j < dheight; j++) {
351: int srcPixelOffset = srcScanlineOffset;
352: int dstPixelOffset = dstScanlineOffset;
353:
354: for (int i = 0; i < dwidth; i++) {
355: int imageOffset = srcPixelOffset;
356: for (int v = 0; v < wp; v++) {
357: tmpValues[v] = srcData[imageOffset];
358: imageOffset += srcPixelStride;
359: }
360: tmpBuffer[revolver + i] = medianFilter(tmpValues);
361:
362: int a = 0;
363: for (int b = i; b < tmpBufferSize; b += dwidth) {
364: medianValues[a++] = tmpBuffer[b];
365: }
366: int val = medianFilter(medianValues);
367:
368: dstData[dstPixelOffset] = val;
369: srcPixelOffset += srcPixelStride;
370: dstPixelOffset += dstPixelStride;
371: }
372: revolver += dwidth;
373: if (revolver == tmpBufferSize) {
374: revolver = 0;
375: }
376: srcScanlineOffset += srcScanlineStride;
377: dstScanlineOffset += dstScanlineStride;
378: }
379: }
380:
381: }
382:
383: protected void floatLoop(RasterAccessor src, RasterAccessor dst,
384: int filterSize) {
385: int dwidth = dst.getWidth();
386: int dheight = dst.getHeight();
387: int dnumBands = dst.getNumBands();
388:
389: float dstDataArrays[][] = dst.getFloatDataArrays();
390: int dstBandOffsets[] = dst.getBandOffsets();
391: int dstPixelStride = dst.getPixelStride();
392: int dstScanlineStride = dst.getScanlineStride();
393:
394: float srcDataArrays[][] = src.getFloatDataArrays();
395: int srcBandOffsets[] = src.getBandOffsets();
396: int srcPixelStride = src.getPixelStride();
397: int srcScanlineStride = src.getScanlineStride();
398:
399: float medianValues[] = new float[filterSize];
400: float tmpValues[] = new float[filterSize];
401: int wp = filterSize;
402: float tmpBuffer[] = new float[filterSize * dwidth];
403: int tmpBufferSize = filterSize * dwidth;
404:
405: for (int k = 0; k < dnumBands; k++) {
406: float dstData[] = dstDataArrays[k];
407: float srcData[] = srcDataArrays[k];
408: int srcScanlineOffset = srcBandOffsets[k];
409: int dstScanlineOffset = dstBandOffsets[k];
410:
411: int revolver = 0;
412: for (int j = 0; j < filterSize - 1; j++) {
413: int srcPixelOffset = srcScanlineOffset;
414:
415: for (int i = 0; i < dwidth; i++) {
416: int imageOffset = srcPixelOffset;
417: for (int v = 0; v < wp; v++) {
418: tmpValues[v] = srcData[imageOffset];
419: imageOffset += srcPixelStride;
420: }
421: tmpBuffer[revolver + i] = medianFilterFloat(tmpValues);
422: srcPixelOffset += srcPixelStride;
423: }
424: revolver += dwidth;
425: srcScanlineOffset += srcScanlineStride;
426: }
427:
428: // srcScanlineStride already bumped by
429: // filterSize-1*scanlineStride
430:
431: for (int j = 0; j < dheight; j++) {
432: int srcPixelOffset = srcScanlineOffset;
433: int dstPixelOffset = dstScanlineOffset;
434:
435: for (int i = 0; i < dwidth; i++) {
436: int imageOffset = srcPixelOffset;
437: for (int v = 0; v < wp; v++) {
438: tmpValues[v] = srcData[imageOffset];
439: imageOffset += srcPixelStride;
440: }
441: tmpBuffer[revolver + i] = medianFilterFloat(tmpValues);
442:
443: int a = 0;
444: for (int b = i; b < tmpBufferSize; b += dwidth) {
445: medianValues[a++] = tmpBuffer[b];
446: }
447: float val = medianFilterFloat(medianValues);
448:
449: dstData[dstPixelOffset] = val;
450: srcPixelOffset += srcPixelStride;
451: dstPixelOffset += dstPixelStride;
452: }
453: revolver += dwidth;
454: if (revolver == tmpBufferSize) {
455: revolver = 0;
456: }
457: srcScanlineOffset += srcScanlineStride;
458: dstScanlineOffset += dstScanlineStride;
459: }
460: }
461: }
462:
463: protected void doubleLoop(RasterAccessor src, RasterAccessor dst,
464: int filterSize) {
465: int dwidth = dst.getWidth();
466: int dheight = dst.getHeight();
467: int dnumBands = dst.getNumBands();
468:
469: double dstDataArrays[][] = dst.getDoubleDataArrays();
470: int dstBandOffsets[] = dst.getBandOffsets();
471: int dstPixelStride = dst.getPixelStride();
472: int dstScanlineStride = dst.getScanlineStride();
473:
474: double srcDataArrays[][] = src.getDoubleDataArrays();
475: int srcBandOffsets[] = src.getBandOffsets();
476: int srcPixelStride = src.getPixelStride();
477: int srcScanlineStride = src.getScanlineStride();
478:
479: double medianValues[] = new double[filterSize];
480: double tmpValues[] = new double[filterSize];
481: int wp = filterSize;
482: double tmpBuffer[] = new double[filterSize * dwidth];
483: int tmpBufferSize = filterSize * dwidth;
484:
485: for (int k = 0; k < dnumBands; k++) {
486: double dstData[] = dstDataArrays[k];
487: double srcData[] = srcDataArrays[k];
488: int srcScanlineOffset = srcBandOffsets[k];
489: int dstScanlineOffset = dstBandOffsets[k];
490:
491: int revolver = 0;
492: for (int j = 0; j < filterSize - 1; j++) {
493: int srcPixelOffset = srcScanlineOffset;
494:
495: for (int i = 0; i < dwidth; i++) {
496: int imageOffset = srcPixelOffset;
497: for (int v = 0; v < wp; v++) {
498: tmpValues[v] = srcData[imageOffset];
499: imageOffset += srcPixelStride;
500: }
501: tmpBuffer[revolver + i] = medianFilterDouble(tmpValues);
502: srcPixelOffset += srcPixelStride;
503: }
504: revolver += dwidth;
505: srcScanlineOffset += srcScanlineStride;
506: }
507:
508: // srcScanlineStride already bumped by
509: // filterSize-1*scanlineStride
510:
511: for (int j = 0; j < dheight; j++) {
512: int srcPixelOffset = srcScanlineOffset;
513: int dstPixelOffset = dstScanlineOffset;
514:
515: for (int i = 0; i < dwidth; i++) {
516: int imageOffset = srcPixelOffset;
517: for (int v = 0; v < wp; v++) {
518: tmpValues[v] = srcData[imageOffset];
519: imageOffset += srcPixelStride;
520: }
521: tmpBuffer[revolver + i] = medianFilterDouble(tmpValues);
522:
523: int a = 0;
524: for (int b = i; b < tmpBufferSize; b += dwidth) {
525: medianValues[a++] = tmpBuffer[b];
526: }
527: double val = medianFilterDouble(medianValues);
528:
529: dstData[dstPixelOffset] = val;
530: srcPixelOffset += srcPixelStride;
531: dstPixelOffset += dstPixelStride;
532: }
533: revolver += dwidth;
534: if (revolver == tmpBufferSize) {
535: revolver = 0;
536: }
537: srcScanlineOffset += srcScanlineStride;
538: dstScanlineOffset += dstScanlineStride;
539: }
540: }
541: }
542:
543: // public static OpImage createTestImage(OpImageTester oit) {
544: // return
545: // new MedianFilterSeparableOpImage(oit.getSource(), null, null,
546: // new ImageLayout(oit.getSource()),
547: // 3);
548: // }
549:
550: // public static void main(String args[]) {
551: // String classname =
552: // "com.sun.media.jai.opimage.MedianFilterSeparableOpImage";
553: // OpImageTester.performDiagnostics(classname,args);
554: // }
555: }
|