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
48template<typename ST, typename IT, typename UIT, typename D>
49static 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(a: 1., b: (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
104void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, float h,
105 int templateWindowSize, int searchWindowSize)
106{
107 CV_INSTRUMENT_REGION();
108
109 fastNlMeansDenoising(src: _src, dst: _dst, h: std::vector<float>(1, h),
110 templateWindowSize, searchWindowSize);
111}
112
113void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, const std::vector<float>& h,
114 int templateWindowSize, int searchWindowSize, int normType)
115{
116 CV_INSTRUMENT_REGION();
117
118 int hn = (int)h.size(), type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
119 CV_Assert(!_src.empty());
120 CV_Assert(hn == 1 || hn == cn);
121
122 Size src_size = _src.size();
123 CV_OCL_RUN(_src.dims() <= 2 && (_src.isUMat() || _dst.isUMat()) &&
124 src_size.width > 5 && src_size.height > 5, // low accuracy on small sizes
125 ocl_fastNlMeansDenoising(_src, _dst, h: &h[0], hn,
126 templateWindowSize, searchWindowSize, normType))
127
128 Mat src = _src.getMat();
129 _dst.create(sz: src_size, type: src.type());
130 Mat dst = _dst.getMat();
131
132 switch (normType) {
133 case NORM_L2:
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
168void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
169 float h, float hForColorComponents,
170 int templateWindowSize, int searchWindowSize)
171{
172 CV_INSTRUMENT_REGION();
173
174 int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
175 Size src_size = _src.size();
176 if (type != CV_8UC3 && type != CV_8UC4)
177 {
178 CV_Error(Error::StsBadArg, "Type of input image should be CV_8UC3 or CV_8UC4!");
179 return;
180 }
181
182 CV_OCL_RUN(_src.dims() <= 2 && (_dst.isUMat() || _src.isUMat()) &&
183 src_size.width > 5 && src_size.height > 5, // low accuracy on small sizes
184 ocl_fastNlMeansDenoisingColored(_src, _dst, h, hForColorComponents,
185 templateWindowSize, searchWindowSize))
186
187 Mat src = _src.getMat();
188 _dst.create(sz: src_size, type);
189 Mat dst = _dst.getMat();
190
191 Mat src_lab;
192 cvtColor(src, dst: src_lab, code: COLOR_LBGR2Lab);
193
194 Mat l(src_size, CV_MAKE_TYPE(depth, 1));
195 Mat ab(src_size, CV_MAKE_TYPE(depth, 2));
196 Mat l_ab[] = { l, ab };
197 int from_to[] = { 0,0, 1,1, 2,2 };
198 mixChannels(src: &src_lab, nsrcs: 1, dst: l_ab, ndsts: 2, fromTo: from_to, npairs: 3);
199
200 fastNlMeansDenoising(src: l, dst: l, h, templateWindowSize, searchWindowSize);
201 fastNlMeansDenoising(src: ab, dst: ab, h: hForColorComponents, templateWindowSize, searchWindowSize);
202
203 Mat l_ab_denoised[] = { l, ab };
204 Mat dst_lab(src_size, CV_MAKE_TYPE(depth, 3));
205 mixChannels(src: l_ab_denoised, nsrcs: 2, dst: &dst_lab, ndsts: 1, fromTo: from_to, npairs: 3);
206
207 cvtColor(src: dst_lab, dst, code: COLOR_Lab2LBGR, dstCn: cn);
208}
209
210static void fastNlMeansDenoisingMultiCheckPreconditions(
211 const std::vector<Mat>& srcImgs,
212 int imgToDenoiseIndex, int temporalWindowSize,
213 int templateWindowSize, int searchWindowSize)
214{
215 int src_imgs_size = static_cast<int>(srcImgs.size());
216 if (src_imgs_size == 0)
217 {
218 CV_Error(Error::StsBadArg, "Input images vector should not be empty!");
219 }
220
221 if (temporalWindowSize % 2 == 0 ||
222 searchWindowSize % 2 == 0 ||
223 templateWindowSize % 2 == 0) {
224 CV_Error(Error::StsBadArg, "All windows sizes should be odd!");
225 }
226
227 int temporalWindowHalfSize = temporalWindowSize / 2;
228 if (imgToDenoiseIndex - temporalWindowHalfSize < 0 ||
229 imgToDenoiseIndex + temporalWindowHalfSize >= src_imgs_size)
230 {
231 CV_Error(Error::StsBadArg,
232 "imgToDenoiseIndex and temporalWindowSize "
233 "should be chosen corresponding srcImgs size!");
234 }
235
236 for (int i = 1; i < src_imgs_size; i++)
237 if (srcImgs[0].size() != srcImgs[i].size() || srcImgs[0].type() != srcImgs[i].type())
238 {
239 CV_Error(Error::StsBadArg, "Input images should have the same size and type!");
240 }
241}
242
243template<typename ST, typename IT, typename UIT, typename D>
244static void fastNlMeansDenoisingMulti_( const std::vector<Mat>& srcImgs, Mat& dst,
245 int imgToDenoiseIndex, int temporalWindowSize,
246 const std::vector<float>& h,
247 int templateWindowSize, int searchWindowSize)
248{
249 int hn = (int)h.size();
250 double granularity = (double)std::max(a: 1., b: (double)dst.total()/(1 << 16));
251
252 switch (srcImgs[0].type())
253 {
254 case CV_8U:
255 parallel_for_(cv::Range(0, srcImgs[0].rows),
256 FastNlMeansMultiDenoisingInvoker<uchar, IT, UIT, D, int>(
257 srcImgs, imgToDenoiseIndex, temporalWindowSize,
258 dst, templateWindowSize, searchWindowSize, &h[0]),
259 granularity);
260 break;
261 case CV_8UC2:
262 if (hn == 1)
263 parallel_for_(cv::Range(0, srcImgs[0].rows),
264 FastNlMeansMultiDenoisingInvoker<Vec<ST, 2>, IT, UIT, D, int>(
265 srcImgs, imgToDenoiseIndex, temporalWindowSize,
266 dst, templateWindowSize, searchWindowSize, &h[0]),
267 granularity);
268 else
269 parallel_for_(cv::Range(0, srcImgs[0].rows),
270 FastNlMeansMultiDenoisingInvoker<Vec<ST, 2>, IT, UIT, D, Vec2i>(
271 srcImgs, imgToDenoiseIndex, temporalWindowSize,
272 dst, templateWindowSize, searchWindowSize, &h[0]),
273 granularity);
274 break;
275 case CV_8UC3:
276 if (hn == 1)
277 parallel_for_(cv::Range(0, srcImgs[0].rows),
278 FastNlMeansMultiDenoisingInvoker<Vec<ST, 3>, IT, UIT, D, int>(
279 srcImgs, imgToDenoiseIndex, temporalWindowSize,
280 dst, templateWindowSize, searchWindowSize, &h[0]),
281 granularity);
282 else
283 parallel_for_(cv::Range(0, srcImgs[0].rows),
284 FastNlMeansMultiDenoisingInvoker<Vec<ST, 3>, IT, UIT, D, Vec3i>(
285 srcImgs, imgToDenoiseIndex, temporalWindowSize,
286 dst, templateWindowSize, searchWindowSize, &h[0]),
287 granularity);
288 break;
289 case CV_8UC4:
290 if (hn == 1)
291 parallel_for_(cv::Range(0, srcImgs[0].rows),
292 FastNlMeansMultiDenoisingInvoker<Vec<ST, 4>, IT, UIT, D, int>(
293 srcImgs, imgToDenoiseIndex, temporalWindowSize,
294 dst, templateWindowSize, searchWindowSize, &h[0]),
295 granularity);
296 else
297 parallel_for_(cv::Range(0, srcImgs[0].rows),
298 FastNlMeansMultiDenoisingInvoker<Vec<ST, 4>, IT, UIT, D, Vec4i>(
299 srcImgs, imgToDenoiseIndex, temporalWindowSize,
300 dst, templateWindowSize, searchWindowSize, &h[0]),
301 granularity);
302 break;
303 default:
304 CV_Error(Error::StsBadArg,
305 "Unsupported image format! Only CV_8U, CV_8UC2, CV_8UC3 and CV_8UC4 are supported");
306 }
307}
308
309void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _dst,
310 int imgToDenoiseIndex, int temporalWindowSize,
311 float h, int templateWindowSize, int searchWindowSize)
312{
313 CV_INSTRUMENT_REGION();
314
315 fastNlMeansDenoisingMulti(srcImgs: _srcImgs, dst: _dst, imgToDenoiseIndex, temporalWindowSize,
316 h: std::vector<float>(1, h), templateWindowSize, searchWindowSize);
317}
318
319void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _dst,
320 int imgToDenoiseIndex, int temporalWindowSize,
321 const std::vector<float>& h,
322 int templateWindowSize, int searchWindowSize, int normType)
323{
324 CV_INSTRUMENT_REGION();
325
326 std::vector<Mat> srcImgs;
327 _srcImgs.getMatVector(mv&: srcImgs);
328
329 fastNlMeansDenoisingMultiCheckPreconditions(
330 srcImgs, imgToDenoiseIndex,
331 temporalWindowSize, templateWindowSize, searchWindowSize);
332
333 int hn = (int)h.size();
334 int type = srcImgs[0].type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
335 CV_Assert(hn == 1 || hn == cn);
336
337 _dst.create(sz: srcImgs[0].size(), type: srcImgs[0].type());
338 Mat dst = _dst.getMat();
339
340 switch (normType) {
341 case NORM_L2:
342 switch (depth) {
343 case CV_8U:
344 fastNlMeansDenoisingMulti_<uchar, int, unsigned,
345 DistSquared>(srcImgs, dst,
346 imgToDenoiseIndex, temporalWindowSize,
347 h,
348 templateWindowSize, searchWindowSize);
349 break;
350 default:
351 CV_Error(Error::StsBadArg,
352 "Unsupported depth! Only CV_8U is supported for NORM_L2");
353 }
354 break;
355 case NORM_L1:
356 switch (depth) {
357 case CV_8U:
358 fastNlMeansDenoisingMulti_<uchar, int, unsigned,
359 DistAbs>(srcImgs, dst,
360 imgToDenoiseIndex, temporalWindowSize,
361 h,
362 templateWindowSize, searchWindowSize);
363 break;
364 case CV_16U:
365 fastNlMeansDenoisingMulti_<ushort, int64, uint64,
366 DistAbs>(srcImgs, dst,
367 imgToDenoiseIndex, temporalWindowSize,
368 h,
369 templateWindowSize, searchWindowSize);
370 break;
371 default:
372 CV_Error(Error::StsBadArg,
373 "Unsupported depth! Only CV_8U and CV_16U are supported for NORM_L1");
374 }
375 break;
376 default:
377 CV_Error(Error::StsBadArg,
378 "Unsupported norm type! Only NORM_L2 and NORM_L1 are supported");
379 }
380}
381
382void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs, OutputArray _dst,
383 int imgToDenoiseIndex, int temporalWindowSize,
384 float h, float hForColorComponents,
385 int templateWindowSize, int searchWindowSize)
386{
387 CV_INSTRUMENT_REGION();
388
389 std::vector<Mat> srcImgs;
390 _srcImgs.getMatVector(mv&: srcImgs);
391
392 fastNlMeansDenoisingMultiCheckPreconditions(
393 srcImgs, imgToDenoiseIndex,
394 temporalWindowSize, templateWindowSize, searchWindowSize);
395
396 _dst.create(sz: srcImgs[0].size(), type: srcImgs[0].type());
397 Mat dst = _dst.getMat();
398
399 int type = srcImgs[0].type(), depth = CV_MAT_DEPTH(type);
400 int src_imgs_size = static_cast<int>(srcImgs.size());
401
402 if (type != CV_8UC3)
403 {
404 CV_Error(Error::StsBadArg, "Type of input images should be CV_8UC3!");
405 return;
406 }
407
408 int from_to[] = { 0,0, 1,1, 2,2 };
409
410 // TODO convert only required images
411 std::vector<Mat> src_lab(src_imgs_size);
412 std::vector<Mat> l(src_imgs_size);
413 std::vector<Mat> ab(src_imgs_size);
414 for (int i = 0; i < src_imgs_size; i++)
415 {
416 src_lab[i] = Mat::zeros(size: srcImgs[0].size(), type);
417 l[i] = Mat::zeros(size: srcImgs[0].size(), CV_MAKE_TYPE(depth, 1));
418 ab[i] = Mat::zeros(size: srcImgs[0].size(), CV_MAKE_TYPE(depth, 2));
419 cvtColor(src: srcImgs[i], dst: src_lab[i], code: COLOR_LBGR2Lab);
420
421 Mat l_ab[] = { l[i], ab[i] };
422 mixChannels(src: &src_lab[i], nsrcs: 1, dst: l_ab, ndsts: 2, fromTo: from_to, npairs: 3);
423 }
424
425 Mat dst_l;
426 Mat dst_ab;
427
428 fastNlMeansDenoisingMulti(
429 srcImgs: l, dst: dst_l, imgToDenoiseIndex, temporalWindowSize,
430 h, templateWindowSize, searchWindowSize);
431
432 fastNlMeansDenoisingMulti(
433 srcImgs: ab, dst: dst_ab, imgToDenoiseIndex, temporalWindowSize,
434 h: hForColorComponents, templateWindowSize, searchWindowSize);
435
436 Mat l_ab_denoised[] = { dst_l, dst_ab };
437 Mat dst_lab(srcImgs[0].size(), srcImgs[0].type());
438 mixChannels(src: l_ab_denoised, nsrcs: 2, dst: &dst_lab, ndsts: 1, fromTo: from_to, npairs: 3);
439
440 cvtColor(src: dst_lab, dst, code: COLOR_Lab2LBGR);
441}
442

Provided by KDAB

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

source code of opencv/modules/photo/src/denoising.cpp