1 /**
2 * Copyright (c) 2011, The University of Southampton and the individual contributors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * * Neither the name of the University of Southampton nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 package org.openimaj.image.analysis.watershed;
31
32 import java.util.HashSet;
33 import java.util.Set;
34
35 import org.openimaj.image.analysis.watershed.feature.ComponentFeature;
36 import org.openimaj.image.analysis.watershed.feature.PixelsFeature;
37 import org.openimaj.image.pixel.IntValuePixel;
38 import org.openimaj.image.pixel.Pixel;
39
40 /**
41 * Represents a region or set of pixels (the name is based on the Microsoft
42 * paper)
43 *
44 * @author David Dupplaw (dpd@ecs.soton.ac.uk)
45 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
46 *
47 */
48 public class Component implements Cloneable
49 {
50 /** Whether this component represents an MSER */
51 public boolean isMSER = false;
52
53 /** List of features representing this component */
54 public ComponentFeature[] features;
55
56 /**
57 * The pivot pixel
58 */
59 public IntValuePixel pivot;
60 private int size = 0;
61
62 /**
63 * Default constructor.
64 *
65 * @param p
66 * The grey level of the component
67 * @param featureClasses
68 * the list of features to create for the component
69 */
70 @SafeVarargs
71 public Component(IntValuePixel p, Class<? extends ComponentFeature>... featureClasses)
72 {
73 this.pivot = p;
74
75 features = new ComponentFeature[featureClasses.length];
76 for (int i = 0; i < featureClasses.length; i++) {
77 try {
78 features[i] = featureClasses[i].newInstance();
79 } catch (final Exception e) {
80 throw new AssertionError(e);
81 }
82 }
83 }
84
85 /**
86 * {@inheritDoc}
87 *
88 * @see java.util.AbstractCollection#toString()
89 */
90 @Override
91 public String toString()
92 {
93 return "Comp@" + super.hashCode() + "(px:" + size + ",gl:" + pivot.value + ")";
94 };
95
96 /**
97 * Add a pixel to the component
98 *
99 * @param p
100 * the pixel to add
101 */
102 public void accumulate(IntValuePixel p) {
103 size++;
104
105 for (final ComponentFeature f : features) {
106 f.addSample(p);
107 }
108 }
109
110 /**
111 * Merge another component with this one
112 *
113 * @param p
114 * the component to merge into this
115 */
116 public void merge(Component p) {
117 size += p.size();
118
119 for (int i = 0; i < features.length; i++) {
120 features[i].merge(p.features[i]);
121 }
122 }
123
124 /**
125 * The size of the component (i.e. the number of pixels)
126 *
127 * @return the size of the component
128 */
129 public int size() {
130 return size;
131 }
132
133 /**
134 * Get the pixels in the component. If the component contains a
135 * {@link PixelsFeature} then the pixels will be returned from that;
136 * otherwise a set containing just the pivot pixel will be returned.
137 *
138 * @return the pixels in the component if possible, or just the pivot pixel
139 */
140 public Set<Pixel> getPixels() {
141 for (final ComponentFeature f : features) {
142 if (f instanceof PixelsFeature)
143 return ((PixelsFeature) f).pixels;
144 }
145
146 final Set<Pixel> pix = new HashSet<Pixel>(1);
147 pix.add(pivot);
148 return pix;
149 }
150
151 @Override
152 public Component clone() {
153 Component result;
154 try {
155 result = (Component) super.clone();
156 result.features = new ComponentFeature[features.length];
157 for (int i = 0; i < features.length; i++)
158 result.features[i] = features[i].clone();
159
160 // result.pixels = pixels.clone();
161
162 return result;
163 } catch (final CloneNotSupportedException e) {
164 throw new AssertionError(e);
165 }
166 }
167
168 /**
169 * Get the feature at the given index
170 *
171 * @param index
172 * the index
173 * @return the feature at the given index or null if it doesn't exist
174 */
175 public ComponentFeature getFeature(int index) {
176 if (index >= features.length)
177 return null;
178
179 return features[index];
180 }
181
182 /**
183 * Get the feature matching the given class if it exists. If more than one
184 * feature of the given class exists, then the first will be returned.
185 *
186 * @param <T>
187 * the class of the feature
188 * @param featureClass
189 * the class of the feature
190 * @return the feature with the given class; or null if no feature is found
191 */
192 @SuppressWarnings("unchecked")
193 public <T extends ComponentFeature> T getFeature(Class<T> featureClass) {
194 for (final ComponentFeature f : features)
195 if (f.getClass().isAssignableFrom(featureClass))
196 return (T) f;
197
198 return null;
199 }
200 }