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.analysis.watershed;
31
32 import java.util.HashMap;
33 import java.util.Map;
34
35 import org.apache.log4j.Logger;
36 import org.openimaj.image.analysis.watershed.event.ComponentStackMergeListener;
37 import org.openimaj.util.tree.TreeNode;
38 import org.openimaj.util.tree.TreeNodeImpl;
39
40 /**
41 * A listener that listens to the watershed algorithm progress and creates a
42 * region tree as the processing takes place.
43 *
44 * @author David Dupplaw (dpd@ecs.soton.ac.uk)
45 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
46 *
47 */
48 public class MergeTreeBuilder implements ComponentStackMergeListener
49 {
50 Logger logger = Logger.getLogger(MergeTreeBuilder.class);
51
52 /** This is the tree we build */
53 private TreeNode<Component> tree = null;
54
55 /**
56 * Because we're creating components to store the history, the components
57 * that are being processed by the algorithm are not the same as those in
58 * our tree, so we must provide a map so that we can join up the tree
59 * afterwards.
60 */
61 private Map<Component, TreeNode<Component>> map = null;
62
63 /**
64 * Default constructor
65 */
66 public MergeTreeBuilder()
67 {
68 map = new HashMap<Component, TreeNode<Component>>();
69 }
70
71 /**
72 * {@inheritDoc}
73 *
74 * @see org.openimaj.image.analysis.watershed.event.ComponentStackMergeListener#componentsMerged(org.openimaj.image.analysis.watershed.Component,
75 * org.openimaj.image.analysis.watershed.Component)
76 */
77 @Override
78 public void componentsMerged(Component c1, Component c2)
79 {
80 // logger.debug( "Map: "+map );
81 logger.debug("Component c1: " + c1);
82 logger.debug("Component c2: " + c2);
83
84 // Create a tree node for the component if it doesn't
85 // exist already
86 TreeNode<Component> c1xtn = map.get(c1);
87 if (c1xtn == null)
88 {
89 logger.debug("c1 not found");
90 c1xtn = new TreeNodeImpl<Component>();
91 final Component c1x = c1.clone();
92 c1xtn.setValue(c1x);
93 map.put(c1, c1xtn);
94 }
95
96 // Add all the pixels from c2 into our copy of c1
97 c1xtn.getValue().merge(c2);
98
99 // Create a tree node for the second component
100 // if it doesn't exist already
101 TreeNode<Component> c2xtn = map.get(c2);
102 if (c2xtn == null)
103 {
104 logger.debug("c2 not found");
105 c2xtn = new TreeNodeImpl<Component>();
106 final Component c2x = c2.clone();
107 c2xtn.setValue(c2x);
108 map.put(c2, c2xtn);
109 }
110
111 // logger.debug("Linking " + c1xtn + " and " + c2xtn);
112
113 // Link the tree nodes
114 c1xtn.addChild(c2xtn);
115 this.tree = c1xtn;
116 }
117
118 /**
119 * {@inheritDoc}
120 *
121 * @see org.openimaj.image.analysis.watershed.event.ComponentStackMergeListener#componentPromoted(org.openimaj.image.analysis.watershed.Component)
122 */
123 @Override
124 public void componentPromoted(Component c1)
125 {
126 final TreeNode<Component> c1xtn_old = map.get(c1);
127
128 final Component c1x = c1.clone();
129
130 final TreeNode<Component> c1xtn = new TreeNodeImpl<Component>();
131 c1xtn.setValue(c1x);
132
133 map.put(c1, c1xtn);
134
135 if (c1xtn_old != null)
136 c1xtn.addChild(c1xtn_old);
137 }
138
139 /**
140 * Return the tree that has been built.
141 *
142 * @return the tree
143 */
144 public TreeNode<Component> getTree()
145 {
146 return tree;
147 }
148 }