1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
5// By downloading, copying, installing or using the software you agree to this license.
6// If you do not agree to this license, do not download, install,
7// copy or use the software.
8//
9//
10// License Agreement
11// For Open Source Computer Vision Library
12//
13// Copyright (C) 2000-2008, 2018, Intel Corporation, all rights reserved.
14// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15// Copyright (C) 2014-2015, Itseez Inc., all rights reserved.
16// Third party copyrights are property of their respective owners.
17//
18// Redistribution and use in source and binary forms, with or without modification,
19// are permitted provided that the following conditions are met:
20//
21// * Redistribution's of source code must retain the above copyright notice,
22// this list of conditions and the following disclaimer.
23//
24// * Redistribution's in binary form must reproduce the above copyright notice,
25// this list of conditions and the following disclaimer in the documentation
26// and/or other materials provided with the distribution.
27//
28// * The name of the copyright holders may not be used to endorse or promote products
29// derived from this software without specific prior written permission.
30//
31// This software is provided by the copyright holders and contributors "as is" and
32// any express or implied warranties, including, but not limited to, the implied
33// warranties of merchantability and fitness for a particular purpose are disclaimed.
34// In no event shall the Intel Corporation or contributors be liable for any direct,
35// indirect, incidental, special, exemplary, or consequential damages
36// (including, but not limited to, procurement of substitute goods or services;
37// loss of use, data, or profits; or business interruption) however caused
38// and on any theory of liability, whether in contract, strict liability,
39// or tort (including negligence or otherwise) arising in any way out of
40// the use of this software, even if advised of the possibility of such damage.
41//
42//M*/
43
44#include "precomp.hpp"
45
46#include <vector>
47
48#include "opencv2/core/hal/intrin.hpp"
49#include "opencl_kernels_imgproc.hpp"
50
51#include "bilateral_filter.simd.hpp"
52#include "bilateral_filter.simd_declarations.hpp" // defines CV_CPU_DISPATCH_MODES_ALL=AVX2,...,BASELINE based on CMakeLists.txt content
53
54/****************************************************************************************\
55 Bilateral Filtering
56\****************************************************************************************/
57
58namespace cv {
59
60#ifdef HAVE_OPENCL
61
62static bool ocl_bilateralFilter_8u(InputArray _src, OutputArray _dst, int d,
63 double sigma_color, double sigma_space,
64 int borderType)
65{
66 CV_INSTRUMENT_REGION();
67#ifdef __ANDROID__
68 if (ocl::Device::getDefault().isNVidia())
69 return false;
70#endif
71
72 int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
73 int i, j, maxk, radius;
74
75 if (depth != CV_8U || cn > 4)
76 return false;
77
78 if (sigma_color <= 0)
79 sigma_color = 1;
80 if (sigma_space <= 0)
81 sigma_space = 1;
82
83 double gauss_color_coeff = -0.5 / (sigma_color * sigma_color);
84 double gauss_space_coeff = -0.5 / (sigma_space * sigma_space);
85
86 if ( d <= 0 )
87 radius = cvRound(value: sigma_space * 1.5);
88 else
89 radius = d / 2;
90 radius = MAX(radius, 1);
91 d = radius * 2 + 1;
92
93 UMat src = _src.getUMat(), dst = _dst.getUMat(), temp;
94 if (src.u == dst.u)
95 return false;
96
97 copyMakeBorder(src, dst: temp, top: radius, bottom: radius, left: radius, right: radius, borderType);
98 std::vector<float> _space_weight(d * d);
99 std::vector<int> _space_ofs(d * d);
100 float * const space_weight = &_space_weight[0];
101 int * const space_ofs = &_space_ofs[0];
102
103 // initialize space-related bilateral filter coefficients
104 for( i = -radius, maxk = 0; i <= radius; i++ )
105 for( j = -radius; j <= radius; j++ )
106 {
107 double r = std::sqrt(x: (double)i * i + (double)j * j);
108 if ( r > radius )
109 continue;
110 space_weight[maxk] = (float)std::exp(x: r * r * gauss_space_coeff);
111 space_ofs[maxk++] = (int)(i * temp.step + j * cn);
112 }
113
114 char cvt[3][50];
115 String cnstr = cn > 1 ? format(fmt: "%d", cn) : "";
116 String kernelName("bilateral");
117 size_t sizeDiv = 1;
118 if ((ocl::Device::getDefault().isIntel()) &&
119 (ocl::Device::getDefault().type() == ocl::Device::TYPE_GPU))
120 {
121 //Intel GPU
122 if (dst.cols % 4 == 0 && cn == 1) // For single channel x4 sized images.
123 {
124 kernelName = "bilateral_float4";
125 sizeDiv = 4;
126 }
127 }
128 ocl::Kernel k(kernelName.c_str(), ocl::imgproc::bilateral_oclsrc,
129 format("-D radius=%d -D maxk=%d -D cn=%d -D int_t=%s -D uint_t=uint%s -D convert_int_t=%s"
130 " -D uchar_t=%s -D float_t=%s -D convert_float_t=%s -D convert_uchar_t=%s -D gauss_color_coeff=(float)%f",
131 radius, maxk, cn, ocl::typeToStr(CV_32SC(cn)), cnstr.c_str(),
132 ocl::convertTypeStr(CV_8U, CV_32S, cn, cvt[0], sizeof(cvt[0])),
133 ocl::typeToStr(type), ocl::typeToStr(CV_32FC(cn)),
134 ocl::convertTypeStr(CV_32S, CV_32F, cn, cvt[1], sizeof(cvt[1])),
135 ocl::convertTypeStr(CV_32F, CV_8U, cn, cvt[2], sizeof(cvt[2])), gauss_color_coeff));
136 if (k.empty())
137 return false;
138
139 Mat mspace_weight(1, d * d, CV_32FC1, space_weight);
140 Mat mspace_ofs(1, d * d, CV_32SC1, space_ofs);
141 UMat ucolor_weight, uspace_weight, uspace_ofs;
142
143 mspace_weight.copyTo(m: uspace_weight);
144 mspace_ofs.copyTo(m: uspace_ofs);
145
146 k.args(kernel_args: ocl::KernelArg::ReadOnlyNoSize(m: temp), kernel_args: ocl::KernelArg::WriteOnly(m: dst),
147 kernel_args: ocl::KernelArg::PtrReadOnly(m: uspace_weight),
148 kernel_args: ocl::KernelArg::PtrReadOnly(m: uspace_ofs));
149
150 size_t globalsize[2] = { (size_t)dst.cols / sizeDiv, (size_t)dst.rows };
151 return k.run(dims: 2, globalsize, NULL, sync: false);
152}
153#endif
154
155
156static void
157bilateralFilter_8u( const Mat& src, Mat& dst, int d,
158 double sigma_color, double sigma_space,
159 int borderType )
160{
161 CV_INSTRUMENT_REGION();
162
163 int cn = src.channels();
164 int i, j, maxk, radius;
165
166 CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) && src.data != dst.data );
167
168 if( sigma_color <= 0 )
169 sigma_color = 1;
170 if( sigma_space <= 0 )
171 sigma_space = 1;
172
173 double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
174 double gauss_space_coeff = -0.5/(sigma_space*sigma_space);
175
176 if( d <= 0 )
177 radius = cvRound(value: sigma_space*1.5);
178 else
179 radius = d/2;
180 radius = MAX(radius, 1);
181 d = radius*2 + 1;
182
183 Mat temp;
184 copyMakeBorder( src, dst: temp, top: radius, bottom: radius, left: radius, right: radius, borderType );
185
186 std::vector<float> _color_weight(cn*256);
187 std::vector<float> _space_weight(d*d);
188 std::vector<int> _space_ofs(d*d);
189 float* color_weight = &_color_weight[0];
190 float* space_weight = &_space_weight[0];
191 int* space_ofs = &_space_ofs[0];
192
193 // initialize color-related bilateral filter coefficients
194
195 for( i = 0; i < 256*cn; i++ )
196 color_weight[i] = (float)std::exp(x: i*i*gauss_color_coeff);
197
198 // initialize space-related bilateral filter coefficients
199 for( i = -radius, maxk = 0; i <= radius; i++ )
200 {
201 j = -radius;
202
203 for( ; j <= radius; j++ )
204 {
205 double r = std::sqrt(x: (double)i*i + (double)j*j);
206 if( r > radius )
207 continue;
208 space_weight[maxk] = (float)std::exp(x: r*r*gauss_space_coeff);
209 space_ofs[maxk++] = (int)(i*temp.step + j*cn);
210 }
211 }
212
213 CV_CPU_DISPATCH(bilateralFilterInvoker_8u, (dst, temp, radius, maxk, space_ofs, space_weight, color_weight),
214 CV_CPU_DISPATCH_MODES_ALL);
215}
216
217
218static void
219bilateralFilter_32f( const Mat& src, Mat& dst, int d,
220 double sigma_color, double sigma_space,
221 int borderType )
222{
223 CV_INSTRUMENT_REGION();
224
225 int cn = src.channels();
226 int i, j, maxk, radius;
227 double minValSrc=-1, maxValSrc=1;
228 const int kExpNumBinsPerChannel = 1 << 12;
229 int kExpNumBins = 0;
230 float lastExpVal = 1.f;
231 float len, scale_index;
232
233 CV_Assert( (src.type() == CV_32FC1 || src.type() == CV_32FC3) && src.data != dst.data );
234
235 if( sigma_color <= 0 )
236 sigma_color = 1;
237 if( sigma_space <= 0 )
238 sigma_space = 1;
239
240 double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
241 double gauss_space_coeff = -0.5/(sigma_space*sigma_space);
242
243 if( d <= 0 )
244 radius = cvRound(value: sigma_space*1.5);
245 else
246 radius = d/2;
247 radius = MAX(radius, 1);
248 d = radius*2 + 1;
249 // compute the min/max range for the input image (even if multichannel)
250
251 minMaxLoc( src: src.reshape(cn: 1), minVal: &minValSrc, maxVal: &maxValSrc );
252 if(std::abs(x: minValSrc - maxValSrc) < FLT_EPSILON)
253 {
254 src.copyTo(m: dst);
255 return;
256 }
257
258 // temporary copy of the image with borders for easy processing
259 Mat temp;
260 copyMakeBorder( src, dst: temp, top: radius, bottom: radius, left: radius, right: radius, borderType );
261
262 // allocate lookup tables
263 std::vector<float> _space_weight(d*d);
264 std::vector<int> _space_ofs(d*d);
265 float* space_weight = &_space_weight[0];
266 int* space_ofs = &_space_ofs[0];
267
268 // assign a length which is slightly more than needed
269 len = (float)(maxValSrc - minValSrc) * cn;
270 kExpNumBins = kExpNumBinsPerChannel * cn;
271 std::vector<float> _expLUT(kExpNumBins+2);
272 float* expLUT = &_expLUT[0];
273
274 scale_index = kExpNumBins/len;
275
276 // initialize the exp LUT
277 for( i = 0; i < kExpNumBins+2; i++ )
278 {
279 if( lastExpVal > 0.f )
280 {
281 double val = i / scale_index;
282 expLUT[i] = (float)std::exp(x: val * val * gauss_color_coeff);
283 lastExpVal = expLUT[i];
284 }
285 else
286 expLUT[i] = 0.f;
287 }
288
289 // initialize space-related bilateral filter coefficients
290 for( i = -radius, maxk = 0; i <= radius; i++ )
291 for( j = -radius; j <= radius; j++ )
292 {
293 double r = std::sqrt(x: (double)i*i + (double)j*j);
294 if( r > radius || ( i == 0 && j == 0 ) )
295 continue;
296 space_weight[maxk] = (float)std::exp(x: r*r*gauss_space_coeff);
297 space_ofs[maxk++] = (int)(i*(temp.step/sizeof(float)) + j*cn);
298 }
299
300 // parallel_for usage
301 CV_CPU_DISPATCH(bilateralFilterInvoker_32f, (cn, radius, maxk, space_ofs, temp, dst, scale_index, space_weight, expLUT),
302 CV_CPU_DISPATCH_MODES_ALL);
303}
304
305#ifdef HAVE_IPP
306#define IPP_BILATERAL_PARALLEL 1
307
308#ifdef HAVE_IPP_IW
309class ipp_bilateralFilterParallel: public ParallelLoopBody
310{
311public:
312 ipp_bilateralFilterParallel(::ipp::IwiImage &_src, ::ipp::IwiImage &_dst, int _radius, Ipp32f _valSquareSigma, Ipp32f _posSquareSigma, ::ipp::IwiBorderType _borderType, bool *_ok):
313 src(_src), dst(_dst)
314 {
315 pOk = _ok;
316
317 radius = _radius;
318 valSquareSigma = _valSquareSigma;
319 posSquareSigma = _posSquareSigma;
320 borderType = _borderType;
321
322 *pOk = true;
323 }
324 ~ipp_bilateralFilterParallel() {}
325
326 virtual void operator() (const Range& range) const CV_OVERRIDE
327 {
328 if(*pOk == false)
329 return;
330
331 try
332 {
333 ::ipp::IwiTile tile = ::ipp::IwiRoi(0, range.start, dst.m_size.width, range.end - range.start);
334 CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterBilateral, src, dst, radius, valSquareSigma, posSquareSigma, ::ipp::IwDefault(), borderType, tile);
335 }
336 catch(const ::ipp::IwException &)
337 {
338 *pOk = false;
339 return;
340 }
341 }
342private:
343 ::ipp::IwiImage &src;
344 ::ipp::IwiImage &dst;
345
346 int radius;
347 Ipp32f valSquareSigma;
348 Ipp32f posSquareSigma;
349 ::ipp::IwiBorderType borderType;
350
351 bool *pOk;
352 const ipp_bilateralFilterParallel& operator= (const ipp_bilateralFilterParallel&);
353};
354#endif
355
356static bool ipp_bilateralFilter(Mat &src, Mat &dst, int d, double sigmaColor, double sigmaSpace, int borderType)
357{
358#ifdef HAVE_IPP_IW
359 CV_INSTRUMENT_REGION_IPP();
360
361 int radius = IPP_MAX(((d <= 0)?cvRound(sigmaSpace*1.5):d/2), 1);
362 Ipp32f valSquareSigma = (Ipp32f)((sigmaColor <= 0)?1:sigmaColor*sigmaColor);
363 Ipp32f posSquareSigma = (Ipp32f)((sigmaSpace <= 0)?1:sigmaSpace*sigmaSpace);
364
365 // Acquire data and begin processing
366 try
367 {
368 ::ipp::IwiImage iwSrc = ippiGetImage(src);
369 ::ipp::IwiImage iwDst = ippiGetImage(src: dst);
370 ::ipp::IwiBorderSize borderSize(radius);
371 ::ipp::IwiBorderType ippBorder(ippiGetBorder(image&: iwSrc, ocvBorderType: borderType, borderSize));
372 if(!ippBorder)
373 return false;
374
375 const int threads = ippiSuggestThreadsNum(image: iwDst, multiplier: 2);
376 if(IPP_BILATERAL_PARALLEL && threads > 1) {
377 bool ok = true;
378 Range range(0, (int)iwDst.m_size.height);
379 ipp_bilateralFilterParallel invoker(iwSrc, iwDst, radius, valSquareSigma, posSquareSigma, ippBorder, &ok);
380 if(!ok)
381 return false;
382
383 parallel_for_(range, body: invoker, nstripes: threads*4);
384
385 if(!ok)
386 return false;
387 } else {
388 CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterBilateral, iwSrc, iwDst, radius, valSquareSigma, posSquareSigma, ::ipp::IwDefault(), ippBorder);
389 }
390 }
391 catch (const ::ipp::IwException &)
392 {
393 return false;
394 }
395 return true;
396#else
397 CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(d); CV_UNUSED(sigmaColor); CV_UNUSED(sigmaSpace); CV_UNUSED(borderType);
398 return false;
399#endif
400}
401#endif
402
403void bilateralFilter( InputArray _src, OutputArray _dst, int d,
404 double sigmaColor, double sigmaSpace,
405 int borderType )
406{
407 CV_INSTRUMENT_REGION();
408
409 CV_Assert(!_src.empty());
410
411 _dst.create( sz: _src.size(), type: _src.type() );
412
413 CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
414 ocl_bilateralFilter_8u(_src, _dst, d, sigma_color: sigmaColor, sigma_space: sigmaSpace, borderType))
415
416 Mat src = _src.getMat(), dst = _dst.getMat();
417
418 CALL_HAL(bilateralFilter, cv_hal_bilateralFilter, src.data, src.step, dst.data, dst.step, src.cols, src.rows, src.depth(),
419 src.channels(), d, sigmaColor, sigmaSpace, borderType);
420
421 CV_IPP_RUN_FAST(ipp_bilateralFilter(src, dst, d, sigmaColor, sigmaSpace, borderType));
422
423 if( src.depth() == CV_8U )
424 bilateralFilter_8u( src, dst, d, sigma_color: sigmaColor, sigma_space: sigmaSpace, borderType );
425 else if( src.depth() == CV_32F )
426 bilateralFilter_32f( src, dst, d, sigma_color: sigmaColor, sigma_space: sigmaSpace, borderType );
427 else
428 CV_Error( cv::Error::StsUnsupportedFormat,
429 "Bilateral filtering is only implemented for 8u and 32f images" );
430}
431
432} // namespace
433

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of opencv/modules/imgproc/src/bilateral_filter.dispatch.cpp