1 /** 2 * Copyright (c) 2011, The University of Southampton and the individual contributors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * * Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * * Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * * Neither the name of the University of Southampton nor the names of its 16 * contributors may be used to endorse or promote products derived from this 17 * software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 package org.openimaj.image.feature.astheticode; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 35 import org.openimaj.image.contour.Contour; 36 import org.openimaj.util.function.Function; 37 import org.openimaj.util.function.Predicate; 38 39 /** 40 * Aestheticode detection algorithm. Only supports simple codes (one parent, 41 * many children, many grandchildren with no children of their own). 42 * 43 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 44 */ 45 public class AestheticodeDetector implements Function<Contour, List<Aestheticode>>, Predicate<Contour> { 46 47 private static final int MAX_CHILDLESS_CHILDREN_DEFAULT = 0; 48 private static final int MAX_CHILDREN_DEFAULT = 5; 49 private static final int MIN_CHILDREN_DEFAULT = 5; 50 private int minChildren; 51 private int maxChildren; 52 private int maxChildlessChildren; 53 54 /** 55 * Constructs with the min and max children to the default (both are 5) and 56 * max childless children to 0 57 */ 58 public AestheticodeDetector() { 59 this.minChildren = MIN_CHILDREN_DEFAULT; 60 this.maxChildren = MAX_CHILDREN_DEFAULT; 61 this.maxChildlessChildren = MAX_CHILDLESS_CHILDREN_DEFAULT; 62 } 63 64 /** 65 * Construct with the given parameters 66 * 67 * @param minChildren 68 * the minimum number of children allowed in a root 69 * @param maxChildren 70 * the maximum number of children allowed in a root 71 * @param maxChildless 72 * the maximum number of childless children 73 */ 74 public AestheticodeDetector(int minChildren, int maxChildren, int maxChildless) { 75 this.minChildren = minChildren; 76 this.maxChildren = maxChildren; 77 this.maxChildlessChildren = maxChildless; 78 } 79 80 @Override 81 public List<Aestheticode> apply(Contour in) { 82 final List<Aestheticode> found = new ArrayList<Aestheticode>(); 83 detectCode(in, found); 84 return found; 85 } 86 87 private void detectCode(Contour root, List<Aestheticode> found) { 88 if (test(root)) { 89 found.add(new Aestheticode(root)); 90 } 91 else { 92 for (final Contour child : root.children) { 93 detectCode(child, found); 94 } 95 } 96 } 97 98 @Override 99 public boolean test(Contour in) { 100 // has at least one child 101 if (in.children.size() < minChildren || in.children.size() > maxChildren) { 102 return false; 103 } 104 105 int childlessChild = 0; 106 // all grandchildren have no children 107 for (final Contour child : in.children) { 108 if (child.children.size() == 0) 109 childlessChild++; 110 111 if (childlessChild > maxChildlessChildren) 112 return false; 113 for (final Contour grandchildren : child.children) { 114 if (grandchildren.children.size() != 0) 115 return false; 116 } 117 } 118 return true; 119 } 120 }