29 #ifndef __FAST_BILATERAL__
30 #define __FAST_BILATERAL__
32 #include <opencv2/opencv.hpp>
37 double sigmaColor,
double sigmaSpace);
39 void bilateralFilterImpl(cv::Mat1d src, cv::Mat1d dst,
40 double sigmaColor,
double sigmaSpace);
43 template<
typename T,
typename T_,
typename T__>
45 T clamp(
const T_ min,
const T__ max,
const T x)
48 ( x <
static_cast<T
>(min) ) ?
static_cast<T
>(min) :
49 ( x <
static_cast<T
>(max) ) ?
static_cast<T
>(x) :
56 trilinear_interpolation(
const cv::Mat mat,
61 const size_t height = mat.size[0];
62 const size_t width = mat.size[1];
63 const size_t depth = mat.size[2];
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;
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);
93 double sigmaColor,
double sigmaSpace)
95 cv::Mat src = _src.getMat();
97 CV_Assert(src.channels() == 1);
100 if ( src.depth() != CV_64FC1 ) {
101 src = cv::Mat(_src.size(), CV_64FC1);
102 _src.getMat().convertTo(src, CV_64FC1);
105 cv::Mat dst_tmp = cv::Mat(_src.size(), CV_64FC1);
106 bilateralFilterImpl(src, dst_tmp, sigmaColor, sigmaSpace);
108 _dst.create(dst_tmp.size(), _src.type());
109 dst_tmp.convertTo(_dst.getMat(), _src.type());
113 void bilateralFilterImpl(cv::Mat1d src, cv::Mat1d dst,
114 double sigma_color,
double sigma_space)
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);
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;
126 int data_size[] = {small_height, small_width, small_depth};
127 cv::Mat data(3, data_size, CV_64FC2);
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;
138 cv::Vec2d v = data.at<cv::Vec2d>(small_y, small_x, small_z);
139 v[0] += src.at<
double>(y,x);
141 data.at<cv::Vec2d>(small_y, small_x, small_z) = v;
146 cv::Mat buffer(3, data_size, CV_64FC2);
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));
153 for (
int dim = 0; dim < 3; ++dim ) {
154 const int off = offset[dim];
155 for (
int ittr = 0; ittr < 2; ++ittr ) {
156 cv::swap(data, buffer);
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;
174 for ( cv::MatIterator_<cv::Vec2d> d = data.begin<cv::Vec2d>(); d != data.end<cv::Vec2d>(); ++d )
176 (*d)[0] /= (*d)[1] != 0 ? (*d)[1] : 1;
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];
This sofrware and program is distributed under MIT License.
void bilateralFilter(cv::InputArray src, cv::OutputArray dst, double sigmaColor, double sigmaSpace)
Implementation.