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