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 // Intel License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective icvers.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
21 //
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
25 //
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "precomp.hpp"
43
44 #include "fast_nlmeans_denoising_invoker.hpp"
45 #include "fast_nlmeans_multi_denoising_invoker.hpp"
46 #include "fast_nlmeans_denoising_opencl.hpp"
47
48 template<typename ST, typename IT, typename UIT, typename D>
fastNlMeansDenoising_(const Mat & src,Mat & dst,const std::vector<float> & h,int templateWindowSize,int searchWindowSize)49 static void fastNlMeansDenoising_( const Mat& src, Mat& dst, const std::vector<float>& h,
50 int templateWindowSize, int searchWindowSize)
51 {
52 int hn = (int)h.size();
53 double granularity = (double)std::max(1., (double)dst.total()/(1 << 17));
54
55 switch (CV_MAT_CN(src.type())) {
56 case 1:
57 parallel_for_(cv::Range(0, src.rows),
58 FastNlMeansDenoisingInvoker<ST, IT, UIT, D, int>(
59 src, dst, templateWindowSize, searchWindowSize, &h[0]),
60 granularity);
61 break;
62 case 2:
63 if (hn == 1)
64 parallel_for_(cv::Range(0, src.rows),
65 FastNlMeansDenoisingInvoker<Vec<ST, 2>, IT, UIT, D, int>(
66 src, dst, templateWindowSize, searchWindowSize, &h[0]),
67 granularity);
68 else
69 parallel_for_(cv::Range(0, src.rows),
70 FastNlMeansDenoisingInvoker<Vec<ST, 2>, IT, UIT, D, Vec2i>(
71 src, dst, templateWindowSize, searchWindowSize, &h[0]),
72 granularity);
73 break;
74 case 3:
75 if (hn == 1)
76 parallel_for_(cv::Range(0, src.rows),
77 FastNlMeansDenoisingInvoker<Vec<ST, 3>, IT, UIT, D, int>(
78 src, dst, templateWindowSize, searchWindowSize, &h[0]),
79 granularity);
80 else
81 parallel_for_(cv::Range(0, src.rows),
82 FastNlMeansDenoisingInvoker<Vec<ST, 3>, IT, UIT, D, Vec3i>(
83 src, dst, templateWindowSize, searchWindowSize, &h[0]),
84 granularity);
85 break;
86 case 4:
87 if (hn == 1)
88 parallel_for_(cv::Range(0, src.rows),
89 FastNlMeansDenoisingInvoker<Vec<ST, 4>, IT, UIT, D, int>(
90 src, dst, templateWindowSize, searchWindowSize, &h[0]),
91 granularity);
92 else
93 parallel_for_(cv::Range(0, src.rows),
94 FastNlMeansDenoisingInvoker<Vec<ST, 4>, IT, UIT, D, Vec4i>(
95 src, dst, templateWindowSize, searchWindowSize, &h[0]),
96 granularity);
97 break;
98 default:
99 CV_Error(Error::StsBadArg,
100 "Unsupported number of channels! Only 1, 2, 3, and 4 are supported");
101 }
102 }
103
fastNlMeansDenoising(InputArray _src,OutputArray _dst,float h,int templateWindowSize,int searchWindowSize)104 void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, float h,
105 int templateWindowSize, int searchWindowSize)
106 {
107 fastNlMeansDenoising(_src, _dst, std::vector<float>(1, h),
108 templateWindowSize, searchWindowSize);
109 }
110
fastNlMeansDenoising(InputArray _src,OutputArray _dst,const std::vector<float> & h,int templateWindowSize,int searchWindowSize,int normType)111 void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, const std::vector<float>& h,
112 int templateWindowSize, int searchWindowSize, int normType)
113 {
114 int hn = (int)h.size(), type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
115 CV_Assert(hn == 1 || hn == cn);
116
117 Size src_size = _src.size();
118 CV_OCL_RUN(_src.dims() <= 2 && (_src.isUMat() || _dst.isUMat()) &&
119 src_size.width > 5 && src_size.height > 5, // low accuracy on small sizes
120 ocl_fastNlMeansDenoising(_src, _dst, &h[0], hn,
121 templateWindowSize, searchWindowSize, normType))
122
123 Mat src = _src.getMat();
124 _dst.create(src_size, src.type());
125 Mat dst = _dst.getMat();
126
127 switch (normType) {
128 case NORM_L2:
129 #ifdef HAVE_TEGRA_OPTIMIZATION
130 if(hn == 1 && tegra::useTegra() &&
131 tegra::fastNlMeansDenoising(src, dst, h[0], templateWindowSize, searchWindowSize))
132 return;
133 #endif
134 switch (depth) {
135 case CV_8U:
136 fastNlMeansDenoising_<uchar, int, unsigned, DistSquared>(src, dst, h,
137 templateWindowSize,
138 searchWindowSize);
139 break;
140 default:
141 CV_Error(Error::StsBadArg,
142 "Unsupported depth! Only CV_8U is supported for NORM_L2");
143 }
144 break;
145 case NORM_L1:
146 switch (depth) {
147 case CV_8U:
148 fastNlMeansDenoising_<uchar, int, unsigned, DistAbs>(src, dst, h,
149 templateWindowSize,
150 searchWindowSize);
151 break;
152 case CV_16U:
153 fastNlMeansDenoising_<ushort, int64, uint64, DistAbs>(src, dst, h,
154 templateWindowSize,
155 searchWindowSize);
156 break;
157 default:
158 CV_Error(Error::StsBadArg,
159 "Unsupported depth! Only CV_8U and CV_16U are supported for NORM_L1");
160 }
161 break;
162 default:
163 CV_Error(Error::StsBadArg,
164 "Unsupported norm type! Only NORM_L2 and NORM_L1 are supported");
165 }
166 }
167
fastNlMeansDenoisingColored(InputArray _src,OutputArray _dst,float h,float hForColorComponents,int templateWindowSize,int searchWindowSize)168 void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
169 float h, float hForColorComponents,
170 int templateWindowSize, int searchWindowSize)
171 {
172 int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
173 Size src_size = _src.size();
174 if (type != CV_8UC3 && type != CV_8UC4)
175 {
176 CV_Error(Error::StsBadArg, "Type of input image should be CV_8UC3 or CV_8UC4!");
177 return;
178 }
179
180 CV_OCL_RUN(_src.dims() <= 2 && (_dst.isUMat() || _src.isUMat()) &&
181 src_size.width > 5 && src_size.height > 5, // low accuracy on small sizes
182 ocl_fastNlMeansDenoisingColored(_src, _dst, h, hForColorComponents,
183 templateWindowSize, searchWindowSize))
184
185 Mat src = _src.getMat();
186 _dst.create(src_size, type);
187 Mat dst = _dst.getMat();
188
189 Mat src_lab;
190 cvtColor(src, src_lab, COLOR_LBGR2Lab);
191
192 Mat l(src_size, CV_MAKE_TYPE(depth, 1));
193 Mat ab(src_size, CV_MAKE_TYPE(depth, 2));
194 Mat l_ab[] = { l, ab };
195 int from_to[] = { 0,0, 1,1, 2,2 };
196 mixChannels(&src_lab, 1, l_ab, 2, from_to, 3);
197
198 fastNlMeansDenoising(l, l, h, templateWindowSize, searchWindowSize);
199 fastNlMeansDenoising(ab, ab, hForColorComponents, templateWindowSize, searchWindowSize);
200
201 Mat l_ab_denoised[] = { l, ab };
202 Mat dst_lab(src_size, CV_MAKE_TYPE(depth, 3));
203 mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3);
204
205 cvtColor(dst_lab, dst, COLOR_Lab2LBGR, cn);
206 }
207
fastNlMeansDenoisingMultiCheckPreconditions(const std::vector<Mat> & srcImgs,int imgToDenoiseIndex,int temporalWindowSize,int templateWindowSize,int searchWindowSize)208 static void fastNlMeansDenoisingMultiCheckPreconditions(
209 const std::vector<Mat>& srcImgs,
210 int imgToDenoiseIndex, int temporalWindowSize,
211 int templateWindowSize, int searchWindowSize)
212 {
213 int src_imgs_size = static_cast<int>(srcImgs.size());
214 if (src_imgs_size == 0)
215 {
216 CV_Error(Error::StsBadArg, "Input images vector should not be empty!");
217 }
218
219 if (temporalWindowSize % 2 == 0 ||
220 searchWindowSize % 2 == 0 ||
221 templateWindowSize % 2 == 0) {
222 CV_Error(Error::StsBadArg, "All windows sizes should be odd!");
223 }
224
225 int temporalWindowHalfSize = temporalWindowSize / 2;
226 if (imgToDenoiseIndex - temporalWindowHalfSize < 0 ||
227 imgToDenoiseIndex + temporalWindowHalfSize >= src_imgs_size)
228 {
229 CV_Error(Error::StsBadArg,
230 "imgToDenoiseIndex and temporalWindowSize "
231 "should be chosen corresponding srcImgs size!");
232 }
233
234 for (int i = 1; i < src_imgs_size; i++)
235 if (srcImgs[0].size() != srcImgs[i].size() || srcImgs[0].type() != srcImgs[i].type())
236 {
237 CV_Error(Error::StsBadArg, "Input images should have the same size and type!");
238 }
239 }
240
241 template<typename ST, typename IT, typename UIT, typename D>
fastNlMeansDenoisingMulti_(const std::vector<Mat> & srcImgs,Mat & dst,int imgToDenoiseIndex,int temporalWindowSize,const std::vector<float> & h,int templateWindowSize,int searchWindowSize)242 static void fastNlMeansDenoisingMulti_( const std::vector<Mat>& srcImgs, Mat& dst,
243 int imgToDenoiseIndex, int temporalWindowSize,
244 const std::vector<float>& h,
245 int templateWindowSize, int searchWindowSize)
246 {
247 int hn = (int)h.size();
248 double granularity = (double)std::max(1., (double)dst.total()/(1 << 16));
249
250 switch (srcImgs[0].type())
251 {
252 case CV_8U:
253 parallel_for_(cv::Range(0, srcImgs[0].rows),
254 FastNlMeansMultiDenoisingInvoker<uchar, IT, UIT, D, int>(
255 srcImgs, imgToDenoiseIndex, temporalWindowSize,
256 dst, templateWindowSize, searchWindowSize, &h[0]),
257 granularity);
258 break;
259 case CV_8UC2:
260 if (hn == 1)
261 parallel_for_(cv::Range(0, srcImgs[0].rows),
262 FastNlMeansMultiDenoisingInvoker<Vec<ST, 2>, IT, UIT, D, int>(
263 srcImgs, imgToDenoiseIndex, temporalWindowSize,
264 dst, templateWindowSize, searchWindowSize, &h[0]),
265 granularity);
266 else
267 parallel_for_(cv::Range(0, srcImgs[0].rows),
268 FastNlMeansMultiDenoisingInvoker<Vec<ST, 2>, IT, UIT, D, Vec2i>(
269 srcImgs, imgToDenoiseIndex, temporalWindowSize,
270 dst, templateWindowSize, searchWindowSize, &h[0]),
271 granularity);
272 break;
273 case CV_8UC3:
274 if (hn == 1)
275 parallel_for_(cv::Range(0, srcImgs[0].rows),
276 FastNlMeansMultiDenoisingInvoker<Vec<ST, 3>, IT, UIT, D, int>(
277 srcImgs, imgToDenoiseIndex, temporalWindowSize,
278 dst, templateWindowSize, searchWindowSize, &h[0]),
279 granularity);
280 else
281 parallel_for_(cv::Range(0, srcImgs[0].rows),
282 FastNlMeansMultiDenoisingInvoker<Vec<ST, 3>, IT, UIT, D, Vec3i>(
283 srcImgs, imgToDenoiseIndex, temporalWindowSize,
284 dst, templateWindowSize, searchWindowSize, &h[0]),
285 granularity);
286 break;
287 case CV_8UC4:
288 if (hn == 1)
289 parallel_for_(cv::Range(0, srcImgs[0].rows),
290 FastNlMeansMultiDenoisingInvoker<Vec<ST, 4>, IT, UIT, D, int>(
291 srcImgs, imgToDenoiseIndex, temporalWindowSize,
292 dst, templateWindowSize, searchWindowSize, &h[0]),
293 granularity);
294 else
295 parallel_for_(cv::Range(0, srcImgs[0].rows),
296 FastNlMeansMultiDenoisingInvoker<Vec<ST, 4>, IT, UIT, D, Vec4i>(
297 srcImgs, imgToDenoiseIndex, temporalWindowSize,
298 dst, templateWindowSize, searchWindowSize, &h[0]),
299 granularity);
300 break;
301 default:
302 CV_Error(Error::StsBadArg,
303 "Unsupported image format! Only CV_8U, CV_8UC2, CV_8UC3 and CV_8UC4 are supported");
304 }
305 }
306
fastNlMeansDenoisingMulti(InputArrayOfArrays _srcImgs,OutputArray _dst,int imgToDenoiseIndex,int temporalWindowSize,float h,int templateWindowSize,int searchWindowSize)307 void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _dst,
308 int imgToDenoiseIndex, int temporalWindowSize,
309 float h, int templateWindowSize, int searchWindowSize)
310 {
311 fastNlMeansDenoisingMulti(_srcImgs, _dst, imgToDenoiseIndex, temporalWindowSize,
312 std::vector<float>(1, h), templateWindowSize, searchWindowSize);
313 }
314
fastNlMeansDenoisingMulti(InputArrayOfArrays _srcImgs,OutputArray _dst,int imgToDenoiseIndex,int temporalWindowSize,const std::vector<float> & h,int templateWindowSize,int searchWindowSize,int normType)315 void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _dst,
316 int imgToDenoiseIndex, int temporalWindowSize,
317 const std::vector<float>& h,
318 int templateWindowSize, int searchWindowSize, int normType)
319 {
320 std::vector<Mat> srcImgs;
321 _srcImgs.getMatVector(srcImgs);
322
323 fastNlMeansDenoisingMultiCheckPreconditions(
324 srcImgs, imgToDenoiseIndex,
325 temporalWindowSize, templateWindowSize, searchWindowSize);
326
327 int hn = (int)h.size();
328 int type = srcImgs[0].type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
329 CV_Assert(hn == 1 || hn == cn);
330
331 _dst.create(srcImgs[0].size(), srcImgs[0].type());
332 Mat dst = _dst.getMat();
333
334 switch (normType) {
335 case NORM_L2:
336 switch (depth) {
337 case CV_8U:
338 fastNlMeansDenoisingMulti_<uchar, int, unsigned,
339 DistSquared>(srcImgs, dst,
340 imgToDenoiseIndex, temporalWindowSize,
341 h,
342 templateWindowSize, searchWindowSize);
343 break;
344 default:
345 CV_Error(Error::StsBadArg,
346 "Unsupported depth! Only CV_8U is supported for NORM_L2");
347 }
348 break;
349 case NORM_L1:
350 switch (depth) {
351 case CV_8U:
352 fastNlMeansDenoisingMulti_<uchar, int, unsigned,
353 DistAbs>(srcImgs, dst,
354 imgToDenoiseIndex, temporalWindowSize,
355 h,
356 templateWindowSize, searchWindowSize);
357 break;
358 case CV_16U:
359 fastNlMeansDenoisingMulti_<ushort, int64, uint64,
360 DistAbs>(srcImgs, dst,
361 imgToDenoiseIndex, temporalWindowSize,
362 h,
363 templateWindowSize, searchWindowSize);
364 break;
365 default:
366 CV_Error(Error::StsBadArg,
367 "Unsupported depth! Only CV_8U and CV_16U are supported for NORM_L1");
368 }
369 break;
370 default:
371 CV_Error(Error::StsBadArg,
372 "Unsupported norm type! Only NORM_L2 and NORM_L1 are supported");
373 }
374 }
375
fastNlMeansDenoisingColoredMulti(InputArrayOfArrays _srcImgs,OutputArray _dst,int imgToDenoiseIndex,int temporalWindowSize,float h,float hForColorComponents,int templateWindowSize,int searchWindowSize)376 void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs, OutputArray _dst,
377 int imgToDenoiseIndex, int temporalWindowSize,
378 float h, float hForColorComponents,
379 int templateWindowSize, int searchWindowSize)
380 {
381 std::vector<Mat> srcImgs;
382 _srcImgs.getMatVector(srcImgs);
383
384 fastNlMeansDenoisingMultiCheckPreconditions(
385 srcImgs, imgToDenoiseIndex,
386 temporalWindowSize, templateWindowSize, searchWindowSize);
387
388 _dst.create(srcImgs[0].size(), srcImgs[0].type());
389 Mat dst = _dst.getMat();
390
391 int type = srcImgs[0].type(), depth = CV_MAT_DEPTH(type);
392 int src_imgs_size = static_cast<int>(srcImgs.size());
393
394 if (type != CV_8UC3)
395 {
396 CV_Error(Error::StsBadArg, "Type of input images should be CV_8UC3!");
397 return;
398 }
399
400 int from_to[] = { 0,0, 1,1, 2,2 };
401
402 // TODO convert only required images
403 std::vector<Mat> src_lab(src_imgs_size);
404 std::vector<Mat> l(src_imgs_size);
405 std::vector<Mat> ab(src_imgs_size);
406 for (int i = 0; i < src_imgs_size; i++)
407 {
408 src_lab[i] = Mat::zeros(srcImgs[0].size(), type);
409 l[i] = Mat::zeros(srcImgs[0].size(), CV_MAKE_TYPE(depth, 1));
410 ab[i] = Mat::zeros(srcImgs[0].size(), CV_MAKE_TYPE(depth, 2));
411 cvtColor(srcImgs[i], src_lab[i], COLOR_LBGR2Lab);
412
413 Mat l_ab[] = { l[i], ab[i] };
414 mixChannels(&src_lab[i], 1, l_ab, 2, from_to, 3);
415 }
416
417 Mat dst_l;
418 Mat dst_ab;
419
420 fastNlMeansDenoisingMulti(
421 l, dst_l, imgToDenoiseIndex, temporalWindowSize,
422 h, templateWindowSize, searchWindowSize);
423
424 fastNlMeansDenoisingMulti(
425 ab, dst_ab, imgToDenoiseIndex, temporalWindowSize,
426 hForColorComponents, templateWindowSize, searchWindowSize);
427
428 Mat l_ab_denoised[] = { dst_l, dst_ab };
429 Mat dst_lab(srcImgs[0].size(), srcImgs[0].type());
430 mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3);
431
432 cvtColor(dst_lab, dst, COLOR_Lab2LBGR);
433 }
434