1 /************************************************************************/
2 /*                                                                      */
3 /*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
4 /*                                                                      */
5 /*    This file is part of the VIGRA computer vision library.           */
6 /*    The VIGRA Website is                                              */
7 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
8 /*    Please direct questions, bug reports, and contributions to        */
9 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
10 /*        vigra@informatik.uni-hamburg.de                               */
11 /*                                                                      */
12 /*    Permission is hereby granted, free of charge, to any person       */
13 /*    obtaining a copy of this software and associated documentation    */
14 /*    files (the "Software"), to deal in the Software without           */
15 /*    restriction, including without limitation the rights to use,      */
16 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
17 /*    sell copies of the Software, and to permit persons to whom the    */
18 /*    Software is furnished to do so, subject to the following          */
19 /*    conditions:                                                       */
20 /*                                                                      */
21 /*    The above copyright notice and this permission notice shall be    */
22 /*    included in all copies or substantial portions of the             */
23 /*    Software.                                                         */
24 /*                                                                      */
25 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
26 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
27 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
28 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
29 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
30 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
31 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
32 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
33 /*                                                                      */
34 /************************************************************************/
35 
36 #ifndef VIGRA_VISIT_BORDER_HXX
37 #define VIGRA_VISIT_BORDER_HXX
38 
39 #include "multi_array.hxx"
40 
41 namespace vigra
42 {
43 
44 namespace visit_border_detail
45 {
46 
47 template <unsigned int K>
48 struct visit_border_impl
49 {
50     template <unsigned int N, class Data, class S1,
51                               class Label, class S2,
52               class Shape, class Visitor>
execvigra::visit_border_detail::visit_border_impl53     static void exec(const MultiArrayView<N, Data, S1>& u_data, MultiArrayView<N, Label, S2> u_labels,
54                      const MultiArrayView<N, Data, S1>& v_data, MultiArrayView<N, Label, S2> v_labels,
55                      const Shape& block_difference, NeighborhoodType neighborhood, Visitor visitor)
56     {
57         static const unsigned int D = K - 1;
58         typedef visit_border_impl<D> next;
59 
60         if(block_difference[D] == -1)
61         {
62             MultiArrayIndex last = v_data.shape(D) - 1;
63             next::exec(u_data.bindAt(D, 0), u_labels.bindAt(D, 0),
64                        v_data.bindAt(D, last), v_labels.bindAt(D, last),
65                        block_difference, neighborhood, visitor);
66         }
67         else if(block_difference[D] == 1)
68         {
69             MultiArrayIndex last = u_data.shape(D) - 1;
70             next::exec(u_data.bindAt(D, last), u_labels.bindAt(D, last),
71                        v_data.bindAt(D, 0), v_labels.bindAt(D, 0),
72                        block_difference, neighborhood, visitor);
73         }
74         else if(block_difference[D] == 0)
75         {
76             next::exec(u_data, u_labels, v_data, v_labels, block_difference, neighborhood, visitor);
77         }
78         else
79         {
80             vigra_precondition(false, "invalid block difference");
81         }
82     }
83 };
84 
85 template <>
86 struct visit_border_impl<0>
87 {
88     template <class Data, class S1,
89               class Label, class S2,
90               class Shape, class Visitor>
execvigra::visit_border_detail::visit_border_impl91     static void exec(const MultiArrayView<0, Data, S1>& u_data, MultiArrayView<0, Label, S2> u_labels,
92                      const MultiArrayView<0, Data, S1>& v_data, MultiArrayView<0, Label, S2> v_labels,
93                      const Shape& block_difference, NeighborhoodType, Visitor visitor)
94     {
95         visitor(u_data(0), u_labels(0), v_data(0), v_labels(0), block_difference);
96     }
97     template <unsigned int N, class Data, class S1,
98                               class Label, class S2,
99               class Shape, class Visitor>
execvigra::visit_border_detail::visit_border_impl100     static void exec(const MultiArrayView<N, Data, S1>& u_data, MultiArrayView<N, Label, S2> u_labels,
101                      const MultiArrayView<N, Data, S1>& v_data, MultiArrayView<N, Label, S2> v_labels,
102                      const Shape& block_difference, NeighborhoodType neighborhood, Visitor visitor)
103     {
104         if(neighborhood == DirectNeighborhood)
105         {
106             typedef typename MultiArrayView<N, Data, S1>::const_iterator DataIterator;
107             typedef typename MultiArrayView<N, Label, S2>::iterator LabelsIterator;
108 
109             DataIterator u_data_it = u_data.begin();
110             LabelsIterator u_labels_it = u_labels.begin();
111 
112             DataIterator v_data_it = v_data.begin();
113             LabelsIterator v_labels_it = v_labels.begin();
114 
115             for( ; u_data_it != u_data.end(); ++u_data_it, ++u_labels_it, ++v_data_it, ++v_labels_it)
116             {
117                 visitor(*u_data_it, *u_labels_it, *v_data_it, *v_labels_it, block_difference);
118             }
119         }
120         else if(neighborhood == IndirectNeighborhood)
121         {
122             typedef GridGraph<N, undirected_tag> Graph;
123             typedef typename Graph::NodeIt GraphScanner;
124             typedef typename Graph::OutArcIt NeighborIterator;
125 
126             static const int global_dim_number = Shape::static_size;
127             TinyVector<unsigned int, N> dim_mapping; // mapping of every local dimension to their actual global dimension indices
128             int local_dims_pos = 0;
129             int global_dims_pos = 0;
130             for( ; global_dims_pos != global_dim_number; ++global_dims_pos)
131             {
132                 if(block_difference[global_dims_pos] == 0)
133                 {
134                     vigra_assert(local_dims_pos != N, "");
135                     dim_mapping[local_dims_pos] = global_dims_pos;
136                     ++local_dims_pos;
137                 }
138             }
139             vigra_assert(local_dims_pos == N, "");
140 
141             Graph graph(u_data.shape(), neighborhood);
142             Shape pixel_difference = block_difference;
143             for(GraphScanner node(graph); node != lemon::INVALID; ++node)
144             {
145                 // compare neighbors that have have equal coordinates in all unbound dimensions
146                 // their pixel-level difference is exactly block_difference
147                 visitor(u_data[*node], u_labels[*node], v_data[*node], v_labels[*node], block_difference);
148                 // now let unbound dimensions vary
149                 for(NeighborIterator arc(graph, *node); arc != lemon::INVALID; ++arc)
150                 {
151                     for(int i = 0; i != N; ++i)
152                         pixel_difference[dim_mapping[i]] = graph.target(*arc)[i] - (*node)[i];
153                     visitor(u_data[*node], u_labels[*node], v_data[graph.target(*arc)], v_labels[graph.target(*arc)], pixel_difference);
154                 }
155             }
156         }
157     }
158 };
159 
160 } // namespace visit_border_detail
161 
162 template <unsigned int N, class Data, class S1,
163                           class Label, class S2,
164           class Shape, class Visitor>
165 inline void
visitBorder(const MultiArrayView<N,Data,S1> & u_data,MultiArrayView<N,Label,S2> u_labels,const MultiArrayView<N,Data,S1> & v_data,MultiArrayView<N,Label,S2> v_labels,const Shape & difference,NeighborhoodType neighborhood,Visitor visitor)166 visitBorder(const MultiArrayView<N, Data, S1>& u_data, MultiArrayView<N, Label, S2> u_labels,
167             const MultiArrayView<N, Data, S1>& v_data, MultiArrayView<N, Label, S2> v_labels,
168             const Shape& difference, NeighborhoodType neighborhood, Visitor visitor)
169 {
170     vigra_precondition(u_data.shape() == u_labels.shape() && v_data.shape() == v_labels.shape(),
171                        "differing block shapes");
172     visit_border_detail::visit_border_impl<N>::exec(u_data, u_labels,
173                                                     v_data, v_labels,
174                                                     difference, neighborhood, visitor);
175 }
176 
177 } // namespace vigra
178 
179 #endif // VIGRA_VISIT_BORDER_HXX
180