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