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 }