1 // Copyright (C) 2014 Carnë Draug <carandraug@octave.org>
2 //
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License as
5 // published by the Free Software Foundation; either version 3 of the
6 // License, or (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful, but
9 // WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, see
15 // <http://www.gnu.org/licenses/>.
16
17 #ifndef OCTAVE_IMAGE_CONNDEF
18 #define OCTAVE_IMAGE_CONNDEF
19
20 #include <string>
21 #include <stdexcept>
22 #include <functional>
23
24 #include <octave/Array.h>
25 #include <octave/idx-vector.h>
26 #include <octave/dim-vector.h>
27 #include <octave/boolNDArray.h>
28 #include <octave/lo-ieee.h> // octave_Inf
29
30 #include <octave/ov.h>
31
32 namespace octave
33 {
34 namespace image
35 {
36 class connectivity
37 {
38 public:
39 connectivity () = default;
40
41 //! Will throw if val is bad
42 explicit connectivity (const boolNDArray& mask_arg);
43 explicit connectivity (const unsigned int conn);
44 connectivity (const octave_idx_type& ndims, const std::string& type);
45
46 boolNDArray mask;
47
48 // For a matrix of size `size', what are the offsets for all of its
49 // connected elements (will have negative and positive values).
50 Array<octave_idx_type> neighbourhood (const dim_vector& size) const;
51 Array<octave_idx_type> deleted_neighbourhood (const dim_vector& size) const;
52 Array<octave_idx_type> positive_neighbourhood (const dim_vector& size) const;
53 Array<octave_idx_type> negative_neighbourhood (const dim_vector& size) const;
54
55 template<class T, class P>
56 T create_padded (const T& image, const P& val) const;
57
58 template<class T>
59 void unpad (T& image) const;
60
61 //! Return a logical mask of elements that are part of the padding.
62 static boolNDArray padding_mask (const dim_vector& size,
63 const dim_vector& padded_size);
64
65 //! Set the padding elements to a specific value.
66 template<class T, class P>
67 static void set_padding (const dim_vector& size,
68 const dim_vector& padded_size,
69 T& im, const P& val);
70
71 template<class P>
72 static P min_value (void);
73
74 static Array<octave_idx_type> padding_lengths (const dim_vector& size,
75 const dim_vector& padded_size);
76
77 private:
78 //! Like Array::ndims() but will return 1 dimension for ColumnVector
79 static octave_idx_type ndims (const dim_vector& d);
80 template<class T>
81 static octave_idx_type ndims (const Array<T>& a);
82 };
83
84 class invalid_connectivity : public std::invalid_argument
85 {
86 public:
invalid_connectivity(const std::string & what_arg)87 invalid_connectivity (const std::string& what_arg)
88 : std::invalid_argument (what_arg) { }
89 };
90
91 connectivity conndef (const octave_value& val);
92 }
93 }
94
95 // Templated methods
96
97 template<class T, class P>
98 T
create_padded(const T & image,const P & val)99 octave::image::connectivity::create_padded (const T& image, const P& val) const
100 {
101 const octave_idx_type pad_ndims = std::min (mask.ndims (), image.ndims ());
102
103 Array<octave_idx_type> idx (dim_vector (image.ndims (), 1), 0);
104 dim_vector padded_size = image.dims ();
105 for (octave_idx_type i = 0; i < pad_ndims; i++)
106 {
107 padded_size(i) += 2;
108 idx(i) = 1;
109 }
110
111 T padded (padded_size, val);
112
113 // padded(2:end-1, 2:end-1, ..., 2:end-1) = BW
114 padded.insert (image, idx);
115 return padded;
116 }
117
118 template<class T>
119 void
unpad(T & image)120 octave::image::connectivity::unpad (T& image) const
121 {
122 const octave_idx_type pad_ndims = std::min (mask.ndims (), image.ndims ());
123 const dim_vector padded_size = image.dims ();
124
125 Array<idx_vector> inner_slice (dim_vector (image.ndims (), 1));
126 for (octave_idx_type i = 0; i < pad_ndims ; i++)
127 inner_slice(i) = idx_vector (1, padded_size(i) - 1);
128 for (octave_idx_type i = pad_ndims; i < image.ndims (); i++)
129 inner_slice(i) = idx_vector (0, padded_size(i));
130
131 image = image.index (inner_slice);
132 return;
133 }
134
135 template<class P>
136 P
min_value(void)137 octave::image::connectivity::min_value (void)
138 {
139 if (typeid (P) == typeid (bool))
140 return false;
141 else
142 return P(-octave_Inf);
143 }
144
145 template<class T, class P>
146 void
set_padding(const dim_vector & size,const dim_vector & padded_size,T & im,const P & val)147 octave::image::connectivity::set_padding (const dim_vector& size,
148 const dim_vector& padded_size,
149 T& im, const P& val)
150 {
151 P* im_v = im.fortran_vec ();
152
153 const Array<octave_idx_type> lengths = padding_lengths (size, padded_size);
154 const octave_idx_type* lengths_v = lengths.fortran_vec ();
155
156 const octave_idx_type* strides_v = size.to_jit ();
157 const octave_idx_type row_stride = strides_v[0];
158
159 std::function<void(const octave_idx_type)> fill;
160 fill = [&] (const octave_idx_type dim) -> void
161 {
162 for (octave_idx_type i = 0; i < lengths_v[dim]; i++, im_v++)
163 *im_v = val;
164
165 if (dim == 0)
166 im_v += row_stride;
167 else
168 for (octave_idx_type i = 0; i < strides_v[dim]; i++)
169 fill (dim -1);
170
171 for (octave_idx_type i = 0; i < lengths_v[dim]; i++, im_v++)
172 *im_v = val;
173 };
174 fill (im.ndims () -1);
175 }
176
177 #endif
178