Source Code Cross Referenced for KernelJAI.java in  » 6.0-JDK-Modules » Java-Advanced-Imaging » javax » media » jai » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » Java Advanced Imaging » javax.media.jai 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $RCSfile: KernelJAI.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:57:11 $
010:         * $State: Exp $
011:         */
012:        package javax.media.jai;
013:
014:        import java.awt.image.Kernel;
015:        import java.io.Serializable;
016:        import javax.media.jai.JaiI18N;
017:
018:        /**
019:         * A kernel representing a matrix with a key position,
020:         *  used by operators such as <code> Convolve </code>.
021:         *
022:         * <p> A <code>KernelJAI</code> is characterized by its width, height, and
023:         * origin, or key element. The key element is the element which is placed
024:         * over the current source pixel to perform convolution or error diffusion.
025:         * 
026:         * <p>A kernel K is separable it the outer product of two one-dimensional
027:         * vectors. It can speed up computation. One can construct a kernel
028:         * from two one-dimensional vectors. 
029:         *
030:         * <>The symmetry can be useful (such as computation speedup). Currently
031:         * the protected instance variables isHorizonallySymmetric
032:         * and  isVerticallySymmetric are set to false.
033:         *
034:         *
035:         * @see javax.media.jai.operator.ConvolveDescriptor
036:         * @see javax.media.jai.operator.OrderedDitherDescriptor
037:         * @see javax.media.jai.operator.ErrorDiffusionDescriptor
038:         */
039:        public class KernelJAI extends Object implements  Serializable {
040:
041:            /**
042:             * Floyd and Steinberg error filter (1975).
043:             * <pre>
044:             * (1/16 x)  [   * 7 ]
045:             *           [ 3 5 1 ]
046:             * </pre>
047:             */
048:            public static final KernelJAI ERROR_FILTER_FLOYD_STEINBERG = new KernelJAI(
049:                    3, 2, 1, 0, new float[] { 0.0F / 16.0F, 0.0F / 16.0F,
050:                            7.0F / 16.0F, 3.0F / 16.0F, 5.0F / 16.0F,
051:                            1.0F / 16.0F });
052:
053:            /**
054:             * Jarvis, Judice, and Ninke error filter (1976).
055:             * <pre>
056:             *           [     * 7 5 ]
057:             * (1/48 x)  [ 3 5 7 5 3 ]
058:             *           [ 1 3 5 3 1 ]
059:             * </pre>
060:             */
061:            public static final KernelJAI ERROR_FILTER_JARVIS = new KernelJAI(
062:                    5, 3, 2, 0, new float[] { 0.0F, 0.0F, 0.0F, 7.0F / 48.0F,
063:                            5.0F / 48.0F, 3.0F / 48.0F, 5.0F / 48.0F,
064:                            7.0F / 48.0F, 5.0F / 48.0F, 3.0F / 48.0F,
065:                            1.0F / 48.0F, 3.0F / 48.0F, 5.0F / 48.0F,
066:                            3.0F / 48.0F, 1.0F / 48.0F });
067:
068:            /**
069:             * Stucki error filter (1981).
070:             * <pre>
071:             *           [     * 7 5 ]
072:             * (1/42 x)  [ 2 4 8 4 2 ]
073:             *           [ 1 2 4 2 1 ]
074:             * </pre>
075:             */
076:            public static final KernelJAI ERROR_FILTER_STUCKI = new KernelJAI(
077:                    5, 3, 2, 0, new float[] { 0.0F, 0.0F, 0.0F, 7.0F / 42.0F,
078:                            5.0F / 42.0F, 2.0F / 42.0F, 4.0F / 42.0F,
079:                            8.0F / 42.0F, 4.0F / 42.0F, 2.0F / 42.0F,
080:                            1.0F / 42.0F, 2.0F / 42.0F, 4.0F / 42.0F,
081:                            2.0F / 42.0F, 1.0F / 42.0F });
082:
083:            /**
084:             * 4x4x1 mask useful for dithering 8-bit grayscale images to 1-bit images.
085:             */
086:            public static final KernelJAI[] DITHER_MASK_441 = new KernelJAI[] { new KernelJAI(
087:                    4, 4, 1, 1, new float[] { 0.9375F, 0.4375F, 0.8125F,
088:                            0.3125F, 0.1875F, 0.6875F, 0.0625F, 0.5625F,
089:                            0.7500F, 0.2500F, 0.8750F, 0.3750F, 0.0000F,
090:                            0.5000F, 0.1250F, 0.6250F }) };
091:
092:            /**
093:             * 4x4x3 mask useful for dithering 24-bit color images to 8-bit
094:             * pseudocolor images.
095:             */
096:            public static final KernelJAI[] DITHER_MASK_443 = new KernelJAI[] {
097:                    new KernelJAI(4, 4, 1, 1, new float[] { 0.0000F, 0.5000F,
098:                            0.1250F, 0.6250F, 0.7500F, 0.2500F, 0.8750F,
099:                            0.3750F, 0.1875F, 0.6875F, 0.0625F, 0.5625F,
100:                            0.9375F, 0.4375F, 0.8125F, 0.3125F }),
101:                    new KernelJAI(4, 4, 1, 1, new float[] { 0.6250F, 0.1250F,
102:                            0.5000F, 0.0000F, 0.3750F, 0.8750F, 0.2500F,
103:                            0.7500F, 0.5625F, 0.0625F, 0.6875F, 0.1875F,
104:                            0.3125F, 0.8125F, 0.4375F, 0.9375F }),
105:                    new KernelJAI(4, 4, 1, 1, new float[] { 0.9375F, 0.4375F,
106:                            0.8125F, 0.3125F, 0.1875F, 0.6875F, 0.0625F,
107:                            0.5625F, 0.7500F, 0.2500F, 0.8750F, 0.3750F,
108:                            0.0000F, 0.5000F, 0.1250F, 0.6250F }) };
109:
110:            /**
111:             * Gradient Mask for SOBEL_VERTICAL.
112:             */
113:            public static final KernelJAI GRADIENT_MASK_SOBEL_VERTICAL = new KernelJAI(
114:                    3, 3, 1, 1, new float[] { -1, -2, -1, 0, 0, 0, 1, 2, 1 });
115:
116:            /**
117:             * Gradient Mask for SOBEL_HORIZONTAL.
118:             */
119:            public static final KernelJAI GRADIENT_MASK_SOBEL_HORIZONTAL = new KernelJAI(
120:                    3, 3, 1, 1, new float[] { -1, 0, 1, -2, 0, 2, -1, 0, 1 });
121:
122:            /** The width of the kernel. */
123:            protected int width;
124:
125:            /** The height of the kernel. */
126:            protected int height;
127:
128:            /** The X coordinate of the key element. */
129:            protected int xOrigin;
130:
131:            /** The Y coordinate of the key element. */
132:            protected int yOrigin;
133:
134:            /** The kernel data in row-major format. */
135:            protected float[] data = null;
136:
137:            /** The horizontal data for a separable kernel */
138:            protected float[] dataH = null;
139:
140:            /** The vertical data for a separable kernel */
141:            protected float[] dataV = null;
142:
143:            /** True if the kernel is separable. */
144:            protected boolean isSeparable = false;
145:
146:            /** True if the kernel has horizontal (Y axis) symmetry. */
147:            protected boolean isHorizontallySymmetric = false;
148:
149:            /** True if the kernel has vertical (X axis) symmetry. */
150:            protected boolean isVerticallySymmetric = false;
151:
152:            /** Variable to cache a copy of the rotated kernel */
153:            protected KernelJAI rotatedKernel = null;
154:
155:            private synchronized void checkSeparable() {
156:                // Define a local constant for single precision floating
157:                // point tolerance.
158:                float floatZeroTol = (float) 1.0E-5;
159:
160:                if (isSeparable) {
161:                    return;
162:                } // already separable
163:                if (width <= 1 || height <= 1) {
164:                    return;
165:                }
166:                // 1D kernel is non-separable unless constructed to explicitly so
167:                // (either dataH or dataV will be a 1x1.
168:
169:                //  else:
170:                //  Check to see if given kernel can be factored into separable kernels
171:                //  previous approach: if data[0]==0, then not separable;
172:                //  new approach: find the largest element (and its row number) first then
173:                //      check to see if rows are multiples of that row
174:                //  Normalize is also important: separable kernel implimentation has
175:                //  hash table look ups... and expecting things in range
176:
177:                float maxData = 0.0F;
178:                int imax = 0, jmax = 0;
179:
180:                for (int k = 0; k < this .data.length; k++) {
181:                    float tmp = Math.abs(this .data[k]);
182:                    if (tmp > maxData) {
183:                        imax = k;
184:                        maxData = tmp;
185:                    }
186:                }
187:
188:                // check for 0 kernel
189:                // a case that should not happen in meaningful convolution
190:                if (maxData < floatZeroTol / (float) data.length) {
191:                    isSeparable = false;
192:                    return;
193:                }
194:
195:                float tmpRow[] = new float[width];
196:                float fac = 1.0F / data[imax];
197:
198:                // position of the max data element in the kernel matrix
199:                jmax = imax % width;
200:                imax = imax / width;
201:
202:                for (int j = 0; j < width; j++) {
203:                    tmpRow[j] = data[imax * width + j] * fac;
204:                }
205:
206:                //
207:                //  Rank 1 checking: every row should be a multiple of tmpRow
208:                //  if separable (a rank one kernel matrix)
209:                for (int i = 0, i0 = 0; i < height; i++, i0 += width) {
210:                    for (int j = 0; j < width; j++) {
211:                        float tmp = Math.abs(data[i0 + jmax] * tmpRow[j]
212:                                - data[i0 + j]);
213:                        if (tmp > floatZeroTol) {
214:                            isSeparable = false;
215:                            return;
216:                        }
217:                    }
218:                }
219:
220:                dataH = tmpRow;
221:                dataV = new float[height];
222:                for (int i = 0; i < height; i++) {
223:                    dataV[i] = data[jmax + i * width];
224:                }
225:                isSeparable = true;
226:
227:                // normalizing - so that dataH and dataV add up to 1
228:                // in some cases, it may not be possible for both if
229:                // the original kernel does not add up to 1.
230:                // Row adds up to 1 as 1st choice.
231:                // If both dataH and dataV add up small,
232:                // no normalization is done.
233:                // NOTE: non-positive kernels, normalization may be skipped
234:                float sumH = 0.0F, sumV = 0.0F;
235:                for (int j = 0; j < width; j++) {
236:                    sumH += dataH[j];
237:                }
238:                for (int j = 0; j < height; j++) {
239:                    sumV += dataV[j];
240:                }
241:
242:                if (Math.abs(sumH) >= Math.abs(sumV)
243:                        && Math.abs(sumH) > floatZeroTol) {
244:                    fac = 1.0F / sumH;
245:                    for (int j = 0; j < width; j++) {
246:                        dataH[j] *= fac;
247:                    }
248:                    for (int j = 0; j < height; j++) {
249:                        dataV[j] *= sumH;
250:                    }
251:                } else if (Math.abs(sumH) < Math.abs(sumV)
252:                        && Math.abs(sumV) > floatZeroTol) {
253:                    fac = 1.0F / sumV;
254:                    for (int j = 0; j < width; j++) {
255:                        dataH[j] *= sumV;
256:                    }
257:                    for (int j = 0; j < height; j++) {
258:                        dataV[j] *= fac;
259:                    }
260:                }
261:            }
262:
263:            private void classifyKernel() {
264:                if (isSeparable == false) {
265:                    checkSeparable();
266:                }
267:                isHorizontallySymmetric = false;
268:                isVerticallySymmetric = false;
269:            }
270:
271:            /**
272:             * Constructs a KernelJAI with the given parameters.  The data
273:             * array is copied.
274:             *
275:             * @param width    the width of the kernel.
276:             * @param height   the height of the kernel.
277:             * @param xOrigin  the X coordinate of the key kernel element.
278:             * @param yOrigin  the Y coordinate of the key kernel element.
279:             * @param data     the float data in row-major format.
280:             *
281:             * @throws IllegalArgumentException if data is null.
282:             * @throws IllegalArgumentException if width is not a positive number.
283:             * @throws IllegalArgumentException if height is not a positive number.
284:             * @throws IllegalArgumentException if kernel data array does not have
285:             * width * height number of elements.
286:             * @classifies as non-separable if width or height is 1.
287:             */
288:            public KernelJAI(int width, int height, int xOrigin, int yOrigin,
289:                    float[] data) {
290:
291:                if (data == null) {
292:                    throw new IllegalArgumentException(JaiI18N
293:                            .getString("Generic0"));
294:                }
295:
296:                this .width = width;
297:                this .height = height;
298:                this .xOrigin = xOrigin;
299:                this .yOrigin = yOrigin;
300:                this .data = (float[]) data.clone();
301:                if (width <= 0) {
302:                    throw new IllegalArgumentException(JaiI18N
303:                            .getString("KernelJAI0"));
304:                }
305:                if (height <= 0) {
306:                    throw new IllegalArgumentException(JaiI18N
307:                            .getString("KernelJAI1"));
308:                }
309:                if (width * height != data.length) {
310:                    throw new IllegalArgumentException(JaiI18N
311:                            .getString("KernelJAI2"));
312:                }
313:                classifyKernel();
314:            }
315:
316:            /**
317:             * Constructs a separable KernelJAI from two float arrays.
318:             * The data arrays are copied.
319:             *
320:             * A Separable kernel K = dataH * dataV^T, the outer product of two
321:             * one dimensional vectors dataH and dataV. It can often speed up
322:             * compution.
323:             *
324:             * @param width    the width of the kernel.
325:             * @param height   the height of the kernel.
326:             * @param xOrigin  the X coordinate of the key kernel element.
327:             * @param yOrigin  the Y coordinate of the key kernel element.
328:             * @param dataH    the float data for the horizontal direction.
329:             * @param dataV    the float data for the vertical direction.
330:             *
331:             * @throws IllegalArgumentException if dataH is null.
332:             * @throws IllegalArgumentException if dataV is null.
333:             * @throws IllegalArgumentException if width is not a positive number.
334:             * @throws IllegalArgumentException if height is not a positive number.
335:             * @throws IllegalArgumentException if dataH does not have width elements.
336:             * @throws IllegalArgumentException if dataV does not have height elements.
337:             * @must   use the other constructor when dataH or dataV is null
338:             */
339:            public KernelJAI(int width, int height, int xOrigin, int yOrigin,
340:                    float[] dataH, float[] dataV) {
341:
342:                if (dataH == null || dataV == null) {
343:                    throw new IllegalArgumentException(JaiI18N
344:                            .getString("Generic0"));
345:                }
346:
347:                if (width <= 0) {
348:                    throw new IllegalArgumentException(JaiI18N
349:                            .getString("KernelJAI0"));
350:                }
351:
352:                if (height <= 0) {
353:                    throw new IllegalArgumentException(JaiI18N
354:                            .getString("KernelJAI1"));
355:                }
356:
357:                if (width != dataH.length) {
358:                    throw new IllegalArgumentException(JaiI18N
359:                            .getString("KernelJAI3"));
360:                }
361:
362:                if (height != dataV.length) {
363:                    throw new IllegalArgumentException(JaiI18N
364:                            .getString("KernelJAI4"));
365:                }
366:
367:                this .width = width;
368:                this .height = height;
369:                this .xOrigin = xOrigin;
370:                this .yOrigin = yOrigin;
371:                this .dataH = (float[]) dataH.clone();
372:                this .dataV = (float[]) dataV.clone();
373:                this .data = new float[dataH.length * dataV.length];
374:
375:                int rowOffset = 0;
376:                for (int i = 0; i < dataV.length; i++) {
377:                    float vValue = dataV[i];
378:                    for (int j = 0; j < dataH.length; j++) {
379:                        data[rowOffset + j] = vValue * dataH[j];
380:                    }
381:                    rowOffset += dataH.length;
382:                }
383:                isSeparable = true;
384:                classifyKernel();
385:            }
386:
387:            /**
388:             * Constructs a kernel with the given parameters.  The data
389:             * array is copied.  The key element is set to
390:             * (trunc(width/2), trunc(height/2)).
391:             *
392:             * @param width    the width of the kernel.
393:             * @param height   the height of the kernel.
394:             * @param data     the float data in row-major format.
395:             *
396:             * @throws IllegalArgumentException if data is null.
397:             * @throws IllegalArgumentException if width is not a positive number.
398:             * @throws IllegalArgumentException if height is not a positive number.
399:             * @throws IllegalArgumentException if data does not have
400:             * width * height number of elements.
401:             */
402:            public KernelJAI(int width, int height, float[] data) {
403:                this (width, height, width / 2, height / 2, data);
404:            }
405:
406:            /**
407:             * Constructs a KernelJAI from a java.awt.image.Kernel
408:             * object.
409:             *
410:             * @throws NullPointerException if k is null.
411:             */
412:            public KernelJAI(Kernel k) {
413:                // XXX - NullPointerException (inconsistent style)
414:                this (k.getWidth(), k.getHeight(), k.getXOrigin(), k
415:                        .getYOrigin(), k.getKernelData(null));
416:            }
417:
418:            /** Returns the width of the kernel. */
419:            public int getWidth() {
420:                return width;
421:            }
422:
423:            /** Returns the height of the kernel. */
424:            public int getHeight() {
425:                return height;
426:            }
427:
428:            /** Returns the X coordinate of the key kernel element. */
429:            public int getXOrigin() {
430:                return xOrigin;
431:            }
432:
433:            /** Returns the Y coordinate of the key kernel element. */
434:            public int getYOrigin() {
435:                return yOrigin;
436:            }
437:
438:            /** Returns a copy of the kernel data in row-major format. */
439:            public float[] getKernelData() {
440:                return (float[]) data.clone();
441:            }
442:
443:            /**
444:             * Returns the horizontal portion of the kernel if the
445:             * kernel is separable, or <code>null</code> otherwise.  The kernel may
446:             * be tested for separability by calling <code>isSeparable()</code>.
447:             */
448:            public float[] getHorizontalKernelData() {
449:                if (dataH == null) {
450:                    return null;
451:                }
452:                return (float[]) dataH.clone();
453:            }
454:
455:            /**
456:             * Returns the vertical portion of the kernel if the
457:             * kernel is separable, or <code>null</code> otherwise.  The kernel may
458:             * be tested for separability by calling <code>isSeparable()</code>.
459:             */
460:            public float[] getVerticalKernelData() {
461:                if (dataV == null) {
462:                    return null;
463:                }
464:                return (float[]) dataV.clone();
465:            }
466:
467:            /** 
468:             * Returns a given element of the kernel. 
469:             *
470:             * @throws ArrayIndexOutOfBoundsException if either xIndex or yIndex is
471:             * an invalid index.
472:             */
473:            public float getElement(int xIndex, int yIndex) {
474:                if (!isSeparable) {
475:                    return data[yIndex * width + xIndex];
476:                } else {
477:                    return dataH[xIndex] * dataV[yIndex];
478:                }
479:            }
480:
481:            /**
482:             * Returns true if the kernel is separable. 
483:             */
484:            public boolean isSeparable() {
485:                return isSeparable;
486:            }
487:
488:            /** Returns true if the kernel has horizontal (Y axis) symmetry. */
489:            public boolean isHorizontallySymmetric() {
490:                return isHorizontallySymmetric;
491:            }
492:
493:            /** Returns true if the kernel has vertical (X axis) symmetry. */
494:            public boolean isVerticallySymmetric() {
495:                return isVerticallySymmetric;
496:            }
497:
498:            /**
499:             * Returns the number of pixels required to the left of the key element.
500:             */
501:            public int getLeftPadding() {
502:                return xOrigin;
503:            }
504:
505:            /**
506:             * Returns the number of pixels required to the right of the key element.
507:             */
508:            public int getRightPadding() {
509:                return width - xOrigin - 1;
510:            }
511:
512:            /**
513:             * Returns the number of pixels required above the key element.
514:             */
515:            public int getTopPadding() {
516:                return yOrigin;
517:            }
518:
519:            /**
520:             * Returns the number of pixels required below the key element.
521:             */
522:            public int getBottomPadding() {
523:                return height - yOrigin - 1;
524:            }
525:
526:            /**
527:             * Returns a 180 degree rotated version of the kernel.  This is
528:             * needed by most convolve operations to get the correct results.
529:             * 
530:             * @return the rotated kernel.
531:             */
532:            public KernelJAI getRotatedKernel() {
533:                if (rotatedKernel == null) {
534:                    if (this .isSeparable) {
535:                        float rotDataH[] = new float[this .width];
536:                        float rotDataV[] = new float[this .height];
537:                        for (int i = 0; i < this .width; i++) {
538:                            rotDataH[i] = this .dataH[width - 1 - i];
539:                        }
540:                        for (int i = 0; i < this .height; i++) {
541:                            rotDataV[i] = this .dataV[height - 1 - i];
542:                        }
543:                        rotatedKernel = new KernelJAI(width, height, width - 1
544:                                - xOrigin, height - 1 - yOrigin, rotDataH,
545:                                rotDataV);
546:                    } else {
547:                        int length = data.length;
548:                        float newData[] = new float[data.length];
549:                        for (int i = 0; i < length; i++) {
550:                            newData[i] = data[length - 1 - i];
551:                        }
552:                        rotatedKernel = new KernelJAI(width, height, width - 1
553:                                - xOrigin, height - 1 - yOrigin, newData);
554:                    }
555:                }
556:                return rotatedKernel;
557:            }
558:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.