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 org.openimaj.citation.annotation.Reference; 033import org.openimaj.citation.annotation.ReferenceType; 034import org.openimaj.image.FImage; 035import org.openimaj.image.pixel.Pixel; 036import org.openimaj.util.function.Operation; 037import org.openimaj.util.pair.IndependentPair; 038 039/** 040 * The neighbourhood border/contour tracing algorithm described in Appendix 1 of 041 * the Suzuki contour detection algorithm 042 * 043 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 044 * 045 */ 046@Reference( 047 type = ReferenceType.Article, 048 author = { "Suzuki, S.", "Abe, K." }, 049 title = "Topological Structural Analysis of Digitized Binary Image by Border Following", 050 year = "1985", 051 journal = "Computer Vision, Graphics and Image Processing", 052 pages = { "32", "46" }, 053 month = "January", 054 number = "1", 055 volume = "30") 056public class SuzukiNeighborStrategy extends ContourFollowingStrategy { 057 @Override 058 public void contour(FImage image, Pixel start, Pixel from, final Operation<Pixel> operation) { 059 directedContour(image, start, from, new Operation<IndependentPair<Pixel, boolean[]>>() { 060 061 @Override 062 public void perform(IndependentPair<Pixel, boolean[]> object) { 063 operation.perform(object.firstObject()); 064 } 065 }); 066 } 067 068 /** 069 * Directed contour following. 070 * 071 * @param image 072 * the image 073 * @param ij 074 * the first pixel 075 * @param i2j2 076 * the second pixel 077 * @param operation 078 * the operation to perform 079 */ 080 public void 081 directedContour(FImage image, Pixel ij, Pixel i2j2, Operation<IndependentPair<Pixel, boolean[]>> operation) 082 { 083 Direction dir = Direction.fromTo(ij, i2j2); 084 Direction trace = dir.clockwise(); 085 // find i1j1 (3.1) 086 Pixel i1j1 = null; 087 while (trace != dir) { 088 final Pixel activePixel = trace.active(image, ij); 089 if (activePixel != null) { 090 i1j1 = activePixel; 091 break; 092 } 093 trace = trace.clockwise(); 094 } 095 if (i1j1 == null) 096 return; // operation never called, signals the starting pixel is 097 // alone! (3.1) 098 099 i2j2 = i1j1; 100 Pixel i3j3 = ij; // (3.2) 101 final boolean[] checked = new boolean[] { 102 /* 103 * N , NE ,E ,SE ,S ,SW ,W ,NW 104 */ 105 false, false, false, false, false, false, false, false 106 }; 107 while (true) { 108 dir = Direction.fromTo(i3j3, i2j2); 109 trace = dir.counterClockwise(); 110 Pixel i4j4 = null; 111 resetChecked(checked); 112 while (true) { 113 i4j4 = trace.active(image, i3j3); // 3.3 114 if (i4j4 != null) 115 break; 116 checked[trace.ordinal()] = true; 117 trace = trace.counterClockwise(); 118 } 119 operation.perform(IndependentPair.pair(i3j3, checked)); 120 if (i4j4.equals(ij) && i3j3.equals(i1j1)) 121 break; // 3.5 122 i2j2 = i3j3; // 3.5 123 i3j3 = i4j4; // 3.5 124 } 125 } 126 127 private void resetChecked(boolean[] checked) { 128 for (int i = 0; i < checked.length; i++) { 129 checked[i] = false; 130 } 131 } 132 133}