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