1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 #include "test_precomp.hpp"
5 
6 namespace opencv_test { namespace {
7 
getOpenCVExtraDir()8 static std::string getOpenCVExtraDir()
9 {
10     return cvtest::TS::ptr()->get_data_path();
11 }
12 
checkSimilarity(InputArray src,InputArray ref)13 static void checkSimilarity(InputArray src, InputArray ref)
14 {
15     // Doesn't work with bilateral filter: EXPECT_LE(cvtest::norm(src, ref, NORM_INF), 1.0);
16     EXPECT_LE(cvtest::norm(src, ref, NORM_L2 | NORM_RELATIVE), 1e-3);
17 }
18 
convertTypeAndSize(Mat src,int dstType,Size dstSize)19 static Mat convertTypeAndSize(Mat src, int dstType, Size dstSize)
20 {
21     Mat dst;
22     int srcCnNum = src.channels();
23     int dstCnNum = CV_MAT_CN(dstType);
24 
25     if (srcCnNum == dstCnNum)
26     {
27         src.copyTo(dst);
28     }
29     else if (srcCnNum == 3 && dstCnNum == 1)
30     {
31         cvtColor(src, dst, COLOR_BGR2GRAY);
32     }
33     else if (srcCnNum == 1 && dstCnNum == 3)
34     {
35         cvtColor(src, dst, COLOR_GRAY2BGR);
36     }
37     else
38     {
39         CV_Error(Error::BadNumChannels, "Bad num channels in src");
40     }
41 
42     dst.convertTo(dst, dstType);
43     resize(dst, dst, dstSize, 0, 0, INTER_LINEAR_EXACT);
44 
45     return dst;
46 }
47 
48 //////////////////////////////////////////////////////////////////////////
49 //////////////////////////////////////////////////////////////////////////
50 
51 typedef tuple<double, MatType, int> RGFParams;
52 typedef TestWithParam<RGFParams> RollingGuidanceFilterTest;
53 
TEST_P(RollingGuidanceFilterTest,SplatSurfaceAccuracy)54 TEST_P(RollingGuidanceFilterTest, SplatSurfaceAccuracy)
55 {
56     RGFParams params = GetParam();
57     double sigmaS   = get<0>(params);
58     int depth       = get<1>(params);
59     int srcCn       = get<2>(params);
60 
61     RNG rnd(0);
62 
63     Size sz(rnd.uniform(512,1024), rnd.uniform(512,1024));
64 
65     for (int i = 0; i < 5; i++)
66     {
67         Scalar surfaceValue;
68         rnd.fill(surfaceValue, RNG::UNIFORM, 0, 255);
69         Mat src(sz, CV_MAKE_TYPE(depth, srcCn), surfaceValue);
70 
71         double sigmaC = rnd.uniform(1.0, 255.0);
72 	int iterNum = int(rnd.uniform(1.0, 5.0));
73 
74         Mat res;
75         rollingGuidanceFilter(src, res, -1, sigmaC, sigmaS, iterNum);
76 
77         double normL1 = cvtest::norm(src, res, NORM_L1)/src.total()/src.channels();
78         EXPECT_LE(normL1, 1.0/64);
79     }
80 }
81 
TEST_P(RollingGuidanceFilterTest,MultiThreadReproducibility)82 TEST_P(RollingGuidanceFilterTest, MultiThreadReproducibility)
83 {
84     if (cv::getNumberOfCPUs() == 1)
85         return;
86 
87     RGFParams params = GetParam();
88     double sigmaS   = get<0>(params);
89     int depth       = get<1>(params);
90     int srcCn       = get<2>(params);
91 
92     double MAX_DIF = 1.0;
93     double MAX_MEAN_DIF = 1.0 / 64.0;
94     int loopsCount = 2;
95     RNG rnd(1);
96 
97     Size sz(rnd.uniform(512,1024), rnd.uniform(512,1024));
98 
99     Mat src(sz,CV_MAKE_TYPE(depth, srcCn));
100     if(src.depth()==CV_8U)
101         randu(src, 0, 255);
102     else if(src.depth()==CV_16S)
103         randu(src, -32767, 32767);
104     else
105         randu(src, -100000.0f, 100000.0f);
106 
107     int nThreads = cv::getNumThreads();
108     if (nThreads == 1)
109         throw SkipTestException("Single thread environment");
110     for (int iter = 0; iter <= loopsCount; iter++)
111     {
112         int iterNum = int(rnd.uniform(1.0, 5.0));
113         double sigmaC = rnd.uniform(1.0, 255.0);
114 
115         cv::setNumThreads(nThreads);
116         Mat resMultiThread;
117         rollingGuidanceFilter(src, resMultiThread, -1, sigmaC, sigmaS, iterNum);
118 
119         cv::setNumThreads(1);
120         Mat resSingleThread;
121         rollingGuidanceFilter(src, resSingleThread, -1, sigmaC, sigmaS, iterNum);
122 
123         EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_INF), MAX_DIF);
124         EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_L1), MAX_MEAN_DIF*src.total()*src.channels());
125     }
126 }
127 
128 INSTANTIATE_TEST_CASE_P(TypicalSet1, RollingGuidanceFilterTest,
129     Combine(
130     Values(2.0, 5.0),
131     Values(CV_8U, CV_32F),
132     Values(1, 3)
133     )
134 );
135 
136 //////////////////////////////////////////////////////////////////////////
137 //////////////////////////////////////////////////////////////////////////
138 
139 typedef tuple<double, string, int> RGFBFParam;
140 typedef TestWithParam<RGFBFParam> RollingGuidanceFilterTest_BilateralRef;
141 
TEST_P(RollingGuidanceFilterTest_BilateralRef,Accuracy)142 TEST_P(RollingGuidanceFilterTest_BilateralRef, Accuracy)
143 {
144     RGFBFParam params = GetParam();
145     double sigmaS       = get<0>(params);
146     string srcPath      = get<1>(params);
147     int srcType         = get<2>(params);
148 
149     Mat src = imread(getOpenCVExtraDir() + srcPath);
150     ASSERT_TRUE(!src.empty());
151     src = convertTypeAndSize(src, srcType, src.size());
152 
153     RNG rnd(0);
154     double sigmaC = rnd.uniform(0.0, 255.0);
155 
156     Mat resRef;
157     bilateralFilter(src, resRef, 0, sigmaC, sigmaS);
158 
159     Mat res, joint = src.clone();
160     rollingGuidanceFilter(src, res, 0, sigmaC, sigmaS, 1);
161 
162     checkSimilarity(res, resRef);
163 }
164 
165 INSTANTIATE_TEST_CASE_P(TypicalSet2, RollingGuidanceFilterTest_BilateralRef,
166     Combine(
167     Values(4.0, 6.0, 8.0),
168     Values("/cv/shared/pic2.png", "/cv/shared/lena.png", "cv/shared/box_in_scene.png"),
169     Values(CV_8UC1, CV_8UC3, CV_32FC1, CV_32FC3)
170     )
171 );
172 
173 
174 }} // namespace
175