123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- /*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.
- //
- //
- // License Agreement
- // For Open Source Computer Vision Library
- //
- // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
- // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
- // Third party copyrights are property of their respective owners.
- //
- // 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 the copyright holders 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 "test_precomp.hpp"
- //#define DUMP_RESULTS
- //#define TEST_TRANSFORMS
- #ifdef TEST_TRANSFORMS
- #include "..\..\xphoto\src\bm3d_denoising_invoker_commons.hpp"
- #include "..\..\xphoto\src\bm3d_denoising_transforms.hpp"
- #include "..\..\xphoto\src\kaiser_window.hpp"
- using namespace cv::xphoto;
- #endif
- #ifdef DUMP_RESULTS
- # define DUMP(image, path) imwrite(path, image)
- #else
- # define DUMP(image, path)
- #endif
- #ifdef OPENCV_ENABLE_NONFREE
- namespace opencv_test { namespace {
- TEST(xphoto_DenoisingBm3dGrayscale, regression_L2)
- {
- std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
- std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
- std::string expected_path = folder + "lena_noised_denoised_bm3d_wiener_grayscale_l2_tw=4_sw=16_h=10_bm=400.png";
- cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
- cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
- ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
- ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path;
- // BM3D: two different calls doing exactly the same thing
- cv::Mat result, resultSec;
- cv::xphoto::bm3dDenoising(original, noArray(), resultSec, 10, 4, 16, 2500, 400, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEPALL);
- cv::xphoto::bm3dDenoising(original, result, 10, 4, 16, 2500, 400, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEPALL);
- DUMP(result, expected_path + ".res.png");
- ASSERT_EQ(cvtest::norm(result, resultSec, cv::NORM_L2), 0);
- ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
- }
- TEST(xphoto_DenoisingBm3dGrayscale, regression_L2_separate)
- {
- std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
- std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
- std::string expected_basic_path = folder + "lena_noised_denoised_bm3d_grayscale_l2_tw=4_sw=16_h=10_bm=2500.png";
- std::string expected_path = folder + "lena_noised_denoised_bm3d_wiener_grayscale_l2_tw=4_sw=16_h=10_bm=400.png";
- cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
- cv::Mat expected_basic = cv::imread(expected_basic_path, cv::IMREAD_GRAYSCALE);
- cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
- ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
- ASSERT_FALSE(expected_basic.empty()) << "Could not load reference image " << expected_basic_path;
- ASSERT_FALSE(expected.empty()) << "Could not load input image " << expected_path;
- cv::Mat basic, result;
- // BM3D step 1
- cv::xphoto::bm3dDenoising(original, basic, 10, 4, 16, 2500, -1, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEP1);
- ASSERT_LT(cvtest::norm(basic, expected_basic, cv::NORM_L2), 200);
- DUMP(basic, expected_basic_path + ".res.basic.png");
- // BM3D step 2
- cv::xphoto::bm3dDenoising(original, basic, result, 10, 4, 16, 2500, 400, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEP2);
- ASSERT_LT(cvtest::norm(basic, expected_basic, cv::NORM_L2), 200);
- DUMP(basic, expected_basic_path + ".res.basic2.png");
- DUMP(result, expected_path + ".res.png");
- ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
- }
- TEST(xphoto_DenoisingBm3dGrayscale, regression_L1)
- {
- std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
- std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
- std::string expected_path = folder + "lena_noised_denoised_bm3d_grayscale_l1_tw=4_sw=16_h=10_bm=2500.png";
- cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
- cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
- ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
- ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path;
- cv::Mat result;
- cv::xphoto::bm3dDenoising(original, result, 10, 4, 16, 2500, -1, 8, 1, 0.0f, cv::NORM_L1, cv::xphoto::BM3D_STEP1);
- DUMP(result, expected_path + ".res.png");
- ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
- }
- TEST(xphoto_DenoisingBm3dGrayscale, regression_L2_8x8)
- {
- std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
- std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
- std::string expected_path = folder + "lena_noised_denoised_bm3d_grayscale_l2_tw=8_sw=16_h=10_bm=2500.png";
- cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
- cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
- ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
- ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path;
- cv::Mat result;
- cv::xphoto::bm3dDenoising(original, result, 10, 8, 16, 2500, -1, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEP1);
- DUMP(result, expected_path + ".res.png");
- ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
- }
- #ifdef TEST_TRANSFORMS
- TEST(xphoto_DenoisingBm3dKaiserWindow, regression_4)
- {
- float beta = 2.0f;
- int N = 4;
- cv::Mat kaiserWindow;
- calcKaiserWindow1D(kaiserWindow, N, beta);
- float kaiser4[] = {
- 0.43869004f,
- 0.92432547f,
- 0.92432547f,
- 0.43869004f
- };
- for (int i = 0; i < N; ++i)
- ASSERT_FLOAT_EQ(kaiser4[i], kaiserWindow.at<float>(i));
- }
- TEST(xphoto_DenoisingBm3dKaiserWindow, regression_8)
- {
- float beta = 2.0f;
- int N = 8;
- cv::Mat kaiserWindow;
- calcKaiserWindow1D(kaiserWindow, N, beta);
- float kaiser8[] = {
- 0.43869004f,
- 0.68134475f,
- 0.87685609f,
- 0.98582518f,
- 0.98582518f,
- 0.87685609f,
- 0.68134463f,
- 0.43869004f
- };
- for (int i = 0; i < N; ++i)
- ASSERT_FLOAT_EQ(kaiser8[i], kaiserWindow.at<float>(i));
- }
- TEST(xphoto_DenoisingBm3dTransforms, regression_2D_generic)
- {
- const int templateWindowSize = 8;
- const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
- uchar src[templateWindowSizeSq];
- short dst[templateWindowSizeSq];
- short dstSec[templateWindowSizeSq];
- // Initialize array
- for (uchar i = 0; i < templateWindowSizeSq; ++i)
- src[i] = (i % 10) * 10;
- // Use tailored transforms
- HaarTransform<uchar, short>::RegisterTransforms2D(templateWindowSize);
- HaarTransform<uchar, short>::forwardTransform2D(src, dst, templateWindowSize, templateWindowSize);
- HaarTransform<uchar, short>::inverseTransform2D(dst, templateWindowSize);
- // Use generic transforms
- HaarTransform2D::ForwardTransformXxX<uchar, short, templateWindowSize>(src, dstSec, templateWindowSize, templateWindowSize);
- HaarTransform2D::InverseTransformXxX<short, templateWindowSize>(dstSec, templateWindowSize);
- for (unsigned i = 0; i < templateWindowSizeSq; ++i)
- ASSERT_EQ(dst[i], dstSec[i]);
- }
- TEST(xphoto_DenoisingBm3dTransforms, regression_2D_4x4)
- {
- const int templateWindowSize = 4;
- const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
- uchar src[templateWindowSizeSq];
- short dst[templateWindowSizeSq];
- // Initialize array
- for (uchar i = 0; i < templateWindowSizeSq; ++i)
- {
- src[i] = i;
- }
- HaarTransform2D::ForwardTransform4x4(src, dst, templateWindowSize, templateWindowSize);
- HaarTransform2D::InverseTransform4x4(dst, templateWindowSize);
- for (uchar i = 0; i < templateWindowSizeSq; ++i)
- ASSERT_EQ(static_cast<short>(src[i]), dst[i]);
- }
- TEST(xphoto_DenoisingBm3dTransforms, regression_2D_8x8)
- {
- const int templateWindowSize = 8;
- const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
- uchar src[templateWindowSizeSq];
- short dst[templateWindowSizeSq];
- // Initialize array
- for (uchar i = 0; i < templateWindowSizeSq; ++i)
- {
- src[i] = i;
- }
- HaarTransform2D::ForwardTransform8x8(src, dst, templateWindowSize, templateWindowSize);
- HaarTransform2D::InverseTransform8x8(dst, templateWindowSize);
- for (uchar i = 0; i < templateWindowSizeSq; ++i)
- ASSERT_EQ(static_cast<short>(src[i]), dst[i]);
- }
- template <typename T, typename DT, typename CT>
- static void Test1dTransform(
- T *thrMap,
- int groupSize,
- int templateWindowSizeSq,
- BlockMatch<T, DT, CT> *bm,
- BlockMatch<T, DT, CT> *bmOrig,
- int expectedNonZeroCount = -1)
- {
- if (expectedNonZeroCount < 0)
- expectedNonZeroCount = groupSize * templateWindowSizeSq;
- // Test group size
- short sumNonZero = 0;
- T *thrMapPtr1D = thrMap + (groupSize - 1) * templateWindowSizeSq;
- for (int n = 0; n < templateWindowSizeSq; n++)
- {
- switch (groupSize)
- {
- case 16:
- HaarTransform1D::ForwardTransform16(bm, n);
- sumNonZero += HardThreshold<16>(bm, n, thrMapPtr1D);
- HaarTransform1D::InverseTransform16(bm, n);
- break;
- case 8:
- HaarTransform1D::ForwardTransform8(bm, n);
- sumNonZero += HardThreshold<8>(bm, n, thrMapPtr1D);
- HaarTransform1D::InverseTransform8(bm, n);
- break;
- case 4:
- HaarTransform1D::ForwardTransform4(bm, n);
- sumNonZero += HardThreshold<4>(bm, n, thrMapPtr1D);
- HaarTransform1D::InverseTransform4(bm, n);
- break;
- case 2:
- HaarTransform1D::ForwardTransform2(bm, n);
- sumNonZero += HardThreshold<2>(bm, n, thrMapPtr1D);
- HaarTransform1D::InverseTransform2(bm, n);
- break;
- default:
- HaarTransform1D::ForwardTransformN(bm, n, groupSize);
- sumNonZero += HardThreshold(bm, n, thrMapPtr1D, groupSize);
- HaarTransform1D::InverseTransformN(bm, n, groupSize);
- }
- }
- // Assert transform
- if (expectedNonZeroCount == groupSize * templateWindowSizeSq)
- {
- for (int i = 0; i < groupSize; ++i)
- for (int j = 0; j < templateWindowSizeSq; ++j)
- ASSERT_EQ(bm[i][j], bmOrig[i][j]);
- }
- // Assert shrinkage
- ASSERT_EQ(sumNonZero, expectedNonZeroCount);
- }
- TEST(xphoto_DenoisingBm3dTransforms, regression_1D_transform)
- {
- const int templateWindowSize = 4;
- const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
- const int searchWindowSize = 16;
- const int searchWindowSizeSq = searchWindowSize * searchWindowSize;
- const float h = 10;
- int maxGroupSize = 64;
- // Precompute separate maps for transform and shrinkage verification
- short *thrMapTransform = NULL;
- short *thrMapShrinkage = NULL;
- HaarTransform<short, short>::calcThresholdMap3D(thrMapTransform, 0, templateWindowSize, maxGroupSize);
- HaarTransform<short, short>::calcThresholdMap3D(thrMapShrinkage, h, templateWindowSize, maxGroupSize);
- // Generate some data
- BlockMatch<short, int, short> *bm = new BlockMatch<short, int, short>[maxGroupSize];
- BlockMatch<short, int, short> *bmOrig = new BlockMatch<short, int, short>[maxGroupSize];
- for (int i = 0; i < maxGroupSize; ++i)
- {
- bm[i].init(templateWindowSizeSq);
- bmOrig[i].init(templateWindowSizeSq);
- }
- for (short i = 0; i < maxGroupSize; ++i)
- {
- for (short j = 0; j < templateWindowSizeSq; ++j)
- {
- bm[i][j] = (j + 1);
- bmOrig[i][j] = bm[i][j];
- }
- }
- // Verify transforms
- Test1dTransform<short, int, short>(thrMapTransform, 2, templateWindowSizeSq, bm, bmOrig);
- Test1dTransform<short, int, short>(thrMapTransform, 4, templateWindowSizeSq, bm, bmOrig);
- Test1dTransform<short, int, short>(thrMapTransform, 8, templateWindowSizeSq, bm, bmOrig);
- Test1dTransform<short, int, short>(thrMapTransform, 16, templateWindowSizeSq, bm, bmOrig);
- Test1dTransform<short, int, short>(thrMapTransform, 32, templateWindowSizeSq, bm, bmOrig);
- Test1dTransform<short, int, short>(thrMapTransform, 64, templateWindowSizeSq, bm, bmOrig);
- // Verify shrinkage
- Test1dTransform<short, int, short>(thrMapShrinkage, 2, templateWindowSizeSq, bm, bmOrig, 6);
- Test1dTransform<short, int, short>(thrMapShrinkage, 4, templateWindowSizeSq, bm, bmOrig, 6);
- Test1dTransform<short, int, short>(thrMapShrinkage, 8, templateWindowSizeSq, bm, bmOrig, 6);
- Test1dTransform<short, int, short>(thrMapShrinkage, 16, templateWindowSizeSq, bm, bmOrig, 6);
- Test1dTransform<short, int, short>(thrMapShrinkage, 32, templateWindowSizeSq, bm, bmOrig, 6);
- Test1dTransform<short, int, short>(thrMapShrinkage, 64, templateWindowSizeSq, bm, bmOrig, 14);
- }
- const float sqrt2 = std::sqrt(2.0f);
- TEST(xphoto_DenoisingBm3dTransforms, regression_1D_generate)
- {
- const int numberOfElements = 8;
- const int arrSize = (numberOfElements << 1) - 1;
- float *thrMap1D = NULL;
- HaarTransform<short, short>::calcThresholdMap1D(thrMap1D, numberOfElements);
- // Expected array
- const float kThrMap1D[arrSize] = {
- 1.0f, // 1 element
- sqrt2 / 2.0f, sqrt2, // 2 elements
- 0.5f, 1.0f, sqrt2, sqrt2, // 4 elements
- sqrt2 / 4.0f, sqrt2 / 2.0f, 1.0f, 1.0f, sqrt2, sqrt2, sqrt2, sqrt2 // 8 elements
- };
- for (int j = 0; j < arrSize; ++j)
- ASSERT_EQ(thrMap1D[j], kThrMap1D[j]);
- delete[] thrMap1D;
- }
- TEST(xphoto_DenoisingBm3dTransforms, regression_2D_generate_4x4)
- {
- const int templateWindowSize = 4;
- float *thrMap2D = NULL;
- HaarTransform<short, short>::calcThresholdMap2D(thrMap2D, templateWindowSize);
- // Expected array
- const float kThrMap4x4[templateWindowSize * templateWindowSize] = {
- 0.25f, 0.5f, sqrt2 / 2.0f, sqrt2 / 2.0f,
- 0.5f, 1.0f, sqrt2, sqrt2,
- sqrt2 / 2.0f, sqrt2, 2.0f, 2.0f,
- sqrt2 / 2.0f, sqrt2, 2.0f, 2.0f
- };
- for (int j = 0; j < templateWindowSize * templateWindowSize; ++j)
- ASSERT_EQ(thrMap2D[j], kThrMap4x4[j]);
- delete[] thrMap2D;
- }
- TEST(xphoto_DenoisingBm3dTransforms, regression_2D_generate_8x8)
- {
- const int templateWindowSize = 8;
- float *thrMap2D = NULL;
- HaarTransform<short, short>::calcThresholdMap2D(thrMap2D, templateWindowSize);
- // Expected array
- const float kThrMap8x8[templateWindowSize * templateWindowSize] = {
- 0.125f, 0.25f, sqrt2 / 4.0f, sqrt2 / 4.0f, 0.5f, 0.5f, 0.5f, 0.5f,
- 0.25f, 0.5f, sqrt2 / 2.0f, sqrt2 / 2.0f, 1.0f, 1.0f, 1.0f, 1.0f,
- sqrt2 / 4.0f, sqrt2 / 2.0f, 1.0f, 1.0f, sqrt2, sqrt2, sqrt2, sqrt2,
- sqrt2 / 4.0f, sqrt2 / 2.0f, 1.0f, 1.0f, sqrt2, sqrt2, sqrt2, sqrt2,
- 0.5f, 1.0f, sqrt2, sqrt2, 2.0f, 2.0f, 2.0f, 2.0f,
- 0.5f, 1.0f, sqrt2, sqrt2, 2.0f, 2.0f, 2.0f, 2.0f,
- 0.5f, 1.0f, sqrt2, sqrt2, 2.0f, 2.0f, 2.0f, 2.0f,
- 0.5f, 1.0f, sqrt2, sqrt2, 2.0f, 2.0f, 2.0f, 2.0f
- };
- for (int j = 0; j < templateWindowSize * templateWindowSize; ++j)
- ASSERT_EQ(thrMap2D[j], kThrMap8x8[j]);
- delete[] thrMap2D;
- }
- TEST(xphoto_Bm3dDenoising, powerOf2)
- {
- ASSERT_EQ(8, getLargestPowerOf2SmallerThan(9));
- ASSERT_EQ(16, getLargestPowerOf2SmallerThan(21));
- ASSERT_EQ(4, getLargestPowerOf2SmallerThan(7));
- ASSERT_EQ(8, getLargestPowerOf2SmallerThan(8));
- ASSERT_EQ(4, getLargestPowerOf2SmallerThan(5));
- ASSERT_EQ(4, getLargestPowerOf2SmallerThan(4));
- ASSERT_EQ(2, getLargestPowerOf2SmallerThan(3));
- ASSERT_EQ(1, getLargestPowerOf2SmallerThan(1));
- ASSERT_EQ(0, getLargestPowerOf2SmallerThan(0));
- }
- #endif // TEST_TRANSFORMS
- }} // namespace
- #endif // OPENCV_ENABLE_NONFREE
|