465 lines
19 KiB
C++
465 lines
19 KiB
C++
/*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
|