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.contour; 031 032import java.io.PrintWriter; 033import java.io.StringWriter; 034import java.util.ArrayList; 035import java.util.Iterator; 036import java.util.List; 037 038import org.openimaj.image.pixel.Pixel; 039import org.openimaj.math.geometry.shape.Polygon; 040import org.openimaj.math.geometry.shape.Rectangle; 041 042/** 043 * A contour or hierarchical set of contours within an image. 044 * 045 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 046 */ 047public class Contour extends Polygon { 048 /** 049 * The type of contour 050 */ 051 public ContourType type; 052 /** 053 * sub contours 054 */ 055 public List<Contour> children = new ArrayList<Contour>(); 056 /** 057 * The parent contour, might be null 058 */ 059 public Contour parent; 060 061 /** 062 * where the contour starts 063 */ 064 public Pixel start; 065 Rectangle rect = null; 066 067 /** 068 * Construct a contour with the given type and start at the origin 069 * 070 * @param type 071 * the type 072 */ 073 public Contour(ContourType type) { 074 this.type = type; 075 this.start = new Pixel(0, 0); 076 } 077 078 /** 079 * Construct a contour with the given type and start pixel 080 * 081 * @param type 082 * the type 083 * @param x 084 * the x-ordinate of the start pixel 085 * @param y 086 * the y-ordinate of the start pixel 087 */ 088 public Contour(ContourType type, int x, int y) { 089 this.type = type; 090 this.start = new Pixel(x, y); 091 } 092 093 /** 094 * Construct a contour with the given type and start pixel 095 * 096 * @param type 097 * the type 098 * @param p 099 * the coordinate of the start pixel 100 */ 101 public Contour(ContourType type, Pixel p) { 102 this.type = type; 103 this.start = p; 104 } 105 106 /** 107 * Construct a contour with the given starting coordinate and a 108 * <code>null</code> type. 109 * 110 * @param x 111 * the x-ordinate of the start pixel 112 * @param y 113 * the y-ordinate of the start pixel 114 */ 115 public Contour(int x, int y) { 116 this.type = null; 117 this.start = new Pixel(x, y); 118 } 119 120 protected void setParent(Contour bp) { 121 this.parent = bp; 122 bp.children.add(this); 123 } 124 125 @Override 126 public String toString() { 127 final StringWriter contour = new StringWriter(); 128 final PrintWriter pw = new PrintWriter(contour); 129 pw.println(String.format("[%s] start: %s %s", this.type, this.start, this.points)); 130 for (final Contour child : this.children) { 131 pw.print(child); 132 } 133 pw.flush(); 134 return contour.toString(); 135 } 136 137 /** 138 * Complete this contour by computing it's bounding box 139 */ 140 public void finish() { 141 this.rect = this.calculateRegularBoundingBox(); 142 } 143 144 private class ContourIterator implements Iterator<Contour> { 145 final List<Contour> toProcess = new ArrayList<Contour>(); 146 147 ContourIterator() { 148 toProcess.add(Contour.this); 149 } 150 151 @Override 152 public boolean hasNext() { 153 return !toProcess.isEmpty(); 154 } 155 156 @Override 157 public Contour next() { 158 final Contour next = toProcess.remove(toProcess.size() - 1); 159 toProcess.addAll(next.children); 160 return next; 161 } 162 163 @Override 164 public void remove() { 165 throw new UnsupportedOperationException("Removal not supported"); 166 } 167 } 168 169 /** 170 * Get an iterator over the complete set of contours (including the root 171 * itself) 172 * 173 * @return the iterator 174 */ 175 public Iterator<Contour> contourIterator() { 176 return new ContourIterator(); 177 } 178 179 /** 180 * Get an {@link Iterable} over all the contours belonging to this root 181 * (including the root itself) 182 * 183 * @return the iterable 184 */ 185 public Iterable<Contour> contourIterable() { 186 return new Iterable<Contour>() { 187 @Override 188 public Iterator<Contour> iterator() { 189 return contourIterator(); 190 } 191 }; 192 } 193 194 @Override 195 public boolean isHole() { 196 return type != null && type.equals(ContourType.HOLE); 197 } 198}