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.image.connectedcomponent.proc;
031
032import org.openimaj.feature.DoubleFV;
033import org.openimaj.feature.FeatureVectorProvider;
034import org.openimaj.image.pixel.ConnectedComponent;
035import org.openimaj.image.processor.connectedcomponent.ConnectedComponentProcessor;
036
037/**
038 * Basic descriptors of the shape of a connected component.
039 * 
040 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
041 * 
042 */
043public class BasicShapeDescriptor implements ConnectedComponentProcessor, FeatureVectorProvider<DoubleFV> {
044        /**
045         * An enum of all the different basic shape descriptors.
046         */
047        public enum BasicShapeDescriptorType {
048                /**
049                 * The area of the component
050                 * 
051                 * @see ConnectedComponent#calculateArea()
052                 */
053                AREA {
054                        @Override
055                        public DoubleFV getFeatureVector(BasicShapeDescriptor desc) {
056                                return new DoubleFV(new double[] { desc.area });
057                        }
058                },
059                /**
060                 * The centroid of the component
061                 * 
062                 * @see ConnectedComponent#calculateCentroid()
063                 */
064                CENTROID {
065                        @Override
066                        public DoubleFV getFeatureVector(BasicShapeDescriptor desc) {
067                                return new DoubleFV(new double[] { desc.cx, desc.cy });
068                        }
069                },
070                /**
071                 * The primary orientation of the component
072                 * 
073                 * @see ConnectedComponent#calculateDirection()
074                 */
075                DIRECTION {
076                        @Override
077                        public DoubleFV getFeatureVector(BasicShapeDescriptor desc) {
078                                return new DoubleFV(new double[] { desc.direction });
079                        }
080                },
081                /**
082                 * The elongatedness of the component. Elongatedness is defined as the
083                 * ratio of the height to width of the oriented bounding box of the
084                 * component.
085                 * 
086                 * @see ConnectedComponent#calculateOrientatedBoundingBoxAspectRatio()
087                 */
088                ELONGATEDNESS {
089                        @Override
090                        public DoubleFV getFeatureVector(BasicShapeDescriptor desc) {
091                                return new DoubleFV(new double[] { desc.elongatedness });
092                        }
093                },
094                /**
095                 * The compactness of the component. Compactness is defined as the ratio
096                 * of the squared edge length of the component to its area.
097                 */
098                COMPACTNESS {
099                        @Override
100                        public DoubleFV getFeatureVector(BasicShapeDescriptor desc) {
101                                return new DoubleFV(new double[] { desc.compactness });
102                        }
103                },
104                /**
105                 * The ratio of the area of the component to the area of its convex hull
106                 * 
107                 * @see ConnectedComponent#calculatePercentageConvexHullFit()
108                 */
109                CHFIT {
110                        @Override
111                        public DoubleFV getFeatureVector(BasicShapeDescriptor desc) {
112                                return new DoubleFV(new double[] { desc.chfit });
113                        }
114                },
115                /**
116                 * The estimated number of corners of the component
117                 * 
118                 * @see ConnectedComponent#estimateNumberOfVertices(int, int)
119                 */
120                CORNERS {
121                        @Override
122                        public DoubleFV getFeatureVector(BasicShapeDescriptor desc) {
123                                return new DoubleFV(new double[] { desc.cornerEst });
124                        }
125                };
126
127                /**
128                 * Create a @link{FeatureVector} representation of the specified
129                 * description
130                 * 
131                 * @param desc
132                 *            the descriptor
133                 * @return the feature vector representation
134                 */
135                public abstract DoubleFV getFeatureVector(BasicShapeDescriptor desc);
136        }
137
138        /**
139         * The area of the component
140         * 
141         * @see ConnectedComponent#calculateArea()
142         */
143        public double area;
144
145        /**
146         * The x coordinate of the component centroid
147         * 
148         * @see ConnectedComponent#calculateCentroid()
149         */
150        public double cx; // centroid x
151
152        /**
153         * The y coordinate of the component centroid
154         * 
155         * @see ConnectedComponent#calculateCentroid()
156         */
157        public double cy; // y
158
159        /**
160         * The primary orientation of the component
161         * 
162         * @see ConnectedComponent#calculateDirection()
163         */
164        public double direction;
165
166        /**
167         * The elongatedness of the component. Elongatedness is defined as the ratio
168         * of the height to width of the oriented bounding box of the component.
169         * 
170         * @see ConnectedComponent#calculateOrientatedBoundingBoxAspectRatio()
171         */
172        public double elongatedness;
173
174        /**
175         * The compactness of the component. Compactness is defined as the ratio of
176         * the squared edge length of the component to its area.
177         */
178        public double compactness;
179
180        /**
181         * The ratio of the area of the component to the area of its convex hull
182         * 
183         * @see ConnectedComponent#calculatePercentageConvexHullFit()
184         */
185        public double chfit;
186
187        /**
188         * The estimated number of corners of the component
189         * 
190         * @see ConnectedComponent#estimateNumberOfVertices(int, int)
191         */
192        public double cornerEst;
193
194        @Override
195        public void process(ConnectedComponent cc) {
196                area = cc.calculateArea();
197
198                final double[] c = cc.calculateCentroid();
199                cx = c[0];
200                cy = c[1];
201
202                direction = cc.calculateDirection();
203
204                elongatedness = cc.calculateOrientatedBoundingBoxAspectRatio();
205
206                final float edge_length = cc.getOuterBoundary().size();
207                compactness = (edge_length * edge_length) / new ConnectedComponent(cc.toPolygon()).calculateArea();
208
209                if (area > 4)
210                        chfit = new ConnectedComponent(cc.toPolygon()).calculatePercentageConvexHullFit(); // chfit
211                                                                                                                                                                                                // won't
212                                                                                                                                                                                                // work
213                                                                                                                                                                                                // for
214                                                                                                                                                                                                // really
215                                                                                                                                                                                                // small
216                                                                                                                                                                                                // regions
217                else
218                        chfit = 1;
219
220                if (area > 100)
221                        cornerEst = cc.estimateNumberOfVertices(3, 10);
222                else
223                        cornerEst = area;
224        }
225
226        /**
227         * Get all the values of the descriptor as an array in the order area,
228         * centroid_x, centroid_y, direction, elongatedness, compactness
229         * convex_hull_fit, corner_count
230         * 
231         * @return an array of descriptor values
232         */
233        public double[] getFeatureVectorArray() {
234                return new double[] { area, cx, cy, direction, elongatedness, compactness, chfit, cornerEst };
235        }
236
237        @Override
238        public DoubleFV getFeatureVector() {
239                return new DoubleFV(getFeatureVectorArray());
240        }
241}