001/******************************************************************************* 002 * This software is provided as a supplement to the authors' textbooks on digital 003 * image processing published by Springer-Verlag in various languages and editions. 004 * Permission to use and distribute this software is granted under the BSD 2-Clause 005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 007 * Visit http://imagingbook.com for additional details. 008 *******************************************************************************/ 009 010package imagingbook.pub.regions; 011 012import java.awt.Point; 013import java.awt.geom.Path2D; 014import java.util.ArrayList; 015import java.util.Iterator; 016import java.util.List; 017 018/** 019 * This class represents a closed contour as a sequence of 020 * pixel coordinates. It implements the {@link Comparable} 021 * interface for sorting contours by length. 022 * It supports iteration over the points along the contour, 023 * e.g., by 024 * <pre> 025 * Contour C = ...; 026 * for (Point p : C) { 027 * // process p ... 028 * } 029 * </pre> 030 * 031 * @version 2016-11-08 032 */ 033public class Contour implements Comparable<Contour>, Iterable<Point> { 034 035 static private int INITIAL_SIZE = 50; 036 037 private final int label; 038 private final List<Point> points; 039 040 /** 041 * Creates a new (empty) contour with the given region label. 042 * @param label the region label for this contour. 043 */ 044 public Contour (int label) { 045 this.label = label; 046 points = new ArrayList<Point>(INITIAL_SIZE); 047 } 048 049 protected void addPoint (Point p) { 050 points.add(p); 051 } 052 053 //--------------------- retrieve contour points ------- 054 055 /** 056 * Get the list of contour points. 057 * @return a reference to the internal list of contour points. 058 */ 059 public List<Point> getPointList() { 060 return points; 061 } 062 063 /** 064 * Get the contour points as an array. 065 * @return a new array of contour points. 066 */ 067 public Point[] getPointArray() { 068 return points.toArray(new Point[0]); 069 } 070 071 //--------------------- contour statistics ------------ 072 073 /** 074 * Get the length of the contour. 075 * @return the number of points on the contour. 076 */ 077 public int getLength() { 078 return points.size(); 079 } 080 081 /** 082 * Get the region label associated with this contour. 083 * @return the region label of the contour. 084 */ 085 public int getLabel() { 086 return label; 087 } 088 089 //--------------------- debug methods ------------------ 090 091// private void printPoints () { 092// for (Point pt: points) { 093// IJ.log(pt.toString()); 094// } 095// } 096 097 @Override 098 public String toString(){ 099 return 100 "Contour " + label + ": " + this.getLength() + " points"; 101 } 102 103 /** 104 * Get the polygon for this contour (for subsequent drawing). 105 * @return the polygon. 106 */ 107 public Path2D getPolygonPath() { 108 return getPolygonPath(0.5, 0.5); // offset by 0.5 to pass through pixel centers 109 } 110 111 /** 112 * Get the polygon for this contour (for subsequent drawing). 113 * An offset can be specified for shifting the contour positions 114 * at pixel centers (set to 0.5/0.5). 115 * 116 * @param xOffset the horizontal offset. 117 * @param yOffset the vertical offset. 118 * @return a polygon. 119 */ 120 public Path2D getPolygonPath(double xOffset, double yOffset) { 121 Path2D path = new Path2D.Float(); 122 Point[] pnts = this.getPointArray(); 123 if (pnts.length > 1){ 124 path.moveTo(pnts[0].x + xOffset, pnts[0].y + yOffset); 125 for (int i = 1; i < pnts.length; i++) { 126 path.lineTo(pnts[i].x + xOffset, pnts[i].y + yOffset); 127 } 128 path.closePath(); 129 } 130 else { // mark single pixel region "X" 131 double x = pnts[0].x; 132 double y = pnts[0].y; 133 path.moveTo(x + xOffset - 0.5, y + yOffset - 0.5); 134 path.lineTo(x + xOffset + 0.5, y + yOffset + 0.5); 135 path.moveTo(x + xOffset - 0.5, y + yOffset + 0.5); 136 path.lineTo(x + xOffset + 0.5, y + yOffset - 0.5); 137 } 138 return path; 139 } 140 141 142 // Compare method for sorting contours by length (longer contours at front) 143 @Override 144 public int compareTo(Contour c2) { 145 return c2.points.size() - this.points.size(); 146 } 147 148 @Override 149 public Iterator<Point> iterator() { 150 return points.iterator(); 151 } 152 153}