001: /*
002: * $RCSfile: MlibSeparableConvolveOpImage.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:05 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.mlib;
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.KernelJAI;
027: import java.util.Map;
028: import com.sun.medialib.mlib.*;
029:
030: // import com.sun.media.jai.test.OpImageTester;
031:
032: /**
033: * An OpImage class to perform convolution on a source image.
034: *
035: * <p> This class implements a convolution operation. Convolution is a
036: * spatial operation that computes each output sample by multiplying
037: * elements of a kernel with the samples surrounding a particular
038: * source sample.
039: *
040: * <p> For each destination sample, the kernel is rotated 180 degrees
041: * and its "key element" is placed over the source pixel corresponding
042: * with the destination pixel. The kernel elements are multiplied
043: * with the source pixels under them, and the resulting products are
044: * summed together to produce the destination sample value.
045: *
046: * <p> Example code for the convolution operation on a single sample
047: * dst[x][y] is as follows, assuming the kernel is of size M rows x N
048: * columns and has already been rotated through 180 degrees. The
049: * kernel's key element is located at position (xKey, yKey):
050: *
051: * <pre>
052: * dst[x][y] = 0;
053: * for (int i = -xKey; i < M - xKey; i++) {
054: * for (int j = -yKey; j < N - yKey; j++) {
055: * dst[x][y] += src[x + i][y + j] * kernel[xKey + i][yKey + j];
056: * }
057: * }
058: * </pre>
059: *
060: * <p> Convolution, or any neighborhood operation, leaves a band of
061: * pixels around the edges undefined, i.e., for a 3x3 kernel, only
062: * four kernel elements and four source pixels contribute to the
063: * destination pixel located at (0,0). Such pixels are not includined
064: * in the destination image, unless a non-null BorderExtender is provided.
065: *
066: * <p> The Kernel cannot be bigger in any dimension than the image data.
067: *
068: *
069: * @see KernelJAI
070: */
071: final class MlibSeparableConvolveOpImage extends AreaOpImage {
072:
073: /**
074: * The kernel with which to do the convolve operation.
075: */
076: protected KernelJAI kernel;
077:
078: /** Kernel variables. */
079: private int kw, kh;
080: float hValues[];
081: float vValues[];
082: double hDoubleData[], vDoubleData[];
083: int hIntData[], vIntData[];
084: int shift = -1;
085:
086: /**
087: * Creates a MlibSeparableConvolveOpImage given the image source
088: * and pre-rotated convolution kernel. The image dimensions are
089: * derived from the source image. The tile grid layout,
090: * SampleModel, and ColorModel may optionally be specified by an
091: * ImageLayout object.
092: *
093: * @param source a RenderedImage.
094: * @param extender a BorderExtender, or null.
095:
096: * or null. If null, a default cache will be used.
097: * @param layout an ImageLayout optionally containing the tile grid layout,
098: * SampleModel, and ColorModel, or null.
099: * @param kernel the pre-rotated convolution KernelJAI.
100: */
101: public MlibSeparableConvolveOpImage(RenderedImage source,
102: BorderExtender extender, Map config, ImageLayout layout,
103: KernelJAI kernel) {
104: super (source, layout, config, true, extender, kernel
105: .getLeftPadding(), kernel.getRightPadding(), kernel
106: .getTopPadding(), kernel.getBottomPadding());
107:
108: this .kernel = kernel;
109: kw = kernel.getWidth();
110: kh = kernel.getHeight();
111:
112: // kx, ky dealt with in AreaOpImage
113:
114: hValues = kernel.getHorizontalKernelData();
115: vValues = kernel.getVerticalKernelData();
116:
117: // A little inefficient but figuring out what datatype
118: // mediaLibAccessor will want is tricky.
119:
120: hDoubleData = new double[hValues.length];
121: for (int i = 0; i < hValues.length; i++) {
122: hDoubleData[i] = (double) hValues[i];
123: }
124:
125: vDoubleData = new double[vValues.length];
126: for (int i = 0; i < vValues.length; i++) {
127: vDoubleData[i] = (double) vValues[i];
128: }
129:
130: hIntData = new int[hValues.length];
131: vIntData = new int[vValues.length];
132:
133: }
134:
135: private synchronized void setShift(int formatTag) {
136: if (shift == -1) {
137: int mediaLibDataType = MediaLibAccessor
138: .getMediaLibDataType(formatTag);
139: shift = Image.SConvKernelConvert(hIntData, vIntData,
140: hDoubleData, vDoubleData, kw, kh, mediaLibDataType);
141: }
142: }
143:
144: /**
145: * Performs convolution on a specified rectangle. The sources are
146: * cobbled.
147: *
148: * @param sources an array of source Rasters, guaranteed to provide all
149: * necessary source data for computing the output.
150: * @param dest a WritableRaster tile containing the area to be computed.
151: * @param destRect the rectangle within dest to be processed.
152: */
153: protected void computeRect(Raster[] sources, WritableRaster dest,
154: Rectangle destRect) {
155:
156: Raster source = sources[0];
157: Rectangle srcRect = mapDestRect(destRect, 0);
158:
159: int formatTag = MediaLibAccessor.findCompatibleTag(sources,
160: dest);
161:
162: MediaLibAccessor srcAccessor = new MediaLibAccessor(source,
163: srcRect, formatTag);
164: MediaLibAccessor dstAccessor = new MediaLibAccessor(dest,
165: destRect, formatTag);
166: int numBands = getSampleModel().getNumBands();
167:
168: mediaLibImage[] srcML = srcAccessor.getMediaLibImages();
169: mediaLibImage[] dstML = dstAccessor.getMediaLibImages();
170: for (int i = 0; i < dstML.length; i++) {
171: switch (dstAccessor.getDataType()) {
172: case DataBuffer.TYPE_BYTE:
173: case DataBuffer.TYPE_USHORT:
174: case DataBuffer.TYPE_SHORT:
175: case DataBuffer.TYPE_INT:
176: if (shift == -1) {
177: setShift(formatTag);
178: }
179: switch (kw) {
180: case 3:
181: Image.SConv3x3(dstML[i], srcML[i], hIntData,
182: vIntData, shift, ((1 << numBands) - 1),
183: Constants.MLIB_EDGE_DST_NO_WRITE);
184: break;
185: case 5:
186: Image.SConv5x5(dstML[i], srcML[i], hIntData,
187: vIntData, shift, ((1 << numBands) - 1),
188: Constants.MLIB_EDGE_DST_NO_WRITE);
189: break;
190: case 7:
191: Image.SConv7x7(dstML[i], srcML[i], hIntData,
192: vIntData, shift, ((1 << numBands) - 1),
193: Constants.MLIB_EDGE_DST_NO_WRITE);
194: break;
195: }
196: break;
197: case DataBuffer.TYPE_FLOAT:
198: case DataBuffer.TYPE_DOUBLE:
199: switch (kw) {
200: case 3:
201: Image.SConv3x3_Fp(dstML[i], srcML[i], hDoubleData,
202: vDoubleData, ((1 << numBands) - 1),
203: Constants.MLIB_EDGE_DST_NO_WRITE);
204: break;
205: case 5:
206: Image.SConv5x5_Fp(dstML[i], srcML[i], hDoubleData,
207: vDoubleData, ((1 << numBands) - 1),
208: Constants.MLIB_EDGE_DST_NO_WRITE);
209: break;
210: case 7:
211: Image.SConv7x7_Fp(dstML[i], srcML[i], hDoubleData,
212: vDoubleData, ((1 << numBands) - 1),
213: Constants.MLIB_EDGE_DST_NO_WRITE);
214: break;
215: }
216: break;
217: default:
218: String className = this .getClass().getName();
219: throw new RuntimeException(JaiI18N
220: .getString("Generic2"));
221: }
222: }
223:
224: if (dstAccessor.isDataCopy()) {
225: dstAccessor.copyDataToRaster();
226: }
227: }
228:
229: // public static OpImage createTestImage(OpImageTester oit) {
230: // float hdata[] = {0.33f,0.33f,0.33f};
231: // float vdata[] = {0.33f,0.33f,0.33f};
232:
233: // KernelJAI kJAI = new KernelJAI(3,3,1,1,hdata,vdata);
234: // return new MlibSeparableConvolveOpImage(oit.getSource(), null, null,
235: // new ImageLayout(oit.getSource()),
236: // kJAI);
237: // }
238:
239: // public static void main (String args[]) {
240: // String classname = "com.sun.media.jai.mlib.MlibSeparableConvolveOpImage";
241: // OpImageTester.performDiagnostics(classname,args);
242: // }
243: }
|