Source Code Cross Referenced for ROI.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) 


0001:        /*
0002:         * $RCSfile: ROI.java,v $
0003:         *
0004:         * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * Use is subject to license terms.
0007:         *
0008:         * $Revision: 1.1 $
0009:         * $Date: 2005/02/11 04:57:18 $
0010:         * $State: Exp $
0011:         */
0012:        package javax.media.jai;
0013:
0014:        import com.sun.media.jai.util.ImageUtil;
0015:        import java.awt.Point;
0016:        import java.awt.Rectangle;
0017:        import java.awt.RenderingHints;
0018:        import java.awt.Shape;
0019:        import java.awt.geom.AffineTransform;
0020:        import java.awt.geom.Area;
0021:        import java.awt.geom.Point2D;
0022:        import java.awt.geom.Rectangle2D;
0023:        import java.awt.image.BufferedImage;
0024:        import java.awt.image.DataBuffer;
0025:        import java.awt.image.MultiPixelPackedSampleModel;
0026:        import java.awt.image.Raster;
0027:        import java.awt.image.RenderedImage;
0028:        import java.awt.image.SampleModel;
0029:        import java.awt.image.WritableRaster;
0030:        import java.awt.image.renderable.ParameterBlock;
0031:        import java.awt.image.renderable.RenderedImageFactory;
0032:        import java.io.IOException;
0033:        import java.io.ObjectInputStream;
0034:        import java.io.ObjectOutputStream;
0035:        import java.io.Serializable;
0036:        import java.util.Arrays;
0037:        import java.util.Hashtable;
0038:        import java.util.LinkedList;
0039:        import java.util.ListIterator;
0040:        import java.util.Vector;
0041:        import javax.media.jai.iterator.RandomIter;
0042:        import javax.media.jai.iterator.RandomIterFactory;
0043:        import javax.media.jai.iterator.RectIter;
0044:        import javax.media.jai.iterator.RectIterFactory;
0045:        import javax.media.jai.remote.SerializableState;
0046:        import javax.media.jai.remote.SerializerFactory;
0047:
0048:        /**
0049:         * The parent class for representations of a region of interest of an
0050:         * image (currently only single band images with integral data types
0051:         * are supported).
0052:         * This class represents region information in image form, and
0053:         * can thus be used as a fallback where a <code>Shape</code>
0054:         * representation is unavailable.  Where possible, subclasses such as
0055:         * ROIShape are used since they provide a more compact means of
0056:         * storage for large regions.
0057:         *
0058:         * <p> The getAsShape() method may be called optimistically on any
0059:         * instance of ROI; however, it may return null to indicate that a
0060:         * <code>Shape</code> representation of the ROI is not available.  In
0061:         * this case, getAsImage() should be called as a fallback.
0062:         *
0063:         * <p> Inclusion and exclusion of pixels is defined by a threshold value.
0064:         * Pixel values greater than or equal to the threshold indicate inclusion.
0065:         *
0066:         */
0067:        public class ROI implements  Serializable {
0068:
0069:            /** A RandomIter used to grab pixels from the ROI. */
0070:            private transient RandomIter iter = null;
0071:
0072:            /** The <code>PlanarImage</code> representation of the ROI. */
0073:            transient PlanarImage theImage = null;
0074:
0075:            /** The inclusion/exclusion threshold of the ROI. */
0076:            int threshold = 127;
0077:
0078:            /**
0079:             * Merge a <code>LinkedList</code> of <code>Rectangle</code>s
0080:             * representing run lengths of pixels in the ROI into a minimal
0081:             * list wherein vertically abutting <code>Rectangle</code>s are
0082:             * merged. The operation is effected in place.
0083:             *
0084:             * @param rectList The list of run length <code>Rectangle</code>s.
0085:             * @throws IllegalArgumentException if rectList is null.
0086:             * @return The merged list.
0087:             */
0088:            protected static LinkedList mergeRunLengthList(LinkedList rectList) {
0089:
0090:                if (rectList == null) {
0091:                    throw new IllegalArgumentException(JaiI18N
0092:                            .getString("Generic0"));
0093:                }
0094:
0095:                // Merge the run length rectangles if more than one was detected.
0096:                if (rectList.size() > 1) {
0097:                    // Traverse the list sequentially merging all subsequent
0098:                    // vertically abutting Rectangles with the same abscissa
0099:                    // origin and width with the current starting Rectangle.
0100:                    for (int mergeIndex = 0; mergeIndex < rectList.size() - 1; mergeIndex++) {
0101:
0102:                        ListIterator rectIter = rectList
0103:                                .listIterator(mergeIndex);
0104:                        Rectangle mergeRect = (Rectangle) rectIter.next();
0105:
0106:                        while (rectIter.hasNext()) {
0107:                            Rectangle runRect = (Rectangle) rectIter.next();
0108:
0109:                            // Calculate ordinate value of abutting rectangle.
0110:                            int abuttingY = mergeRect.y + mergeRect.height;
0111:
0112:                            if (runRect.y == abuttingY
0113:                                    && runRect.x == mergeRect.x
0114:                                    && runRect.width == mergeRect.width) {
0115:                                mergeRect = new Rectangle(mergeRect.x,
0116:                                        mergeRect.y, mergeRect.width,
0117:                                        mergeRect.height + runRect.height);
0118:
0119:                                // Remove "runRect" from the list.
0120:                                rectIter.remove();
0121:
0122:                                // Replace "mergeRect" with updated version.
0123:                                rectList.set(mergeIndex, (Object) mergeRect);
0124:                            } else if (runRect.y > abuttingY) {
0125:                                // All Rectangles in the list with index greater than
0126:                                // mergeIndex are runlength Rectangles and are sorted
0127:                                // in non-decreasing ordinate order. Therefore there
0128:                                // are no more Rectangles which could possibly be
0129:                                // merged with mergeRect.
0130:                                break;
0131:                            }
0132:                        }
0133:                    }
0134:                }
0135:
0136:                return rectList;
0137:            }
0138:
0139:            /**
0140:             * The default constructor.
0141:             *
0142:             * Using this constructor means that the subclass must override
0143:             * all methods that reference theImage.
0144:             */
0145:            protected ROI() {
0146:            }
0147:
0148:            /**
0149:             * Constructs an ROI from a RenderedImage.  The inclusion
0150:             * threshold is taken to be halfway between the minimum and maximum
0151:             * sample values specified by the image's SampleModel.
0152:             *
0153:             * @param im A single-banded RenderedImage.
0154:             *
0155:             * @throws IllegalArgumentException if im is null.
0156:             * @throws IllegalArgumentException if im does not have exactly one band
0157:             */
0158:            public ROI(RenderedImage im) {
0159:                this (im, 127);
0160:            }
0161:
0162:            /**
0163:             * Constructs an ROI from a RenderedImage.  The inclusion
0164:             * threshold is specified explicitly.
0165:             *
0166:             * @param im A single-banded RenderedImage.
0167:             * @param threshold The desired inclusion threshold.
0168:             *
0169:             * @throws IllegalArgumentException if im is null.
0170:             * @throws IllegalArgumentException if im does not have exactly one band
0171:             */
0172:            public ROI(RenderedImage im, int threshold) {
0173:
0174:                if (im == null) {
0175:                    throw new IllegalArgumentException(JaiI18N
0176:                            .getString("Generic0"));
0177:                }
0178:
0179:                SampleModel sm = im.getSampleModel();
0180:
0181:                if (sm.getNumBands() != 1) {
0182:                    throw new IllegalArgumentException(JaiI18N
0183:                            .getString("ROI0"));
0184:                }
0185:
0186:                this .threshold = threshold;
0187:
0188:                // If the image is already binary and the threshold is >1
0189:                // then there is no work to do.
0190:                if ((threshold >= 1) && ImageUtil.isBinary(sm)) {
0191:                    theImage = PlanarImage.wrapRenderedImage(im);
0192:
0193:                    // Otherwise binarize the image for efficiency.
0194:                } else {
0195:
0196:                    ParameterBlockJAI pbj = new ParameterBlockJAI("binarize");
0197:
0198:                    pbj.setSource("source0", im);
0199:                    pbj.setParameter("threshold", (double) threshold);
0200:
0201:                    theImage = JAI.create("binarize", pbj, null);
0202:                }
0203:            }
0204:
0205:            /** Get the iterator, construct it if need be. */
0206:            private RandomIter getIter() {
0207:                if (iter == null) {
0208:                    iter = RandomIterFactory.create(theImage, null);
0209:                }
0210:                return iter;
0211:            }
0212:
0213:            /** Returns the inclusion/exclusion threshold value. */
0214:            public int getThreshold() {
0215:                return threshold;
0216:            }
0217:
0218:            /** Sets the inclusion/exclusion threshold value. */
0219:            public void setThreshold(int threshold) {
0220:                this .threshold = threshold;
0221:                ((RenderedOp) theImage).setParameter((double) threshold, 0);
0222:                iter = null;
0223:                getIter();
0224:            }
0225:
0226:            /** Returns the bounds of the ROI as a <code>Rectangle</code>. */
0227:            public Rectangle getBounds() {
0228:                return new Rectangle(theImage.getMinX(), theImage.getMinY(),
0229:                        theImage.getWidth(), theImage.getHeight());
0230:            }
0231:
0232:            /** Returns the bounds of the ROI as a <code>Rectangle2D</code>. */
0233:            public Rectangle2D getBounds2D() {
0234:                return new Rectangle2D.Float((float) theImage.getMinX(),
0235:                        (float) theImage.getMinY(),
0236:                        (float) theImage.getWidth(), (float) theImage
0237:                                .getHeight());
0238:            }
0239:
0240:            /**
0241:             * Returns <code>true</code> if the ROI contains a given Point.
0242:             *
0243:             * @param p A Point identifying the pixel to be queried.
0244:             * @throws IllegalArgumentException if p is null.
0245:             * @return <code>true</code> if the pixel lies within the ROI.
0246:             */
0247:            public boolean contains(Point p) {
0248:                if (p == null) {
0249:                    throw new IllegalArgumentException(JaiI18N
0250:                            .getString("Generic0"));
0251:                }
0252:
0253:                return contains(p.x, p.y);
0254:            }
0255:
0256:            /**
0257:             * Returns <code>true</code> if the ROI contains a given Point2D.
0258:             *
0259:             * @param p A Point2D identifying the pixel to be queried.
0260:             * @throws IllegalArgumentException if p is null.
0261:             * @return <code>true</code> if the pixel lies within the ROI.
0262:             */
0263:            public boolean contains(Point2D p) {
0264:                if (p == null) {
0265:                    throw new IllegalArgumentException(JaiI18N
0266:                            .getString("Generic0"));
0267:                }
0268:
0269:                return contains((int) p.getX(), (int) p.getY());
0270:            }
0271:
0272:            /**
0273:             * Returns <code>true</code> if the ROI contains the point (x, y).
0274:             *
0275:             * @param x An int specifying the X coordinate of the pixel to be queried.
0276:             * @param y An int specifying the Y coordinate of the pixel to be queried.
0277:             * @return <code>true</code> if the pixel lies within the ROI.
0278:             */
0279:            public boolean contains(int x, int y) {
0280:                int minX = theImage.getMinX();
0281:                int minY = theImage.getMinY();
0282:
0283:                return (x >= minX && x < minX + theImage.getWidth())
0284:                        && (y >= minY && y < minY + theImage.getHeight())
0285:                        && (getIter().getSample(x, y, 0) >= 1);
0286:            }
0287:
0288:            /**
0289:             * Returns <code>true</code> if the ROI contain the point (x, y).
0290:             *
0291:             * @param x A double specifying the X coordinate of the pixel
0292:             *        to be queried.
0293:             * @param y A double specifying the Y coordinate of the pixel
0294:             *        to be queried.
0295:             * @return <code>true</code> if the pixel lies within the ROI.
0296:             */
0297:            public boolean contains(double x, double y) {
0298:                return contains((int) x, (int) y);
0299:            }
0300:
0301:            /**
0302:             * Returns <code>true</code> if a given <code>Rectangle</code> is
0303:             * entirely included within the ROI.
0304:             *
0305:             * @param rect A <code>Rectangle</code> specifying the region to be tested
0306:             *        for inclusion.
0307:             * @throws IllegalArgumentException if rect is null.
0308:             * @return <code>true</code> if the rectangle is entirely
0309:             *         contained within the ROI.
0310:             */
0311:            public boolean contains(Rectangle rect) {
0312:                if (rect == null) {
0313:                    throw new IllegalArgumentException(JaiI18N
0314:                            .getString("Generic0"));
0315:                }
0316:
0317:                if (!rect.equals(rect.intersection(getBounds()))) {
0318:                    return false;
0319:                }
0320:
0321:                byte[] packedData = ImageUtil.getPackedBinaryData(theImage
0322:                        .getData(), rect);
0323:
0324:                // ImageUtil.getPackedBinaryData does not zero out the extra
0325:                // bits used to pad to the nearest byte - therefore ignore
0326:                // these bits.
0327:                int leftover = rect.width % 8;
0328:
0329:                if (leftover == 0) {
0330:
0331:                    for (int i = 0; i < packedData.length; i++)
0332:                        if ((packedData[i] & 0xff) != 0xff)
0333:                            return false;
0334:
0335:                } else {
0336:
0337:                    int mask = ((1 << leftover) - 1) << (8 - leftover);
0338:
0339:                    for (int y = 0, k = 0; y < rect.height; y++) {
0340:                        for (int x = 0; x < rect.width - leftover; x += 8, k++) {
0341:                            if ((packedData[k] & 0xff) != 0xff)
0342:                                return false;
0343:                        }
0344:
0345:                        if ((packedData[k] & mask) != mask)
0346:                            return false;
0347:
0348:                        k++;
0349:                    }
0350:                }
0351:
0352:                return true;
0353:            }
0354:
0355:            /**
0356:             * Returns <code>true</code> if a given <code>Rectangle2D</code> is
0357:             * entirely included within the ROI.
0358:             *
0359:             * @param rect A <code>Rectangle2D</code> specifying the region to be
0360:             *        tested for inclusion.
0361:             * @throws IllegalArgumentException if rect is null.
0362:             * @return <code>true</code> if the rectangle is entirely contained
0363:             *         within the ROI.
0364:             */
0365:            public boolean contains(Rectangle2D rect) {
0366:                if (rect == null) {
0367:                    throw new IllegalArgumentException(JaiI18N
0368:                            .getString("Generic0"));
0369:                }
0370:                Rectangle r = new Rectangle((int) rect.getX(), (int) rect
0371:                        .getY(), (int) rect.getWidth(), (int) rect.getHeight());
0372:                return contains(r);
0373:            }
0374:
0375:            /**
0376:             * Returns <code>true</code> if a given rectangle (x, y, w, h) is entirely
0377:             * included within the ROI.
0378:             *
0379:             * @param x The int X coordinate of the upper left corner of the region.
0380:             * @param y The int Y coordinate of the upper left corner of the region.
0381:             * @param w The int width of the region.
0382:             * @param h The int height of the region.
0383:             * @return <code>true</code> if the rectangle is entirely contained
0384:             *         within the ROI.
0385:             */
0386:            public boolean contains(int x, int y, int w, int h) {
0387:                Rectangle r = new Rectangle(x, y, w, h);
0388:                return contains(r);
0389:            }
0390:
0391:            /**
0392:             * Returns <code>true</code> if a given rectangle (x, y, w, h) is entirely
0393:             * included within the ROI.
0394:             *
0395:             * @param x The double X coordinate of the upper left corner of the region.
0396:             * @param y The double Y coordinate of the upper left corner of the region.
0397:             * @param w The double width of the region.
0398:             * @param h The double height of the region.
0399:             *
0400:             * @return <code>true</code> if the rectangle is entirely
0401:             * contained within the ROI.
0402:             */
0403:            public boolean contains(double x, double y, double w, double h) {
0404:                Rectangle rect = new Rectangle((int) x, (int) y, (int) w,
0405:                        (int) h);
0406:                return contains(rect);
0407:            }
0408:
0409:            /**
0410:             * Returns <code>true</code> if a given <code>Rectangle</code>
0411:             * intersects the ROI.
0412:             *
0413:             * @param rect A <code>Rectangle</code> specifying the region to be tested
0414:             *        for inclusion.
0415:             * @throws IllegalArgumentException if rect is null.
0416:             * @return <code>true</code> if the rectangle intersects the ROI.
0417:             */
0418:            public boolean intersects(Rectangle rect) {
0419:                if (rect == null) {
0420:                    throw new IllegalArgumentException(JaiI18N
0421:                            .getString("Generic0"));
0422:                }
0423:
0424:                Rectangle r = rect.intersection(getBounds());
0425:
0426:                if (r.isEmpty()) {
0427:                    return false;
0428:                }
0429:
0430:                byte[] packedData = ImageUtil.getPackedBinaryData(theImage
0431:                        .getData(), r);
0432:
0433:                // ImageUtil.getPackedBinaryData does not zero out the extra
0434:                // bits used to pad to the nearest byte - therefore ignore
0435:                // these bits.
0436:                int leftover = r.width % 8;
0437:
0438:                if (leftover == 0) {
0439:
0440:                    for (int i = 0; i < packedData.length; i++)
0441:                        if ((packedData[i] & 0xff) != 0)
0442:                            return true;
0443:
0444:                } else {
0445:
0446:                    int mask = ((1 << leftover) - 1) << (8 - leftover);
0447:
0448:                    for (int y = 0, k = 0; y < r.height; y++) {
0449:                        for (int x = 0; x < r.width - leftover; x += 8, k++) {
0450:                            if ((packedData[k] & 0xff) != 0)
0451:                                return true;
0452:                        }
0453:                        if ((packedData[k] & mask) != 0)
0454:                            return true;
0455:                        k++;
0456:                    }
0457:                }
0458:
0459:                return false;
0460:            }
0461:
0462:            /**
0463:             * Returns <code>true</code> if a given <code>Rectangle2D</code>
0464:             * intersects the ROI.
0465:             *
0466:             * @param r A <code>Rectangle2D</code> specifying the region to be tested
0467:             *        for inclusion.
0468:             * @throws IllegalArgumentException if r is null.
0469:             * @return <code>true</code> if the rectangle intersects the ROI.
0470:             */
0471:            public boolean intersects(Rectangle2D r) {
0472:                if (r == null) {
0473:                    throw new IllegalArgumentException(JaiI18N
0474:                            .getString("Generic0"));
0475:                }
0476:
0477:                Rectangle rect = new Rectangle((int) r.getX(), (int) r.getY(),
0478:                        (int) r.getWidth(), (int) r.getHeight());
0479:                return intersects(rect);
0480:            }
0481:
0482:            /**
0483:             * Returns <code>true</code> if a given rectangular region
0484:             * intersects the ROI.
0485:             *
0486:             * @param x The int X coordinate of the upper left corner of the region.
0487:             * @param y The int Y coordinate of the upper left corner of the region.
0488:             * @param w The int width of the region.
0489:             * @param h The int height of the region.
0490:             * @return <code>true</code> if the rectangle intersects the ROI.
0491:             */
0492:            public boolean intersects(int x, int y, int w, int h) {
0493:                Rectangle rect = new Rectangle(x, y, w, h);
0494:                return intersects(rect);
0495:            }
0496:
0497:            /**
0498:             * Returns <code>true</code> if a given rectangular region
0499:             * intersects the ROI.
0500:             *
0501:             * @param x The double X coordinate of the upper left corner of the region.
0502:             * @param y The double Y coordinate of the upper left corner of the region.
0503:             * @param w The double width of the region.
0504:             * @param h The double height of the region.
0505:             * @return <code>true</code> if the rectangle intersects the ROI.
0506:             */
0507:            public boolean intersects(double x, double y, double w, double h) {
0508:                Rectangle rect = new Rectangle((int) x, (int) y, (int) w,
0509:                        (int) h);
0510:                return intersects(rect);
0511:            }
0512:
0513:            /**
0514:             * Create a binary PlanarImage of the size/bounds specified by
0515:             * the rectangle.
0516:             */
0517:            private static PlanarImage createBinaryImage(Rectangle r) {
0518:
0519:                if ((r.x == 0) && (r.y == 0)) {
0520:
0521:                    BufferedImage bi = new BufferedImage(r.width, r.height,
0522:                            BufferedImage.TYPE_BYTE_BINARY);
0523:
0524:                    return PlanarImage.wrapRenderedImage(bi);
0525:
0526:                } else {
0527:
0528:                    SampleModel sm = new MultiPixelPackedSampleModel(
0529:                            DataBuffer.TYPE_BYTE, r.width, r.height, 1);
0530:
0531:                    // Create a TiledImage into which to write.
0532:                    return new TiledImage(r.x, r.y, r.width, r.height, r.x,
0533:                            r.y, sm, PlanarImage.createColorModel(sm));
0534:                }
0535:            }
0536:
0537:            /**
0538:             * Creates a merged ROI by performing the specified image operation
0539:             * on <code>this</code> image and the image of the specified ROI.
0540:             *
0541:             * @param ROI the ROI to merge with <code>this</code>
0542:             * @param op  the JAI operator to use for merge.
0543:             *
0544:             * @return the merged ROI
0545:             */
0546:            private ROI createOpROI(ROI roi, String op) {
0547:
0548:                if (roi == null) {
0549:                    throw new IllegalArgumentException(JaiI18N
0550:                            .getString("Generic0"));
0551:                }
0552:
0553:                PlanarImage imThis = this .getAsImage();
0554:                PlanarImage imROI = roi.getAsImage();
0555:                PlanarImage imDest;
0556:
0557:                Rectangle boundsThis = imThis.getBounds();
0558:                Rectangle boundsROI = imROI.getBounds();
0559:
0560:                // If the bounds of the two images do not match, then
0561:                // expand as necessary to the union of the two bounds
0562:                // using the "overlay" operator and then perform the JAI
0563:                // operation.
0564:                if (op.equals("and") || boundsThis.equals(boundsROI)) {
0565:                    imDest = JAI.create(op, imThis, imROI);
0566:
0567:                } else if (op.equals("subtract")
0568:                        || boundsThis.contains(boundsROI)) {
0569:
0570:                    PlanarImage imBounds = createBinaryImage(boundsThis);
0571:
0572:                    imBounds = JAI.create("overlay", imBounds, imROI);
0573:                    imDest = JAI.create(op, imThis, imBounds);
0574:
0575:                } else if (boundsROI.contains(boundsThis)) {
0576:
0577:                    PlanarImage imBounds = createBinaryImage(boundsROI);
0578:
0579:                    imBounds = JAI.create("overlay", imBounds, imThis);
0580:                    imDest = JAI.create(op, imBounds, imROI);
0581:
0582:                } else {
0583:
0584:                    Rectangle merged = boundsThis.union(boundsROI);
0585:
0586:                    PlanarImage imBoundsThis = createBinaryImage(merged);
0587:                    PlanarImage imBoundsROI = createBinaryImage(merged);
0588:
0589:                    imBoundsThis = JAI.create("overlay", imBoundsThis, imThis);
0590:                    imBoundsROI = JAI.create("overlay", imBoundsROI, imROI);
0591:                    imDest = JAI.create(op, imBoundsThis, imBoundsROI);
0592:                }
0593:
0594:                return new ROI(imDest, threshold);
0595:            }
0596:
0597:            /**
0598:             * Adds another <code>ROI</code> to this one and returns the result
0599:             * as a new <code>ROI</code>. The supplied <code>ROI</code> will
0600:             * be converted to a rendered form if necessary. The bounds of the
0601:             * resultant <code>ROI</code> will be the union of the bounds of the
0602:             * two <code>ROI</code>s being merged.
0603:             *
0604:             * @param roi An ROI.
0605:             * @throws IllegalArgumentException if roi is null.
0606:             * @return A new ROI containing the new ROI data.
0607:             */
0608:            public ROI add(ROI roi) {
0609:                return createOpROI(roi, "add");
0610:            }
0611:
0612:            /**
0613:             * Subtracts another <code>ROI</code> from this one and returns the
0614:             * result as a new <code>ROI</code>. The supplied <code>ROI</code>
0615:             * will be converted to a rendered form if necessary. The
0616:             * bounds of the resultant <code>ROI</code> will be the same as
0617:             * <code>this</code> <code>ROI</code>.
0618:             *
0619:             * @param roi An ROI.
0620:             * @throws IllegalArgumentException if roi is null.
0621:             * @return A new ROI containing the new ROI data.
0622:             */
0623:            public ROI subtract(ROI roi) {
0624:                return createOpROI(roi, "subtract");
0625:            }
0626:
0627:            /**
0628:             * Intersects the <code>ROI</code> with another <code>ROI</code> and returns the result as
0629:             * a new <code>ROI</code>. The supplied <code>ROI</code> will be converted to a rendered
0630:             * form if necessary. The bounds of the resultant <code>ROI</code> will be the
0631:             * intersection of the bounds of the two <code>ROI</code>s being merged.
0632:             *
0633:             * @param roi An ROI.
0634:             * @throws IllegalArgumentException if roi is null.
0635:             * @return A new ROI containing the new ROI data.
0636:             */
0637:            public ROI intersect(ROI roi) {
0638:                return createOpROI(roi, "and");
0639:            }
0640:
0641:            /**
0642:             * Exclusive-ors the <code>ROI</code> with another <code>ROI</code>
0643:             * and returns the result as a new <code>ROI</code>. The supplied
0644:             * <code>ROI</code> will be converted to a rendered form if
0645:             * necessary. The bounds of the resultant <code>ROI</code> will
0646:             * be the union of the bounds of the two <code>ROI</code>s being
0647:             * merged.
0648:             *
0649:             * @param roi An ROI.
0650:             * @throws IllegalArgumentException if roi is null.
0651:             * @return A new ROI containing the new ROI data.
0652:             */
0653:            public ROI exclusiveOr(ROI roi) {
0654:                return createOpROI(roi, "xor");
0655:            }
0656:
0657:            /**
0658:             * Performs an affine transformation and returns the result as a new
0659:             * ROI.  The transformation is performed by an "Affine" RIF using the
0660:             * indicated interpolation method.
0661:             *
0662:             * @param at an AffineTransform specifying the transformation.
0663:             * @param interp the Interpolation to be used.
0664:             * @throws IllegalArgumentException if at is null.
0665:             * @throws IllegalArgumentException if interp is null.
0666:             * @return a new ROI containing the transformed ROI data.
0667:             */
0668:            public ROI transform(AffineTransform at, Interpolation interp) {
0669:
0670:                if (at == null) {
0671:                    throw new IllegalArgumentException(JaiI18N
0672:                            .getString("ROI5"));
0673:                }
0674:
0675:                if (interp == null) {
0676:                    throw new IllegalArgumentException(JaiI18N
0677:                            .getString("ROI6"));
0678:                }
0679:
0680:                ParameterBlock paramBlock = new ParameterBlock();
0681:                paramBlock.add(at);
0682:                paramBlock.add(interp);
0683:                return performImageOp("Affine", paramBlock, 0, null);
0684:            }
0685:
0686:            /**
0687:             * Performs an affine transformation and returns the result as a new
0688:             * ROI.  The transformation is performed by an "Affine" RIF using
0689:             * nearest neighbor interpolation.
0690:             *
0691:             * @param at an AffineTransform specifying the transformation.
0692:             * @throws IllegalArgumentException if at is null.
0693:             * @return a new ROI containing the transformed ROI data.
0694:             */
0695:            public ROI transform(AffineTransform at) {
0696:                if (at == null) {
0697:                    throw new IllegalArgumentException(JaiI18N
0698:                            .getString("Generic0"));
0699:                }
0700:
0701:                return transform(at, Interpolation
0702:                        .getInstance(Interpolation.INTERP_NEAREST));
0703:            }
0704:
0705:            /**
0706:             * Transforms an ROI using an imaging operation.  The operation is
0707:             * specified by a <code>RenderedImageFactory</code>.  The
0708:             * operation's <code>ParameterBlock</code>, minus the image source
0709:             * itself is supplied, along with an index indicating where to
0710:             * insert the ROI image.  The <code>renderHints</code> argument
0711:             * allows rendering hints to be passed in.
0712:             *
0713:             * @param RIF A <code>RenderedImageFactory</code> that will be used
0714:             *        to create the op.
0715:             * @param paramBlock A <code>ParameterBlock</code> containing all
0716:             *        sources and parameters for the op except for the ROI itself.
0717:             * @param sourceIndex The index of the <code>ParameterBlock</code>'s
0718:             *        sources where the ROI is to be inserted.
0719:             * @param renderHints A <code>RenderingHints</code> object containing
0720:             *        rendering hints, or null.
0721:             * @throws IllegalArgumentException if RIF is null.
0722:             * @throws IllegalArgumentException if paramBlock is null.
0723:             */
0724:            public ROI performImageOp(RenderedImageFactory RIF,
0725:                    ParameterBlock paramBlock, int sourceIndex,
0726:                    RenderingHints renderHints) {
0727:
0728:                if (RIF == null || paramBlock == null) {
0729:                    throw new IllegalArgumentException(JaiI18N
0730:                            .getString("Generic0"));
0731:                }
0732:
0733:                // Clone the ParameterBlock and insert a source
0734:                ParameterBlock pb = (ParameterBlock) paramBlock.clone();
0735:                Vector sources = pb.getSources();
0736:                sources.insertElementAt(this .getAsImage(), sourceIndex);
0737:
0738:                // Create a new RenderedImage based on the RIF
0739:                // and ParameterBlock.
0740:                RenderedImage im = RIF.create(pb, renderHints);
0741:                return new ROI(im, threshold);
0742:            }
0743:
0744:            /**
0745:             * Transforms an ROI using an imaging operation.  The
0746:             * operation is specified by name; the default JAI registry is
0747:             * used to resolve this into a RIF.  The operation's
0748:             * <code>ParameterBlock</code>, minus the image source itself is supplied,
0749:             * along with an index indicating where to insert the ROI image.
0750:             * The <code>renderHints</code> argument allows rendering hints to
0751:             * be passed in.
0752:             *
0753:             * @param name The name of the operation to perform.
0754:             * @param paramBlock A <code>ParameterBlock</code> containing all
0755:             *        sources and parameters for the op except for the ROI itself.
0756:             * @param sourceIndex The index of the <code>ParameterBlock</code>'s
0757:             *        sources where the ROI is to be inserted.
0758:             * @param renderHints A <code>RenderingHints</code> object containing
0759:             *        rendering hints, or null.
0760:             * @throws IllegalArgumentException if name is null.
0761:             * @throws IllegalArgumentException if paramBlock is null.
0762:             */
0763:            public ROI performImageOp(String name, ParameterBlock paramBlock,
0764:                    int sourceIndex, RenderingHints renderHints) {
0765:
0766:                if (name == null || paramBlock == null) {
0767:                    throw new IllegalArgumentException(JaiI18N
0768:                            .getString("Generic0"));
0769:                }
0770:
0771:                // Clone the ParameterBlock and insert a source
0772:                ParameterBlock pb = (ParameterBlock) paramBlock.clone();
0773:                Vector sources = pb.getSources();
0774:                sources.insertElementAt(this .getAsImage(), sourceIndex);
0775:
0776:                // Create a new RenderedImage based on the operation name
0777:                // and ParameterBlock using the default registry.
0778:                RenderedImage im = JAI.create(name, pb, renderHints);
0779:                return new ROI(im, threshold);
0780:            }
0781:
0782:            /**
0783:             * Returns a <code>Shape</code> representation of the
0784:             * <code>ROI</code>, if possible. If none is available, null is
0785:             * returned. A proper instance of <code>ROI</code> (one that is not
0786:             * an instance of any subclass of <code>ROI</code>) will always
0787:             * return null.
0788:             *
0789:             * @return The <code>ROI</code> as a <code>Shape</code>.
0790:             */
0791:            public Shape getAsShape() {
0792:                return null;
0793:            }
0794:
0795:            /**
0796:             * Returns a <code>PlanarImage</code> representation of the
0797:             * <code>ROI</code>. This method will always succeed. This method
0798:             * returns a (bilevel) image whose <code>SampleModel</code> is an
0799:             * instance of <code>MultiPixelPackedSampleModel</code>.
0800:             *
0801:             * @return The <code>ROI</code> as a <code>PlanarImage</code>.
0802:             */
0803:            public PlanarImage getAsImage() {
0804:                return theImage;
0805:            }
0806:
0807:            /**
0808:             * Returns a bitmask for a given rectangular region of the ROI
0809:             * indicating whether the pixel is included in the region of
0810:             * interest.  The results are packed into 32-bit integers, with
0811:             * the MSB considered to lie on the left.  The last entry in each
0812:             * row of the result may have bits that lie outside of the
0813:             * requested rectangle.  These bits are guaranteed to be zeroed.
0814:             *
0815:             * <p> The <code>mask</code> array, if supplied, must be of length
0816:             * equal to or greater than <code>height</code> and each of its
0817:             * subarrays must have length equal to or greater than (width +
0818:             * 31)/32.  If <code>null</code> is passed in, a suitable array
0819:             * will be constructed.  If the mask is non-null but has
0820:             * insufficient size, an exception will be thrown.
0821:             *
0822:             * @param x The X coordinate of the upper left corner of the rectangle.
0823:             * @param y The Y coordinate of the upper left corner of the rectangle.
0824:             * @param width The width of the rectangle.
0825:             * @param height The height of the rectangle.
0826:             * @param mask A two-dimensional array of ints at least
0827:             *        (width + 31)/32 entries wide and (height) entries tall,
0828:             *        or null.
0829:             * @return A reference to the <code>mask</code> parameter, or
0830:             *         to a newly constructed array if <code>mask</code> is
0831:             *         <code>null</code>. If the specified rectangle does
0832:             *	       intersect with the image bounds then a <code>null</code>
0833:             *	       is returned.
0834:             */
0835:            public int[][] getAsBitmask(int x, int y, int width, int height,
0836:                    int[][] mask) {
0837:
0838:                Rectangle rect = getBounds().intersection(
0839:                        new Rectangle(x, y, width, height));
0840:
0841:                // Verify that the requested area actually intersects the ROI image.
0842:                if (rect.isEmpty()) {
0843:                    return null;
0844:                }
0845:
0846:                // Determine the minimum required width of the bitmask in integers.
0847:                int bitmaskIntWidth = (width + 31) / 32;
0848:
0849:                // Construct bitmask array if argument is null.
0850:                if (mask == null) {
0851:                    mask = new int[height][bitmaskIntWidth];
0852:                } else if (mask.length < height
0853:                        || mask[0].length < bitmaskIntWidth) {
0854:                    throw new RuntimeException(JaiI18N.getString("ROI3"));
0855:                }
0856:
0857:                byte[] data = ImageUtil.getPackedBinaryData(theImage.getData(),
0858:                        rect);
0859:
0860:                // ImageUtil.getPackedBinaryData does not zero out the extra
0861:                // bits used to pad to the nearest byte - so zero these
0862:                // bits out.
0863:                int leftover = rect.width % 8;
0864:
0865:                if (leftover != 0) {
0866:                    int datamask = ((1 << leftover) - 1) << (8 - leftover);
0867:                    int linestride = (width + 7) / 8;
0868:
0869:                    for (int i = linestride - 1; i < data.length; i += linestride) {
0870:                        data[i] = (byte) (data[i] & datamask);
0871:                    }
0872:                }
0873:
0874:                int lineStride = (rect.width + 7) / 8;
0875:                int leftOver = lineStride % 4;
0876:
0877:                int row, col, k;
0878:                int ncols = (lineStride - leftOver) / 4;
0879:
0880:                for (row = 0, k = 0; row < rect.height; row++) {
0881:                    int[] maskRow = mask[row];
0882:
0883:                    for (col = 0; col < ncols; col++) {
0884:                        maskRow[col] = ((data[k] & 0xff) << 24)
0885:                                | ((data[k + 1] & 0xff) << 16)
0886:                                | ((data[k + 2] & 0xff) << 8)
0887:                                | ((data[k + 3] & 0xff) << 0);
0888:                        k += 4;
0889:                    }
0890:
0891:                    switch (leftOver) {
0892:                    case 0:
0893:                        break;
0894:                    case 1:
0895:                        maskRow[col++] = ((data[k] & 0xff) << 24);
0896:                        break;
0897:                    case 2:
0898:                        maskRow[col++] = ((data[k] & 0xff) << 24)
0899:                                | ((data[k + 1] & 0xff) << 16);
0900:                        break;
0901:                    case 3:
0902:                        maskRow[col++] = ((data[k] & 0xff) << 24)
0903:                                | ((data[k + 1] & 0xff) << 16)
0904:                                | ((data[k + 2] & 0xff) << 8);
0905:                        break;
0906:                    }
0907:
0908:                    k += leftOver;
0909:
0910:                    Arrays.fill(maskRow, col, bitmaskIntWidth, 0);
0911:                }
0912:
0913:                // Clear any trailing rows.
0914:                for (row = rect.height; row < height; row++) {
0915:                    Arrays.fill(mask[row], 0);
0916:                }
0917:
0918:                return mask;
0919:            }
0920:
0921:            /**
0922:             * Returns a <code>LinkedList</code> of <code>Rectangle</code>s
0923:             * for a given rectangular region of the ROI. The
0924:             * <code>Rectangle</code>s in the list are merged into a minimal
0925:             * set.
0926:             *
0927:             * @param x The X coordinate of the upper left corner of the rectangle.
0928:             * @param y The Y coordinate of the upper left corner of the rectangle.
0929:             * @param width The width of the rectangle.
0930:             * @param height The height of the rectangle.
0931:             * @return A <code>LinkedList</code> of <code>Rectangle</code>s.
0932:             *	       If the specified rectangle does intersect with the image
0933:             *	       bounds then a <code>null</code> is returned.
0934:             */
0935:            public LinkedList getAsRectangleList(int x, int y, int width,
0936:                    int height) {
0937:                return getAsRectangleList(x, y, width, height, true);
0938:            }
0939:
0940:            /**
0941:             * Returns a <code>LinkedList</code> of <code>Rectangle</code>s for
0942:             * a given rectangular region of the ROI.
0943:             *
0944:             * @param x The X coordinate of the upper left corner of the rectangle.
0945:             * @param y The Y coordinate of the upper left corner of the rectangle.
0946:             * @param width The width of the rectangle.
0947:             * @param height The height of the rectangle.
0948:             * @param mergeRectangles <code>true</code> if the <code>Rectangle</code>s
0949:             *        are to be merged into a minimal set.
0950:             * @return A <code>LinkedList</code> of <code>Rectangle</code>s.
0951:             *	       If the specified rectangle does intersect with the image
0952:             *	       bounds then a <code>null</code> is returned.
0953:             */
0954:            protected LinkedList getAsRectangleList(int x, int y, int width,
0955:                    int height, boolean mergeRectangles) {
0956:
0957:                // Verify that the requested area actually intersects the ROI image.
0958:                Rectangle bounds = getBounds();
0959:                Rectangle rect = new Rectangle(x, y, width, height);
0960:                if (!bounds.intersects(rect)) {
0961:                    return null;
0962:                }
0963:
0964:                // Clip the requested area to the ROI image if necessary.
0965:                if (!bounds.contains(rect)) {
0966:                    rect = bounds.intersection(rect);
0967:                    x = rect.x;
0968:                    y = rect.y;
0969:                    width = rect.width;
0970:                    height = rect.height;
0971:                }
0972:
0973:                byte[] data = ImageUtil.getPackedBinaryData(theImage.getData(),
0974:                        rect);
0975:
0976:                // ImageUtil.getPackedBinaryData does not zero out the extra
0977:                // bits used to pad to the nearest byte - therefore ignore
0978:                // these bits.
0979:                int lineStride = (width + 7) / 8;
0980:                int leftover = width % 8;
0981:                int mask = (leftover == 0) ? 0xff
0982:                        : ((1 << leftover) - 1) << (8 - leftover);
0983:
0984:                LinkedList rectList = new LinkedList();
0985:
0986:                // Calculate the initial list of rectangles as a list of run
0987:                // lengths which are in fact rectangles of unit height.
0988:
0989:                int row, col, k, start, val, cnt;
0990:
0991:                for (row = 0, k = 0; row < height; row++) {
0992:
0993:                    start = -1;
0994:
0995:                    for (col = 0, cnt = 0; col < lineStride; col++, k++) {
0996:
0997:                        val = data[k] & ((col == lineStride - 1) ? mask : 0xff);
0998:
0999:                        if (val == 0) {
1000:                            if (start >= 0) {
1001:                                rectList.addLast(new Rectangle(x + start, y
1002:                                        + row, col * 8 - start, 1));
1003:                                start = -1;
1004:                            }
1005:
1006:                        } else if (val == 0xff) {
1007:                            if (start < 0) {
1008:                                start = col * 8;
1009:                            }
1010:
1011:                        } else {
1012:                            for (int bit = 7; bit >= 0; bit--) {
1013:                                if ((val & (1 << bit)) == 0x00) {
1014:                                    if (start >= 0) {
1015:                                        rectList.addLast(new Rectangle(x
1016:                                                + start, y + row, col * 8
1017:                                                + (7 - bit) - start, 1));
1018:                                        start = -1;
1019:                                    }
1020:                                } else {
1021:                                    if (start < 0) {
1022:                                        start = col * 8 + (7 - bit);
1023:                                    }
1024:                                }
1025:                            }
1026:                        }
1027:                    }
1028:
1029:                    if (start >= 0) {
1030:                        rectList.addLast(new Rectangle(x + start, y + row, col
1031:                                * 8 - start, 1));
1032:                    }
1033:                }
1034:
1035:                // Return the list of Rectangles possibly merged into a minimal set.
1036:                return mergeRectangles ? mergeRunLengthList(rectList)
1037:                        : rectList;
1038:            }
1039:
1040:            /**
1041:             * Serialize the <code>ROI</code>.
1042:             *
1043:             * @param out The <code>ObjectOutputStream</code>.
1044:             */
1045:            private void writeObject(ObjectOutputStream out) throws IOException {
1046:                out.defaultWriteObject();
1047:                if (theImage != null) {
1048:                    out.writeBoolean(true);
1049:                    RenderingHints hints = new RenderingHints(null);
1050:                    hints.put(JAI.KEY_SERIALIZE_DEEP_COPY, new Boolean(true));
1051:                    out
1052:                            .writeObject(SerializerFactory.getState(theImage,
1053:                                    hints));
1054:                } else {
1055:                    out.writeBoolean(false);
1056:                }
1057:            }
1058:
1059:            /**
1060:             * Deserialize the <code>ROI</code>.
1061:             *
1062:             * @param in The <code>ObjectInputStream</code>.
1063:             */
1064:            private void readObject(ObjectInputStream in) throws IOException,
1065:                    ClassNotFoundException {
1066:                in.defaultReadObject();
1067:                if ((boolean) in.readBoolean()) {
1068:                    SerializableState ss = (SerializableState) in.readObject();
1069:                    RenderedImage ri = (RenderedImage) (ss.getObject());
1070:                    theImage = PlanarImage.wrapRenderedImage(ri);
1071:                } else {
1072:                    theImage = null;
1073:                }
1074:                iter = null;
1075:            }
1076:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.