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 public Component(IntValuePixel p, Class<? extends ComponentFeature>... featureClasses) 071 { 072 this.pivot = p; 073 074 features = new ComponentFeature[featureClasses.length]; 075 for (int i = 0; i < featureClasses.length; i++) { 076 try { 077 features[i] = featureClasses[i].newInstance(); 078 } catch (final Exception e) { 079 throw new AssertionError(e); 080 } 081 } 082 } 083 084 /** 085 * {@inheritDoc} 086 * 087 * @see java.util.AbstractCollection#toString() 088 */ 089 @Override 090 public String toString() 091 { 092 return "Comp@" + super.hashCode() + "(px:" + size + ",gl:" + pivot.value + ")"; 093 }; 094 095 /** 096 * Add a pixel to the component 097 * 098 * @param p 099 * the pixel to add 100 */ 101 public void accumulate(IntValuePixel p) { 102 size++; 103 104 for (final ComponentFeature f : features) { 105 f.addSample(p); 106 } 107 } 108 109 /** 110 * Merge another component with this one 111 * 112 * @param p 113 * the component to merge into this 114 */ 115 public void merge(Component p) { 116 size += p.size(); 117 118 for (int i = 0; i < features.length; i++) { 119 features[i].merge(p.features[i]); 120 } 121 } 122 123 /** 124 * The size of the component (i.e. the number of pixels) 125 * 126 * @return the size of the component 127 */ 128 public int size() { 129 return size; 130 } 131 132 /** 133 * Get the pixels in the component. If the component contains a 134 * {@link PixelsFeature} then the pixels will be returned from that; 135 * otherwise a set containing just the pivot pixel will be returned. 136 * 137 * @return the pixels in the component if possible, or just the pivot pixel 138 */ 139 public Set<Pixel> getPixels() { 140 for (final ComponentFeature f : features) { 141 if (f instanceof PixelsFeature) 142 return ((PixelsFeature) f).pixels; 143 } 144 145 final Set<Pixel> pix = new HashSet<Pixel>(1); 146 pix.add(pivot); 147 return pix; 148 } 149 150 @Override 151 public Component clone() { 152 Component result; 153 try { 154 result = (Component) super.clone(); 155 result.features = new ComponentFeature[features.length]; 156 for (int i = 0; i < features.length; i++) 157 result.features[i] = features[i].clone(); 158 159 // result.pixels = pixels.clone(); 160 161 return result; 162 } catch (final CloneNotSupportedException e) { 163 throw new AssertionError(e); 164 } 165 } 166 167 /** 168 * Get the feature at the given index 169 * 170 * @param index 171 * the index 172 * @return the feature at the given index or null if it doesn't exist 173 */ 174 public ComponentFeature getFeature(int index) { 175 if (index >= features.length) 176 return null; 177 178 return features[index]; 179 } 180 181 /** 182 * Get the feature matching the given class if it exists. If more than one 183 * feature of the given class exists, then the first will be returned. 184 * 185 * @param <T> 186 * the class of the feature 187 * @param featureClass 188 * the class of the feature 189 * @return the feature with the given class; or null if no feature is found 190 */ 191 @SuppressWarnings("unchecked") 192 public <T extends ComponentFeature> T getFeature(Class<T> featureClass) { 193 for (final ComponentFeature f : features) 194 if (f.getClass().isAssignableFrom(featureClass)) 195 return (T) f; 196 197 return null; 198 } 199}