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> |
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(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 | |
104 | void 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 | |
113 | void 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 | |
168 | void 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 | |
210 | static 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 | |
243 | template<typename ST, typename IT, typename UIT, typename D> |
244 | static 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 | |
309 | void 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 | |
319 | void 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 | |
382 | void 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 | |