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.analysis.watershed; 031 032import java.util.HashSet; 033import java.util.Set; 034 035import org.openimaj.image.analysis.watershed.feature.ComponentFeature; 036import org.openimaj.image.analysis.watershed.feature.PixelsFeature; 037import org.openimaj.image.pixel.IntValuePixel; 038import org.openimaj.image.pixel.Pixel; 039 040/** 041 * Represents a region or set of pixels (the name is based on the Microsoft 042 * paper) 043 * 044 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 045 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 046 * 047 */ 048public class Component implements Cloneable 049{ 050 /** Whether this component represents an MSER */ 051 public boolean isMSER = false; 052 053 /** List of features representing this component */ 054 public ComponentFeature[] features; 055 056 /** 057 * The pivot pixel 058 */ 059 public IntValuePixel pivot; 060 private int size = 0; 061 062 /** 063 * Default constructor. 064 * 065 * @param p 066 * The grey level of the component 067 * @param featureClasses 068 * the list of features to create for the component 069 */ 070 @SafeVarargs 071 public Component(IntValuePixel p, Class<? extends ComponentFeature>... featureClasses) 072 { 073 this.pivot = p; 074 075 features = new ComponentFeature[featureClasses.length]; 076 for (int i = 0; i < featureClasses.length; i++) { 077 try { 078 features[i] = featureClasses[i].newInstance(); 079 } catch (final Exception e) { 080 throw new AssertionError(e); 081 } 082 } 083 } 084 085 /** 086 * {@inheritDoc} 087 * 088 * @see java.util.AbstractCollection#toString() 089 */ 090 @Override 091 public String toString() 092 { 093 return "Comp@" + super.hashCode() + "(px:" + size + ",gl:" + pivot.value + ")"; 094 }; 095 096 /** 097 * Add a pixel to the component 098 * 099 * @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}