stereo-vision
All Data Structures Namespaces Functions Modules Pages
fastBilateral.hpp
1 
29 #ifndef __FAST_BILATERAL__
30 #define __FAST_BILATERAL__
31 
32 #include <opencv2/opencv.hpp>
33 
34 namespace cv_extend {
35 
36 void bilateralFilter(cv::InputArray src, cv::OutputArray dst,
37  double sigmaColor, double sigmaSpace);
38 
39 void bilateralFilterImpl(cv::Mat1d src, cv::Mat1d dst,
40  double sigmaColor, double sigmaSpace);
41 
42 
43 template<typename T, typename T_, typename T__>
44 inline
45 T clamp(const T_ min, const T__ max, const T x)
46 {
47  return
48  ( x < static_cast<T>(min) ) ? static_cast<T>(min) :
49  ( x < static_cast<T>(max) ) ? static_cast<T>(x) :
50  static_cast<T>(max);
51 }
52 
53 template<typename T>
54 inline
55 T
56 trilinear_interpolation( const cv::Mat mat,
57  const double y,
58  const double x,
59  const double z)
60 {
61  const size_t height = mat.size[0];
62  const size_t width = mat.size[1];
63  const size_t depth = mat.size[2];
64 
65  const size_t y_index = clamp(0, height-1, static_cast<size_t>(y));
66  const size_t yy_index = clamp(0, height-1, y_index+1);
67  const size_t x_index = clamp(0, width-1, static_cast<size_t>(x));
68  const size_t xx_index = clamp(0, width-1, x_index+1);
69  const size_t z_index = clamp(0, depth-1, static_cast<size_t>(z));
70  const size_t zz_index = clamp(0, depth-1, z_index+1);
71  const double y_alpha = y - y_index;
72  const double x_alpha = x - x_index;
73  const double z_alpha = z - z_index;
74 
75  return
76  (1.0-y_alpha) * (1.0-x_alpha) * (1.0-z_alpha) * mat.at<T>(y_index, x_index, z_index) +
77  (1.0-y_alpha) * x_alpha * (1.0-z_alpha) * mat.at<T>(y_index, xx_index, z_index) +
78  y_alpha * (1.0-x_alpha) * (1.0-z_alpha) * mat.at<T>(yy_index, x_index, z_index) +
79  y_alpha * x_alpha * (1.0-z_alpha) * mat.at<T>(yy_index, xx_index, z_index) +
80  (1.0-y_alpha) * (1.0-x_alpha) * z_alpha * mat.at<T>(y_index, x_index, zz_index) +
81  (1.0-y_alpha) * x_alpha * z_alpha * mat.at<T>(y_index, xx_index, zz_index) +
82  y_alpha * (1.0-x_alpha) * z_alpha * mat.at<T>(yy_index, x_index, zz_index) +
83  y_alpha * x_alpha * z_alpha * mat.at<T>(yy_index, xx_index, zz_index);
84 
85 }
86 
87 
92 void bilateralFilter(cv::InputArray _src, cv::OutputArray _dst,
93  double sigmaColor, double sigmaSpace)
94 {
95  cv::Mat src = _src.getMat();
96 
97  CV_Assert(src.channels() == 1);
98 
99  // bilateralFilterImpl runs with double depth, single channel
100  if ( src.depth() != CV_64FC1 ) {
101  src = cv::Mat(_src.size(), CV_64FC1);
102  _src.getMat().convertTo(src, CV_64FC1);
103  }
104 
105  cv::Mat dst_tmp = cv::Mat(_src.size(), CV_64FC1);
106  bilateralFilterImpl(src, dst_tmp, sigmaColor, sigmaSpace);
107 
108  _dst.create(dst_tmp.size(), _src.type());
109  dst_tmp.convertTo(_dst.getMat(), _src.type());
110 
111 }
112 
113 void bilateralFilterImpl(cv::Mat1d src, cv::Mat1d dst,
114  double sigma_color, double sigma_space)
115 {
116  using namespace cv;
117  const size_t height = src.rows, width = src.cols;
118  const size_t padding_xy = 2, padding_z = 2;
119  double src_min, src_max;
120  cv::minMaxLoc(src, &src_min, &src_max);
121 
122  const size_t small_height = static_cast<size_t>((height-1)/sigma_space) + 1 + 2 * padding_xy;
123  const size_t small_width = static_cast<size_t>((width-1)/sigma_space) + 1 + 2 * padding_xy;
124  const size_t small_depth = static_cast<size_t>((src_max-src_min)/sigma_color) + 1 + 2 * padding_xy;
125 
126  int data_size[] = {small_height, small_width, small_depth};
127  cv::Mat data(3, data_size, CV_64FC2);
128  data.setTo(0);
129 
130  // down sample
131  for ( int y = 0; y < height; ++y ) {
132  for ( int x = 0; x < width; ++x) {
133  const size_t small_x = static_cast<size_t>( x/sigma_space + 0.5) + padding_xy;
134  const size_t small_y = static_cast<size_t>( y/sigma_space + 0.5) + padding_xy;
135  const double z = src.at<double>(y,x) - src_min;
136  const size_t small_z = static_cast<size_t>( z/sigma_color + 0.5 ) + padding_z;
137 
138  cv::Vec2d v = data.at<cv::Vec2d>(small_y, small_x, small_z);
139  v[0] += src.at<double>(y,x);
140  v[1] += 1.0;
141  data.at<cv::Vec2d>(small_y, small_x, small_z) = v;
142  }
143  }
144 
145  // convolution
146  cv::Mat buffer(3, data_size, CV_64FC2);
147  buffer.setTo(0);
148  int offset[3];
149  offset[0] = &(data.at<cv::Vec2d>(1,0,0)) - &(data.at<cv::Vec2d>(0,0,0));
150  offset[1] = &(data.at<cv::Vec2d>(0,1,0)) - &(data.at<cv::Vec2d>(0,0,0));
151  offset[2] = &(data.at<cv::Vec2d>(0,0,1)) - &(data.at<cv::Vec2d>(0,0,0));
152 
153  for ( int dim = 0; dim < 3; ++dim ) { // dim = 3 stands for x, y, and depth
154  const int off = offset[dim];
155  for ( int ittr = 0; ittr < 2; ++ittr ) {
156  cv::swap(data, buffer);
157 
158  for ( int y = 1; y < small_height-1; ++y ) {
159  for ( int x = 1; x < small_width-1; ++x ) {
160  cv::Vec2d *d_ptr = &(data.at<cv::Vec2d>(y,x,1));
161  cv::Vec2d *b_ptr = &(buffer.at<cv::Vec2d>(y,x,1));
162  for ( int z = 1; z < small_depth-1; ++z, ++d_ptr, ++b_ptr ) {
163  cv::Vec2d b_prev = *(b_ptr-off), b_curr = *b_ptr, b_next = *(b_ptr+off);
164  *d_ptr = (b_prev + b_next + 2.0 * b_curr) / 4.0;
165  } // z
166  } // x
167  } // y
168 
169  } // ittr
170  } // dim
171 
172  // upsample
173 
174  for ( cv::MatIterator_<cv::Vec2d> d = data.begin<cv::Vec2d>(); d != data.end<cv::Vec2d>(); ++d )
175  {
176  (*d)[0] /= (*d)[1] != 0 ? (*d)[1] : 1;
177  }
178 
179  for ( int y = 0; y < height; ++y ) {
180  for ( int x = 0; x < width; ++x ) {
181  const double z = src.at<double>(y,x) - src_min;
182  const double px = static_cast<double>(x) / sigma_space + padding_xy;
183  const double py = static_cast<double>(y) / sigma_space + padding_xy;
184  const double pz = static_cast<double>(z) / sigma_color + padding_z;
185  dst.at<double>(y,x) = trilinear_interpolation<cv::Vec2d>(data, py, px, pz)[0];
186  }
187  }
188 
189 }
190 
191 } // end of namespace cv_extend
192 #endif
This sofrware and program is distributed under MIT License.
void bilateralFilter(cv::InputArray src, cv::OutputArray dst, double sigmaColor, double sigmaSpace)
Implementation.