1 // This is core/vil/vil_border.h
2 #ifndef vil_border_h_
3 #define vil_border_h_
4 //:
5 // \file
6 // \brief Border handling for images.
7 // \author Nicolas Burrus - Paris
8
9 #include <limits>
10 #include <cassert>
11 // not used? #include <vcl_compiler.h>
12
13 //: Vil border modes.
14 enum vil_border_mode
15 {
16 //: Border pixels are constant
17 vil_border_constant = 0,
18
19 //: Border pixels take the value of the closest image point.
20 // This ensures object continuity.
21 // ex: im(im.ni()+2, -1) == im(im.ni()-1, 0)
22 vil_border_geodesic = 1,
23
24 //: Border pixels take the value of the image point which is its symmetric w.r.t. the closest image edge.
25 // ex: im(im.ni()+3, 0) = im(im.ni()-4, 0)
26 vil_border_reflect = 2,
27
28 //: The image is seen as periodic, after the right (respectively bottom) edge comes the left (respectively top).
29 // ex: im(im.ni()+2,0) == im(2,0)
30 // ex: im(im.ni()+3, im.nj()+2) == im(3,2)
31 vil_border_periodic = 3,
32 };
33
34 //: Border class. Makes pixel access outside image range transparent and configurable.
35 // Note that a border is not assigned to a specific image, but only holds border properties.
36 template <class imT>
37 class vil_border
38 {
39 public:
40 typedef typename imT::pixel_type pixel_type;
41
42 public:
43 //: Default constructor, creates a constant border.
vil_border()44 vil_border() : constant_value_() {}
45
46 //: Set the border kind.
set_kind(vil_border_mode brdr_kind)47 void set_kind(vil_border_mode brdr_kind) { border_kind_ = brdr_kind; }
48 //: Get the current border kind.
kind()49 vil_border_mode kind() const { return border_kind_; }
50
51 //: True if border values are constant.
is_constant()52 inline bool is_constant() const {
53 return border_kind_ == vil_border_constant; }
54
55 //: If border kind is vil_border_constant, returns the border value.
constant_value()56 inline const pixel_type& constant_value() const { return constant_value_; }
57
58 //: Set the border value if the border kind is vil_border_constant.
set_constant_value(const pixel_type & val)59 void set_constant_value (const pixel_type& val) { constant_value_ = val; }
60
61 //: Return read-only reference to pixel at (i,j,p) on the given image.
62 // If the pixel falls out of the image range, the border value is returned.
63 inline const pixel_type&
operator()64 operator()(const imT& im, int i, int j, int p = 0) const
65 {
66 if (im.in_range(i,j,p))
67 return im(i,j,p);
68
69 return in_border(im, i, j, p);
70 }
71
72 protected:
73 inline const pixel_type&
74 in_border(const imT& im, int i, int j, int p = 0) const
75 {
76 switch (border_kind_)
77 {
78 case vil_border_constant:
79 return constant_value_;
80 case vil_border_geodesic:
81 if (i < 0) i = 0; else if (i >= (int)im.ni()) i = im.ni()-1;
82 if (j < 0) j = 0; else if (j >= (int)im.nj()) j = im.nj()-1;
83 if (p < 0) p = 0; else if (p >= (int)im.nplanes()) p = im.nplanes()-1;
84 return im(i,j,p);
85 case vil_border_reflect:
86 if (i < 0) i = -i-1; else if (i >= (int)im.ni()) i = 2*im.ni()-i-1;
87 if (j < 0) j = -j-1; else if (j >= (int)im.nj()) j = 2*im.nj()-j-1;
88 if (p < 0) p = -p-1; else if (p >= (int)im.nplanes()) p = 2*im.nplanes()-p-1;
89 return im(i,j,p);
90 case vil_border_periodic:
91 if (i < 0) i = im.ni()-((-i)%im.ni());
92 else i = i%im.ni();
93
94 if (j < 0) j = im.nj()-((-j)%im.nj());
95 else j = j%im.nj();
96
97 if (p < 0) p = im.nplanes()-((-p)%im.nplanes());
98 else p = p%im.nplanes();
99
100 return im(i,j,p);
101 default:
102 assert(false);
103 return constant_value_; // To avoid warnings
104 };
105 }
106
107 private:
108 vil_border_mode border_kind_{vil_border_constant};
109 pixel_type constant_value_;
110 };
111
112 //: Provides a pixel accessor which is syntax-compatible with vil_image_view.
113 // It acts like a proxy to the underlying image,
114 // transparently providing border pixel values if required.
115 template <class imT>
116 class vil_border_accessor
117 {
118 public:
119 typedef typename imT::pixel_type pixel_type;
120
121 public:
122 //: Constructor.
vil_border_accessor(const imT & img,const vil_border<imT> & brdr)123 vil_border_accessor(const imT& img, const vil_border<imT>& brdr)
124 : im(img), border(brdr)
125 {}
126
127 //: Returns a const reference on the pixel (i,j,p).
128 // If the pixel falls out of the image range, a border value is returned.
129 inline const pixel_type&
operator()130 operator()(int i, int j, int p = 0) const
131 { return border(im, i, j, p); }
132
133 private:
134 const imT& im;
135 vil_border<imT> border;
136 };
137
138 //: Instantiates a border accessor, provided for convenience.
139 template <class imT>
140 vil_border_accessor<imT>
vil_border_create_accessor(const imT & im,const vil_border<imT> & border)141 vil_border_create_accessor(const imT& im, const vil_border<imT>& border)
142 {
143 return vil_border_accessor<imT>(im, border);
144 }
145
146 //: Instantiate a constant border whose type is derived from imT.
147 template <class imT>
148 inline vil_border<imT>
149 vil_border_create_constant(const imT&, typename imT::pixel_type constant_val = 0)
150 {
151 vil_border<imT> border;
152 border.set_kind(vil_border_constant);
153 border.set_constant_value(constant_val);
154 return border;
155 }
156
157 //: Instantiate a geodesic border whose type is derived from imT.
158 template <class imT>
159 inline vil_border<imT>
vil_border_create_geodesic(const imT &)160 vil_border_create_geodesic(const imT&)
161 {
162 vil_border<imT> border;
163 border.set_kind(vil_border_geodesic);
164 return border;
165 }
166
167 //: Instantiate a reflect border whose type is derived from imT.
168 template <class imT>
169 inline vil_border<imT>
vil_border_create_reflect(const imT &)170 vil_border_create_reflect(const imT&)
171 {
172 vil_border<imT> border;
173 border.set_kind(vil_border_reflect);
174 return border;
175 }
176
177 //: Instantiate a reflect border whose type is derived from imT.
178 template <class imT>
179 inline vil_border<imT>
vil_border_create_periodic(const imT &)180 vil_border_create_periodic(const imT&)
181 {
182 vil_border<imT> border;
183 border.set_kind(vil_border_periodic);
184 return border;
185 }
186
187 #endif // vil_border_h_
188