denoising.cpp 19.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective icvers.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"
43

44 45
#include "fast_nlmeans_denoising_invoker.hpp"
#include "fast_nlmeans_multi_denoising_invoker.hpp"
46
#include "fast_nlmeans_denoising_opencl.hpp"
47

48 49 50
template<typename ST, typename IT, typename UIT, typename D>
static void fastNlMeansDenoising_( const Mat& src, Mat& dst, const std::vector<float>& h,
                                   int templateWindowSize, int searchWindowSize)
51
{
Erik Karlsson's avatar
Erik Karlsson committed
52
    int hn = (int)h.size();
53
    double granularity = (double)std::max(1., (double)dst.total()/(1 << 17));
54

55 56
    switch (CV_MAT_CN(src.type())) {
        case 1:
57
            parallel_for_(cv::Range(0, src.rows),
58
                          FastNlMeansDenoisingInvoker<ST, IT, UIT, D, int>(
59 60
                              src, dst, templateWindowSize, searchWindowSize, &h[0]),
                          granularity);
61
            break;
62
        case 2:
63 64
            if (hn == 1)
                parallel_for_(cv::Range(0, src.rows),
65
                              FastNlMeansDenoisingInvoker<Vec<ST, 2>, IT, UIT, D, int>(
66 67
                                  src, dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
68 69
            else
                parallel_for_(cv::Range(0, src.rows),
70
                              FastNlMeansDenoisingInvoker<Vec<ST, 2>, IT, UIT, D, Vec2i>(
71 72
                                  src, dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
73
            break;
74
        case 3:
75 76
            if (hn == 1)
                parallel_for_(cv::Range(0, src.rows),
77
                              FastNlMeansDenoisingInvoker<Vec<ST, 3>, IT, UIT, D, int>(
78 79
                                  src, dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
80 81
            else
                parallel_for_(cv::Range(0, src.rows),
82
                              FastNlMeansDenoisingInvoker<Vec<ST, 3>, IT, UIT, D, Vec3i>(
83 84
                                  src, dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
85
            break;
86
        case 4:
87 88
            if (hn == 1)
                parallel_for_(cv::Range(0, src.rows),
89
                              FastNlMeansDenoisingInvoker<Vec<ST, 4>, IT, UIT, D, int>(
90 91
                                  src, dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
92 93
            else
                parallel_for_(cv::Range(0, src.rows),
94
                              FastNlMeansDenoisingInvoker<Vec<ST, 4>, IT, UIT, D, Vec4i>(
95 96
                                  src, dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
97 98 99
            break;
        default:
            CV_Error(Error::StsBadArg,
100 101 102 103 104 105 106
                     "Unsupported number of channels! Only 1, 2, 3, and 4 are supported");
    }
}

void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, float h,
                               int templateWindowSize, int searchWindowSize)
{
107 108
    CV_INSTRUMENT_REGION()

109 110 111 112 113 114 115
    fastNlMeansDenoising(_src, _dst, std::vector<float>(1, h),
                         templateWindowSize, searchWindowSize);
}

void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, const std::vector<float>& h,
                               int templateWindowSize, int searchWindowSize, int normType)
{
116 117
    CV_INSTRUMENT_REGION()

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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    CV_Assert(hn == 1 || hn == cn);

    Size src_size = _src.size();
    CV_OCL_RUN(_src.dims() <= 2 && (_src.isUMat() || _dst.isUMat()) &&
               src_size.width > 5 && src_size.height > 5, // low accuracy on small sizes
               ocl_fastNlMeansDenoising(_src, _dst, &h[0], hn,
                                        templateWindowSize, searchWindowSize, normType))

    Mat src = _src.getMat();
    _dst.create(src_size, src.type());
    Mat dst = _dst.getMat();

    switch (normType) {
        case NORM_L2:
#ifdef HAVE_TEGRA_OPTIMIZATION
            if(hn == 1 && tegra::useTegra() &&
               tegra::fastNlMeansDenoising(src, dst, h[0], templateWindowSize, searchWindowSize))
                return;
#endif
            switch (depth) {
                case CV_8U:
                    fastNlMeansDenoising_<uchar, int, unsigned, DistSquared>(src, dst, h,
                                                                             templateWindowSize,
                                                                             searchWindowSize);
                    break;
                default:
                    CV_Error(Error::StsBadArg,
                             "Unsupported depth! Only CV_8U is supported for NORM_L2");
            }
            break;
        case NORM_L1:
            switch (depth) {
                case CV_8U:
                    fastNlMeansDenoising_<uchar, int, unsigned, DistAbs>(src, dst, h,
                                                                         templateWindowSize,
                                                                         searchWindowSize);
                    break;
                case CV_16U:
                    fastNlMeansDenoising_<ushort, int64, uint64, DistAbs>(src, dst, h,
                                                                          templateWindowSize,
                                                                          searchWindowSize);
                    break;
                default:
                    CV_Error(Error::StsBadArg,
                             "Unsupported depth! Only CV_8U and CV_16U are supported for NORM_L1");
            }
            break;
        default:
            CV_Error(Error::StsBadArg,
                     "Unsupported norm type! Only NORM_L2 and NORM_L1 are supported");
170 171 172
    }
}

173
void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
174
                                      float h, float hForColorComponents,
175
                                      int templateWindowSize, int searchWindowSize)
176
{
177 178
    CV_INSTRUMENT_REGION()

179
    int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
180
    Size src_size = _src.size();
181
    if (type != CV_8UC3 && type != CV_8UC4)
182
    {
183
        CV_Error(Error::StsBadArg, "Type of input image should be CV_8UC3 or CV_8UC4!");
184 185 186
        return;
    }

187 188
    CV_OCL_RUN(_src.dims() <= 2 && (_dst.isUMat() || _src.isUMat()) &&
                src_size.width > 5 && src_size.height > 5, // low accuracy on small sizes
189 190 191 192
                ocl_fastNlMeansDenoisingColored(_src, _dst, h, hForColorComponents,
                                                templateWindowSize, searchWindowSize))

    Mat src = _src.getMat();
193
    _dst.create(src_size, type);
194 195
    Mat dst = _dst.getMat();

196
    Mat src_lab;
197
    cvtColor(src, src_lab, COLOR_LBGR2Lab);
198

199 200
    Mat l(src_size, CV_MAKE_TYPE(depth, 1));
    Mat ab(src_size, CV_MAKE_TYPE(depth, 2));
201 202 203
    Mat l_ab[] = { l, ab };
    int from_to[] = { 0,0, 1,1, 2,2 };
    mixChannels(&src_lab, 1, l_ab, 2, from_to, 3);
204

205 206
    fastNlMeansDenoising(l, l, h, templateWindowSize, searchWindowSize);
    fastNlMeansDenoising(ab, ab, hForColorComponents, templateWindowSize, searchWindowSize);
207 208

    Mat l_ab_denoised[] = { l, ab };
209
    Mat dst_lab(src_size, CV_MAKE_TYPE(depth, 3));
210 211
    mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3);

212
    cvtColor(dst_lab, dst, COLOR_Lab2LBGR, cn);
213 214
}

215 216
static void fastNlMeansDenoisingMultiCheckPreconditions(
                               const std::vector<Mat>& srcImgs,
217
                               int imgToDenoiseIndex, int temporalWindowSize,
218
                               int templateWindowSize, int searchWindowSize)
219
{
220
    int src_imgs_size = static_cast<int>(srcImgs.size());
Ilya Lavrenov's avatar
Ilya Lavrenov committed
221 222
    if (src_imgs_size == 0)
    {
223
        CV_Error(Error::StsBadArg, "Input images vector should not be empty!");
224 225 226 227 228
    }

    if (temporalWindowSize % 2 == 0 ||
        searchWindowSize % 2 == 0 ||
        templateWindowSize % 2 == 0) {
229
        CV_Error(Error::StsBadArg, "All windows sizes should be odd!");
230 231 232
    }

    int temporalWindowHalfSize = temporalWindowSize / 2;
233 234 235
    if (imgToDenoiseIndex - temporalWindowHalfSize < 0 ||
        imgToDenoiseIndex + temporalWindowHalfSize >= src_imgs_size)
    {
236
        CV_Error(Error::StsBadArg,
237
            "imgToDenoiseIndex and temporalWindowSize "
Ilya Lavrenov's avatar
Ilya Lavrenov committed
238
            "should be chosen corresponding srcImgs size!");
239 240
    }

Ilya Lavrenov's avatar
Ilya Lavrenov committed
241 242 243
    for (int i = 1; i < src_imgs_size; i++)
        if (srcImgs[0].size() != srcImgs[i].size() || srcImgs[0].type() != srcImgs[i].type())
        {
244
            CV_Error(Error::StsBadArg, "Input images should have the same size and type!");
245 246 247
        }
}

248 249 250 251 252
template<typename ST, typename IT, typename UIT, typename D>
static void fastNlMeansDenoisingMulti_( const std::vector<Mat>& srcImgs, Mat& dst,
                                        int imgToDenoiseIndex, int temporalWindowSize,
                                        const std::vector<float>& h,
                                        int templateWindowSize, int searchWindowSize)
253
{
Erik Karlsson's avatar
Erik Karlsson committed
254
    int hn = (int)h.size();
255
    double granularity = (double)std::max(1., (double)dst.total()/(1 << 16));
256 257 258 259 260

    switch (srcImgs[0].type())
    {
        case CV_8U:
            parallel_for_(cv::Range(0, srcImgs[0].rows),
261
                          FastNlMeansMultiDenoisingInvoker<uchar, IT, UIT, D, int>(
262
                              srcImgs, imgToDenoiseIndex, temporalWindowSize,
263 264
                              dst, templateWindowSize, searchWindowSize, &h[0]),
                          granularity);
265 266
            break;
        case CV_8UC2:
267 268
            if (hn == 1)
                parallel_for_(cv::Range(0, srcImgs[0].rows),
269
                              FastNlMeansMultiDenoisingInvoker<Vec<ST, 2>, IT, UIT, D, int>(
270
                                  srcImgs, imgToDenoiseIndex, temporalWindowSize,
271 272
                                  dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
273 274
            else
                parallel_for_(cv::Range(0, srcImgs[0].rows),
275
                              FastNlMeansMultiDenoisingInvoker<Vec<ST, 2>, IT, UIT, D, Vec2i>(
276
                                  srcImgs, imgToDenoiseIndex, temporalWindowSize,
277 278
                                  dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
279 280
            break;
        case CV_8UC3:
281 282
            if (hn == 1)
                parallel_for_(cv::Range(0, srcImgs[0].rows),
283
                              FastNlMeansMultiDenoisingInvoker<Vec<ST, 3>, IT, UIT, D, int>(
284
                                  srcImgs, imgToDenoiseIndex, temporalWindowSize,
285 286
                                  dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
287 288
            else
                parallel_for_(cv::Range(0, srcImgs[0].rows),
289
                              FastNlMeansMultiDenoisingInvoker<Vec<ST, 3>, IT, UIT, D, Vec3i>(
290
                                  srcImgs, imgToDenoiseIndex, temporalWindowSize,
291 292
                                  dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
293 294
            break;
        case CV_8UC4:
295 296
            if (hn == 1)
                parallel_for_(cv::Range(0, srcImgs[0].rows),
297
                              FastNlMeansMultiDenoisingInvoker<Vec<ST, 4>, IT, UIT, D, int>(
298
                                  srcImgs, imgToDenoiseIndex, temporalWindowSize,
299 300
                                  dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
301 302
            else
                parallel_for_(cv::Range(0, srcImgs[0].rows),
303
                              FastNlMeansMultiDenoisingInvoker<Vec<ST, 4>, IT, UIT, D, Vec4i>(
304
                                  srcImgs, imgToDenoiseIndex, temporalWindowSize,
305 306
                                  dst, templateWindowSize, searchWindowSize, &h[0]),
                              granularity);
307 308 309 310 311 312 313
            break;
        default:
            CV_Error(Error::StsBadArg,
                "Unsupported image format! Only CV_8U, CV_8UC2, CV_8UC3 and CV_8UC4 are supported");
    }
}

314 315 316 317
void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _dst,
                                    int imgToDenoiseIndex, int temporalWindowSize,
                                    float h, int templateWindowSize, int searchWindowSize)
{
318 319
    CV_INSTRUMENT_REGION()

320 321 322 323 324 325 326 327 328
    fastNlMeansDenoisingMulti(_srcImgs, _dst, imgToDenoiseIndex, temporalWindowSize,
                              std::vector<float>(1, h), templateWindowSize, searchWindowSize);
}

void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _dst,
                                    int imgToDenoiseIndex, int temporalWindowSize,
                                    const std::vector<float>& h,
                                    int templateWindowSize, int searchWindowSize, int normType)
{
329 330
    CV_INSTRUMENT_REGION()

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
    std::vector<Mat> srcImgs;
    _srcImgs.getMatVector(srcImgs);

    fastNlMeansDenoisingMultiCheckPreconditions(
        srcImgs, imgToDenoiseIndex,
        temporalWindowSize, templateWindowSize, searchWindowSize);

    int hn = (int)h.size();
    int type = srcImgs[0].type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
    CV_Assert(hn == 1 || hn == cn);

    _dst.create(srcImgs[0].size(), srcImgs[0].type());
    Mat dst = _dst.getMat();

    switch (normType) {
        case NORM_L2:
            switch (depth) {
                case CV_8U:
                    fastNlMeansDenoisingMulti_<uchar, int, unsigned,
                                               DistSquared>(srcImgs, dst,
                                                            imgToDenoiseIndex, temporalWindowSize,
                                                            h,
                                                            templateWindowSize, searchWindowSize);
                    break;
                default:
                    CV_Error(Error::StsBadArg,
                             "Unsupported depth! Only CV_8U is supported for NORM_L2");
            }
            break;
        case NORM_L1:
            switch (depth) {
                case CV_8U:
                    fastNlMeansDenoisingMulti_<uchar, int, unsigned,
                                               DistAbs>(srcImgs, dst,
                                                        imgToDenoiseIndex, temporalWindowSize,
                                                        h,
                                                        templateWindowSize, searchWindowSize);
                    break;
                case CV_16U:
                    fastNlMeansDenoisingMulti_<ushort, int64, uint64,
                                               DistAbs>(srcImgs, dst,
                                                        imgToDenoiseIndex, temporalWindowSize,
                                                        h,
                                                        templateWindowSize, searchWindowSize);
                    break;
                default:
                    CV_Error(Error::StsBadArg,
                             "Unsupported depth! Only CV_8U and CV_16U are supported for NORM_L1");
            }
            break;
        default:
            CV_Error(Error::StsBadArg,
                     "Unsupported norm type! Only NORM_L2 and NORM_L1 are supported");
    }
}

387
void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs, OutputArray _dst,
388
                                           int imgToDenoiseIndex, int temporalWindowSize,
389
                                           float h, float hForColorComponents,
390
                                           int templateWindowSize, int searchWindowSize)
391
{
392 393
    CV_INSTRUMENT_REGION()

394
    std::vector<Mat> srcImgs;
395
    _srcImgs.getMatVector(srcImgs);
396

397
    fastNlMeansDenoisingMultiCheckPreconditions(
398
        srcImgs, imgToDenoiseIndex,
Ilya Lavrenov's avatar
Ilya Lavrenov committed
399
        temporalWindowSize, templateWindowSize, searchWindowSize);
400

401 402
    _dst.create(srcImgs[0].size(), srcImgs[0].type());
    Mat dst = _dst.getMat();
403

404
    int type = srcImgs[0].type(), depth = CV_MAT_DEPTH(type);
405
    int src_imgs_size = static_cast<int>(srcImgs.size());
406

407
    if (type != CV_8UC3)
Ilya Lavrenov's avatar
Ilya Lavrenov committed
408
    {
409
        CV_Error(Error::StsBadArg, "Type of input images should be CV_8UC3!");
410 411 412 413 414 415
        return;
    }

    int from_to[] = { 0,0, 1,1, 2,2 };

    // TODO convert only required images
416 417 418
    std::vector<Mat> src_lab(src_imgs_size);
    std::vector<Mat> l(src_imgs_size);
    std::vector<Mat> ab(src_imgs_size);
Ilya Lavrenov's avatar
Ilya Lavrenov committed
419 420
    for (int i = 0; i < src_imgs_size; i++)
    {
421 422 423
        src_lab[i] = Mat::zeros(srcImgs[0].size(), type);
        l[i] = Mat::zeros(srcImgs[0].size(), CV_MAKE_TYPE(depth, 1));
        ab[i] = Mat::zeros(srcImgs[0].size(), CV_MAKE_TYPE(depth, 2));
424
        cvtColor(srcImgs[i], src_lab[i], COLOR_LBGR2Lab);
425

426 427 428
        Mat l_ab[] = { l[i], ab[i] };
        mixChannels(&src_lab[i], 1, l_ab, 2, from_to, 3);
    }
429

430 431 432 433
    Mat dst_l;
    Mat dst_ab;

    fastNlMeansDenoisingMulti(
434 435
        l, dst_l, imgToDenoiseIndex, temporalWindowSize,
        h, templateWindowSize, searchWindowSize);
436 437

    fastNlMeansDenoisingMulti(
438 439
        ab, dst_ab, imgToDenoiseIndex, temporalWindowSize,
        hForColorComponents, templateWindowSize, searchWindowSize);
440 441 442 443 444

    Mat l_ab_denoised[] = { dst_l, dst_ab };
    Mat dst_lab(srcImgs[0].size(), srcImgs[0].type());
    mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3);

445
    cvtColor(dst_lab, dst, COLOR_Lab2LBGR);
446
}