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 }