001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.tools.globalfeature;
031
032import org.kohsuke.args4j.CmdLineOptionsProvider;
033import org.kohsuke.args4j.Option;
034import org.kohsuke.args4j.ProxyOptionHandler;
035import org.openimaj.feature.FeatureVector;
036import org.openimaj.image.FImage;
037import org.openimaj.image.MBFImage;
038import org.openimaj.image.connectedcomponent.proc.AffineInvariantMoments;
039import org.openimaj.image.connectedcomponent.proc.BasicShapeDescriptor;
040import org.openimaj.image.connectedcomponent.proc.BasicShapeDescriptor.BasicShapeDescriptorType;
041import org.openimaj.image.connectedcomponent.proc.BoundaryDistanceDescriptor;
042import org.openimaj.image.connectedcomponent.proc.ColourDescriptor;
043import org.openimaj.image.connectedcomponent.proc.ColourDescriptor.ColourDescriptorType;
044import org.openimaj.image.connectedcomponent.proc.HuMoments;
045import org.openimaj.image.pixel.ConnectedComponent;
046
047/**
048 * Features describing the shape of the foreground object in an image. A mask is
049 * used to separate foreground/background pixels.
050 * 
051 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
052 * 
053 */
054public enum ShapeFeatures implements CmdLineOptionsProvider {
055        /**
056         * Any of the {@link GlobalFeatureType}s applied only to the foreground
057         * region.
058         */
059        GLOBAL {
060                @Override
061                public ShapeFeaturesOp getOptions() {
062                        return new ShapeFeaturesOp() {
063                                @Option(
064                                                name = "--global-feature-type",
065                                                aliases = "-g",
066                                                handler = ProxyOptionHandler.class,
067                                                usage = "Global feature type",
068                                                required = true)
069                                private GlobalFeatureType feature;
070                                private GlobalFeatureExtractor featureOp;
071
072                                @Override
073                                public FeatureVector execute(MBFImage image, FImage mask) {
074                                        return featureOp.extract(image);
075                                }
076                        };
077                }
078        },
079        /**
080         * Affine invariant moments
081         * 
082         * @see AffineInvariantMoments
083         */
084        AFFINE_INVARIANT_MOMENTS {
085                @Override
086                public ShapeFeaturesOp getOptions() {
087                        return new ShapeFeaturesOp() {
088                                @Override
089                                public FeatureVector execute(MBFImage image, FImage mask) {
090                                        final AffineInvariantMoments f = new AffineInvariantMoments();
091                                        f.process(c(mask));
092                                        return f.getFeatureVector();
093                                }
094                        };
095                }
096        },
097        /**
098         * Basic shape features
099         * 
100         * @see BasicShapeDescriptor
101         */
102        BASIC_SHAPE_FEATURES {
103                @Override
104                public ShapeFeaturesOp getOptions() {
105                        return new ShapeFeaturesOp() {
106                                @Option(name = "--type", aliases = "-t", usage = "Shape feature type", required = true)
107                                BasicShapeDescriptorType type;
108
109                                @Override
110                                public FeatureVector execute(MBFImage image, FImage mask) {
111                                        final BasicShapeDescriptor f = new BasicShapeDescriptor();
112                                        f.process(c(mask));
113                                        return type.getFeatureVector(f);
114                                }
115                        };
116                }
117        },
118        /**
119         * Distance from boundary descriptor
120         * 
121         * @see BoundaryDistanceDescriptor
122         */
123        BOUNDARY_DISTANCE_FEATURE {
124                @Override
125                public ShapeFeaturesOp getOptions() {
126                        return new ShapeFeaturesOp() {
127                                @Option(name = "--no-scale-normalisation", usage = "Disable scale normalisation", required = false)
128                                boolean noNormaliseScale = false;
129
130                                @Option(name = "--no-rotation-normalisation", usage = "Disable rotation normalisation", required = false)
131                                boolean noNormaliseRotation = false;
132
133                                @Override
134                                public FeatureVector execute(MBFImage image, FImage mask) {
135                                        final BoundaryDistanceDescriptor f = new BoundaryDistanceDescriptor(!noNormaliseScale,
136                                                        !noNormaliseRotation);
137                                        f.process(c(mask));
138                                        return f.getFeatureVector();
139                                }
140                        };
141                }
142        },
143        /**
144         * Hu moments
145         * 
146         * @see HuMoments
147         */
148        HU_MOMENTS {
149                @Override
150                public ShapeFeaturesOp getOptions() {
151                        return new ShapeFeaturesOp() {
152                                @Override
153                                public FeatureVector execute(MBFImage image, FImage mask) {
154                                        final HuMoments f = new HuMoments();
155                                        f.process(c(mask));
156                                        return f.getFeatureVector();
157                                }
158                        };
159                }
160        },
161        /**
162         * Colour statistics
163         * 
164         * @see ColourDescriptor
165         */
166        COLOR_STATISTICS {
167                @Override
168                public ShapeFeaturesOp getOptions() {
169                        return new ShapeFeaturesOp() {
170                                @Option(name = "--type", aliases = "-t", usage = "Colour statistics type", required = true)
171                                ColourDescriptorType type;
172
173                                @Override
174                                public FeatureVector execute(MBFImage image, FImage mask) {
175                                        final ColourDescriptor f = new ColourDescriptor(image);
176                                        f.process(c(mask));
177                                        return type.getFeatureVector(f);
178                                }
179                        };
180                }
181        };
182
183        protected ConnectedComponent c(FImage mask) {
184                return new ConnectedComponent(mask, 0.5f);
185        }
186
187        @Override
188        public abstract ShapeFeaturesOp getOptions();
189
190        /**
191         * An object able to perform the execution associated with a ShapeFeatures
192         * type; possibly contains extra options for the operation.
193         * 
194         * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
195         */
196        public interface ShapeFeaturesOp {
197                /**
198                 * Calculate a feature using the shape defined by the mask and possibly
199                 * the pixel values from the image.
200                 * 
201                 * @param image
202                 *            the image.
203                 * @param mask
204                 *            the mask.
205                 * @return the feature.
206                 */
207                public abstract FeatureVector execute(MBFImage image, FImage mask);
208        }
209}