• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2018, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include <limits.h>
13 #include <math.h>
14 #include <algorithm>
15 #include <vector>
16 
17 #include "aom_dsp/noise_model.h"
18 #include "aom_dsp/noise_util.h"
19 #include "config/aom_dsp_rtcd.h"
20 #include "test/acm_random.h"
21 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
22 
23 namespace {
24 
25 // Return normally distrbuted values with standard deviation of sigma.
randn(libaom_test::ACMRandom * random,double sigma)26 double randn(libaom_test::ACMRandom *random, double sigma) {
27   while (1) {
28     const double u = 2.0 * ((double)random->Rand31() /
29                             testing::internal::Random::kMaxRange) -
30                      1.0;
31     const double v = 2.0 * ((double)random->Rand31() /
32                             testing::internal::Random::kMaxRange) -
33                      1.0;
34     const double s = u * u + v * v;
35     if (s > 0 && s < 1) {
36       return sigma * (u * sqrt(-2.0 * log(s) / s));
37     }
38   }
39   return 0;
40 }
41 
42 // Synthesizes noise using the auto-regressive filter of the given lag,
43 // with the provided n coefficients sampled at the given coords.
noise_synth(libaom_test::ACMRandom * random,int lag,int n,const int (* coords)[2],const double * coeffs,double * data,int w,int h)44 void noise_synth(libaom_test::ACMRandom *random, int lag, int n,
45                  const int (*coords)[2], const double *coeffs, double *data,
46                  int w, int h) {
47   const int pad_size = 3 * lag;
48   const int padded_w = w + pad_size;
49   const int padded_h = h + pad_size;
50   int x = 0, y = 0;
51   std::vector<double> padded(padded_w * padded_h);
52 
53   for (y = 0; y < padded_h; ++y) {
54     for (x = 0; x < padded_w; ++x) {
55       padded[y * padded_w + x] = randn(random, 1.0);
56     }
57   }
58   for (y = lag; y < padded_h; ++y) {
59     for (x = lag; x < padded_w; ++x) {
60       double sum = 0;
61       int i = 0;
62       for (i = 0; i < n; ++i) {
63         const int dx = coords[i][0];
64         const int dy = coords[i][1];
65         sum += padded[(y + dy) * padded_w + (x + dx)] * coeffs[i];
66       }
67       padded[y * padded_w + x] += sum;
68     }
69   }
70   // Copy over the padded rows to the output
71   for (y = 0; y < h; ++y) {
72     memcpy(data + y * w, &padded[0] + y * padded_w, sizeof(*data) * w);
73   }
74 }
75 
get_noise_psd(double * noise,int width,int height,int block_size)76 std::vector<float> get_noise_psd(double *noise, int width, int height,
77                                  int block_size) {
78   float *block =
79       (float *)aom_memalign(32, block_size * block_size * sizeof(block));
80   std::vector<float> psd(block_size * block_size);
81   if (block == nullptr) {
82     EXPECT_NE(block, nullptr);
83     return psd;
84   }
85   int num_blocks = 0;
86   struct aom_noise_tx_t *tx = aom_noise_tx_malloc(block_size);
87   if (tx == nullptr) {
88     EXPECT_NE(tx, nullptr);
89     return psd;
90   }
91   for (int y = 0; y <= height - block_size; y += block_size / 2) {
92     for (int x = 0; x <= width - block_size; x += block_size / 2) {
93       for (int yy = 0; yy < block_size; ++yy) {
94         for (int xx = 0; xx < block_size; ++xx) {
95           block[yy * block_size + xx] = (float)noise[(y + yy) * width + x + xx];
96         }
97       }
98       aom_noise_tx_forward(tx, &block[0]);
99       aom_noise_tx_add_energy(tx, &psd[0]);
100       num_blocks++;
101     }
102   }
103   for (int yy = 0; yy < block_size; ++yy) {
104     for (int xx = 0; xx <= block_size / 2; ++xx) {
105       psd[yy * block_size + xx] /= num_blocks;
106     }
107   }
108   // Fill in the data that is missing due to symmetries
109   for (int xx = 1; xx < block_size / 2; ++xx) {
110     psd[(block_size - xx)] = psd[xx];
111   }
112   for (int yy = 1; yy < block_size; ++yy) {
113     for (int xx = 1; xx < block_size / 2; ++xx) {
114       psd[(block_size - yy) * block_size + (block_size - xx)] =
115           psd[yy * block_size + xx];
116     }
117   }
118   aom_noise_tx_free(tx);
119   aom_free(block);
120   return psd;
121 }
122 
123 }  // namespace
124 
TEST(NoiseStrengthSolver,GetCentersTwoBins)125 TEST(NoiseStrengthSolver, GetCentersTwoBins) {
126   aom_noise_strength_solver_t solver;
127   aom_noise_strength_solver_init(&solver, 2, 8);
128   EXPECT_NEAR(0, aom_noise_strength_solver_get_center(&solver, 0), 1e-5);
129   EXPECT_NEAR(255, aom_noise_strength_solver_get_center(&solver, 1), 1e-5);
130   aom_noise_strength_solver_free(&solver);
131 }
132 
TEST(NoiseStrengthSolver,GetCentersTwoBins10bit)133 TEST(NoiseStrengthSolver, GetCentersTwoBins10bit) {
134   aom_noise_strength_solver_t solver;
135   aom_noise_strength_solver_init(&solver, 2, 10);
136   EXPECT_NEAR(0, aom_noise_strength_solver_get_center(&solver, 0), 1e-5);
137   EXPECT_NEAR(1023, aom_noise_strength_solver_get_center(&solver, 1), 1e-5);
138   aom_noise_strength_solver_free(&solver);
139 }
140 
TEST(NoiseStrengthSolver,GetCenters256Bins)141 TEST(NoiseStrengthSolver, GetCenters256Bins) {
142   const int num_bins = 256;
143   aom_noise_strength_solver_t solver;
144   aom_noise_strength_solver_init(&solver, num_bins, 8);
145 
146   for (int i = 0; i < 256; ++i) {
147     EXPECT_NEAR(i, aom_noise_strength_solver_get_center(&solver, i), 1e-5);
148   }
149   aom_noise_strength_solver_free(&solver);
150 }
151 
152 // Tests that the noise strength solver returns the identity transform when
153 // given identity-like constraints.
TEST(NoiseStrengthSolver,ObserveIdentity)154 TEST(NoiseStrengthSolver, ObserveIdentity) {
155   const int num_bins = 256;
156   aom_noise_strength_solver_t solver;
157   ASSERT_EQ(1, aom_noise_strength_solver_init(&solver, num_bins, 8));
158 
159   // We have to add a big more strength to constraints at the boundary to
160   // overcome any regularization.
161   for (int j = 0; j < 5; ++j) {
162     aom_noise_strength_solver_add_measurement(&solver, 0, 0);
163     aom_noise_strength_solver_add_measurement(&solver, 255, 255);
164   }
165   for (int i = 0; i < 256; ++i) {
166     aom_noise_strength_solver_add_measurement(&solver, i, i);
167   }
168   EXPECT_EQ(1, aom_noise_strength_solver_solve(&solver));
169   for (int i = 2; i < num_bins - 2; ++i) {
170     EXPECT_NEAR(i, solver.eqns.x[i], 0.1);
171   }
172 
173   aom_noise_strength_lut_t lut;
174   EXPECT_EQ(1, aom_noise_strength_solver_fit_piecewise(&solver, 2, &lut));
175 
176   ASSERT_EQ(2, lut.num_points);
177   EXPECT_NEAR(0.0, lut.points[0][0], 1e-5);
178   EXPECT_NEAR(0.0, lut.points[0][1], 0.5);
179   EXPECT_NEAR(255.0, lut.points[1][0], 1e-5);
180   EXPECT_NEAR(255.0, lut.points[1][1], 0.5);
181 
182   aom_noise_strength_lut_free(&lut);
183   aom_noise_strength_solver_free(&solver);
184 }
185 
TEST(NoiseStrengthSolver,SimplifiesCurve)186 TEST(NoiseStrengthSolver, SimplifiesCurve) {
187   const int num_bins = 256;
188   aom_noise_strength_solver_t solver;
189   EXPECT_EQ(1, aom_noise_strength_solver_init(&solver, num_bins, 8));
190 
191   // Create a parabolic input
192   for (int i = 0; i < 256; ++i) {
193     const double x = (i - 127.5) / 63.5;
194     aom_noise_strength_solver_add_measurement(&solver, i, x * x);
195   }
196   EXPECT_EQ(1, aom_noise_strength_solver_solve(&solver));
197 
198   // First try to fit an unconstrained lut
199   aom_noise_strength_lut_t lut;
200   EXPECT_EQ(1, aom_noise_strength_solver_fit_piecewise(&solver, -1, &lut));
201   ASSERT_LE(20, lut.num_points);
202   aom_noise_strength_lut_free(&lut);
203 
204   // Now constrain the maximum number of points
205   const int kMaxPoints = 9;
206   EXPECT_EQ(1,
207             aom_noise_strength_solver_fit_piecewise(&solver, kMaxPoints, &lut));
208   ASSERT_EQ(kMaxPoints, lut.num_points);
209 
210   // Check that the input parabola is still well represented
211   EXPECT_NEAR(0.0, lut.points[0][0], 1e-5);
212   EXPECT_NEAR(4.0, lut.points[0][1], 0.1);
213   for (int i = 1; i < lut.num_points - 1; ++i) {
214     const double x = (lut.points[i][0] - 128.) / 64.;
215     EXPECT_NEAR(x * x, lut.points[i][1], 0.1);
216   }
217   EXPECT_NEAR(255.0, lut.points[kMaxPoints - 1][0], 1e-5);
218 
219   EXPECT_NEAR(4.0, lut.points[kMaxPoints - 1][1], 0.1);
220   aom_noise_strength_lut_free(&lut);
221   aom_noise_strength_solver_free(&solver);
222 }
223 
TEST(NoiseStrengthLut,LutInitNegativeOrZeroSize)224 TEST(NoiseStrengthLut, LutInitNegativeOrZeroSize) {
225   aom_noise_strength_lut_t lut;
226   ASSERT_FALSE(aom_noise_strength_lut_init(&lut, -1));
227   ASSERT_FALSE(aom_noise_strength_lut_init(&lut, 0));
228 }
229 
TEST(NoiseStrengthLut,LutEvalSinglePoint)230 TEST(NoiseStrengthLut, LutEvalSinglePoint) {
231   aom_noise_strength_lut_t lut;
232   ASSERT_TRUE(aom_noise_strength_lut_init(&lut, 1));
233   ASSERT_EQ(1, lut.num_points);
234   lut.points[0][0] = 0;
235   lut.points[0][1] = 1;
236   EXPECT_EQ(1, aom_noise_strength_lut_eval(&lut, -1));
237   EXPECT_EQ(1, aom_noise_strength_lut_eval(&lut, 0));
238   EXPECT_EQ(1, aom_noise_strength_lut_eval(&lut, 1));
239   aom_noise_strength_lut_free(&lut);
240 }
241 
TEST(NoiseStrengthLut,LutEvalMultiPointInterp)242 TEST(NoiseStrengthLut, LutEvalMultiPointInterp) {
243   const double kEps = 1e-5;
244   aom_noise_strength_lut_t lut;
245   ASSERT_TRUE(aom_noise_strength_lut_init(&lut, 4));
246   ASSERT_EQ(4, lut.num_points);
247 
248   lut.points[0][0] = 0;
249   lut.points[0][1] = 0;
250 
251   lut.points[1][0] = 1;
252   lut.points[1][1] = 1;
253 
254   lut.points[2][0] = 2;
255   lut.points[2][1] = 1;
256 
257   lut.points[3][0] = 100;
258   lut.points[3][1] = 1001;
259 
260   // Test lower boundary
261   EXPECT_EQ(0, aom_noise_strength_lut_eval(&lut, -1));
262   EXPECT_EQ(0, aom_noise_strength_lut_eval(&lut, 0));
263 
264   // Test first part that should be identity
265   EXPECT_NEAR(0.25, aom_noise_strength_lut_eval(&lut, 0.25), kEps);
266   EXPECT_NEAR(0.75, aom_noise_strength_lut_eval(&lut, 0.75), kEps);
267 
268   // This is a constant section (should evaluate to 1)
269   EXPECT_NEAR(1.0, aom_noise_strength_lut_eval(&lut, 1.25), kEps);
270   EXPECT_NEAR(1.0, aom_noise_strength_lut_eval(&lut, 1.75), kEps);
271 
272   // Test interpolation between to non-zero y coords.
273   EXPECT_NEAR(1, aom_noise_strength_lut_eval(&lut, 2), kEps);
274   EXPECT_NEAR(251, aom_noise_strength_lut_eval(&lut, 26.5), kEps);
275   EXPECT_NEAR(751, aom_noise_strength_lut_eval(&lut, 75.5), kEps);
276 
277   // Test upper boundary
278   EXPECT_EQ(1001, aom_noise_strength_lut_eval(&lut, 100));
279   EXPECT_EQ(1001, aom_noise_strength_lut_eval(&lut, 101));
280 
281   aom_noise_strength_lut_free(&lut);
282 }
283 
TEST(NoiseModel,InitSuccessWithValidSquareShape)284 TEST(NoiseModel, InitSuccessWithValidSquareShape) {
285   aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, 2, 8, 0 };
286   aom_noise_model_t model;
287 
288   EXPECT_TRUE(aom_noise_model_init(&model, params));
289 
290   const int kNumCoords = 12;
291   const int kCoords[][2] = { { -2, -2 }, { -1, -2 }, { 0, -2 },  { 1, -2 },
292                              { 2, -2 },  { -2, -1 }, { -1, -1 }, { 0, -1 },
293                              { 1, -1 },  { 2, -1 },  { -2, 0 },  { -1, 0 } };
294   EXPECT_EQ(kNumCoords, model.n);
295   for (int i = 0; i < kNumCoords; ++i) {
296     const int *coord = kCoords[i];
297     EXPECT_EQ(coord[0], model.coords[i][0]);
298     EXPECT_EQ(coord[1], model.coords[i][1]);
299   }
300   aom_noise_model_free(&model);
301 }
302 
TEST(NoiseModel,InitSuccessWithValidDiamondShape)303 TEST(NoiseModel, InitSuccessWithValidDiamondShape) {
304   aom_noise_model_t model;
305   aom_noise_model_params_t params = { AOM_NOISE_SHAPE_DIAMOND, 2, 8, 0 };
306   EXPECT_TRUE(aom_noise_model_init(&model, params));
307   EXPECT_EQ(6, model.n);
308   const int kNumCoords = 6;
309   const int kCoords[][2] = { { 0, -2 }, { -1, -1 }, { 0, -1 },
310                              { 1, -1 }, { -2, 0 },  { -1, 0 } };
311   EXPECT_EQ(kNumCoords, model.n);
312   for (int i = 0; i < kNumCoords; ++i) {
313     const int *coord = kCoords[i];
314     EXPECT_EQ(coord[0], model.coords[i][0]);
315     EXPECT_EQ(coord[1], model.coords[i][1]);
316   }
317   aom_noise_model_free(&model);
318 }
319 
TEST(NoiseModel,InitFailsWithTooLargeLag)320 TEST(NoiseModel, InitFailsWithTooLargeLag) {
321   aom_noise_model_t model;
322   aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, 10, 8, 0 };
323   EXPECT_FALSE(aom_noise_model_init(&model, params));
324   aom_noise_model_free(&model);
325 }
326 
TEST(NoiseModel,InitFailsWithTooSmallLag)327 TEST(NoiseModel, InitFailsWithTooSmallLag) {
328   aom_noise_model_t model;
329   aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, 0, 8, 0 };
330   EXPECT_FALSE(aom_noise_model_init(&model, params));
331   aom_noise_model_free(&model);
332 }
333 
TEST(NoiseModel,InitFailsWithInvalidShape)334 TEST(NoiseModel, InitFailsWithInvalidShape) {
335   aom_noise_model_t model;
336   aom_noise_model_params_t params = { aom_noise_shape(100), 3, 8, 0 };
337   EXPECT_FALSE(aom_noise_model_init(&model, params));
338   aom_noise_model_free(&model);
339 }
340 
TEST(NoiseModel,InitFailsWithInvalidBitdepth)341 TEST(NoiseModel, InitFailsWithInvalidBitdepth) {
342   aom_noise_model_t model;
343   aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, 2, 8, 0 };
344   for (int i = 0; i <= 32; ++i) {
345     params.bit_depth = i;
346     if (i == 8 || i == 10 || i == 12) {
347       EXPECT_TRUE(aom_noise_model_init(&model, params)) << "bit_depth: " << i;
348       aom_noise_model_free(&model);
349     } else {
350       EXPECT_FALSE(aom_noise_model_init(&model, params)) << "bit_depth: " << i;
351     }
352   }
353   params.bit_depth = INT_MAX;
354   EXPECT_FALSE(aom_noise_model_init(&model, params));
355 }
356 
357 // A container template class to hold a data type and extra arguments.
358 // All of these args are bundled into one struct so that we can use
359 // parameterized tests on combinations of supported data types
360 // (uint8_t and uint16_t) and bit depths (8, 10, 12).
361 template <typename T, int bit_depth, bool use_highbd>
362 struct BitDepthParams {
363   typedef T data_type_t;
364   static const int kBitDepth = bit_depth;
365   static const bool kUseHighBD = use_highbd;
366 };
367 
368 template <typename T>
369 class FlatBlockEstimatorTest : public ::testing::Test, public T {
370  public:
SetUp()371   virtual void SetUp() { random_.Reset(171); }
372   typedef std::vector<typename T::data_type_t> VecType;
373   VecType data_;
374   libaom_test::ACMRandom random_;
375 };
376 
377 TYPED_TEST_SUITE_P(FlatBlockEstimatorTest);
378 
TYPED_TEST_P(FlatBlockEstimatorTest,ExtractBlock)379 TYPED_TEST_P(FlatBlockEstimatorTest, ExtractBlock) {
380   const int kBlockSize = 16;
381   aom_flat_block_finder_t flat_block_finder;
382   ASSERT_EQ(1, aom_flat_block_finder_init(&flat_block_finder, kBlockSize,
383                                           this->kBitDepth, this->kUseHighBD));
384   const double normalization = flat_block_finder.normalization;
385 
386   // Test with an image of more than one block.
387   const int h = 2 * kBlockSize;
388   const int w = 2 * kBlockSize;
389   const int stride = 2 * kBlockSize;
390   this->data_.resize(h * stride, 128);
391 
392   // Set up the (0,0) block to be a plane and the (0,1) block to be a
393   // checkerboard
394   const int shift = this->kBitDepth - 8;
395   for (int y = 0; y < kBlockSize; ++y) {
396     for (int x = 0; x < kBlockSize; ++x) {
397       this->data_[y * stride + x] = (-y + x + 128) << shift;
398       this->data_[y * stride + x + kBlockSize] =
399           ((x % 2 + y % 2) % 2 ? 128 - 20 : 128 + 20) << shift;
400     }
401   }
402   std::vector<double> block(kBlockSize * kBlockSize, 1);
403   std::vector<double> plane(kBlockSize * kBlockSize, 1);
404 
405   // The block data should be a constant (zero) and the rest of the plane
406   // trend is covered in the plane data.
407   aom_flat_block_finder_extract_block(&flat_block_finder,
408                                       (uint8_t *)&this->data_[0], w, h, stride,
409                                       0, 0, &plane[0], &block[0]);
410   for (int y = 0; y < kBlockSize; ++y) {
411     for (int x = 0; x < kBlockSize; ++x) {
412       EXPECT_NEAR(0, block[y * kBlockSize + x], 1e-5);
413       EXPECT_NEAR((double)(this->data_[y * stride + x]) / normalization,
414                   plane[y * kBlockSize + x], 1e-5);
415     }
416   }
417 
418   // The plane trend is a constant, and the block is a zero mean checkerboard.
419   aom_flat_block_finder_extract_block(&flat_block_finder,
420                                       (uint8_t *)&this->data_[0], w, h, stride,
421                                       kBlockSize, 0, &plane[0], &block[0]);
422   const int mid = 128 << shift;
423   for (int y = 0; y < kBlockSize; ++y) {
424     for (int x = 0; x < kBlockSize; ++x) {
425       EXPECT_NEAR(((double)this->data_[y * stride + x + kBlockSize] - mid) /
426                       normalization,
427                   block[y * kBlockSize + x], 1e-5);
428       EXPECT_NEAR(mid / normalization, plane[y * kBlockSize + x], 1e-5);
429     }
430   }
431   aom_flat_block_finder_free(&flat_block_finder);
432 }
433 
TYPED_TEST_P(FlatBlockEstimatorTest,FindFlatBlocks)434 TYPED_TEST_P(FlatBlockEstimatorTest, FindFlatBlocks) {
435   const int kBlockSize = 32;
436   aom_flat_block_finder_t flat_block_finder;
437   ASSERT_EQ(1, aom_flat_block_finder_init(&flat_block_finder, kBlockSize,
438                                           this->kBitDepth, this->kUseHighBD));
439 
440   const int num_blocks_w = 8;
441   const int h = kBlockSize;
442   const int w = kBlockSize * num_blocks_w;
443   const int stride = w;
444   this->data_.resize(h * stride, 128);
445   std::vector<uint8_t> flat_blocks(num_blocks_w, 0);
446 
447   const int shift = this->kBitDepth - 8;
448   for (int y = 0; y < kBlockSize; ++y) {
449     for (int x = 0; x < kBlockSize; ++x) {
450       // Block 0 (not flat): constant doesn't have enough variance to qualify
451       this->data_[y * stride + x + 0 * kBlockSize] = 128 << shift;
452 
453       // Block 1 (not flat): too high of variance is hard to validate as flat
454       this->data_[y * stride + x + 1 * kBlockSize] =
455           ((uint8_t)(128 + randn(&this->random_, 5))) << shift;
456 
457       // Block 2 (flat): slight checkerboard added to constant
458       const int check = (x % 2 + y % 2) % 2 ? -2 : 2;
459       this->data_[y * stride + x + 2 * kBlockSize] = (128 + check) << shift;
460 
461       // Block 3 (flat): planar block with checkerboard pattern is also flat
462       this->data_[y * stride + x + 3 * kBlockSize] =
463           (y * 2 - x / 2 + 128 + check) << shift;
464 
465       // Block 4 (flat): gaussian random with standard deviation 1.
466       this->data_[y * stride + x + 4 * kBlockSize] =
467           ((uint8_t)(randn(&this->random_, 1) + x + 128.0)) << shift;
468 
469       // Block 5 (flat): gaussian random with standard deviation 2.
470       this->data_[y * stride + x + 5 * kBlockSize] =
471           ((uint8_t)(randn(&this->random_, 2) + y + 128.0)) << shift;
472 
473       // Block 6 (not flat): too high of directional gradient.
474       const int strong_edge = x > kBlockSize / 2 ? 64 : 0;
475       this->data_[y * stride + x + 6 * kBlockSize] =
476           ((uint8_t)(randn(&this->random_, 1) + strong_edge + 128.0)) << shift;
477 
478       // Block 7 (not flat): too high gradient.
479       const int big_check = ((x >> 2) % 2 + (y >> 2) % 2) % 2 ? -16 : 16;
480       this->data_[y * stride + x + 7 * kBlockSize] =
481           ((uint8_t)(randn(&this->random_, 1) + big_check + 128.0)) << shift;
482     }
483   }
484 
485   EXPECT_EQ(4, aom_flat_block_finder_run(&flat_block_finder,
486                                          (uint8_t *)&this->data_[0], w, h,
487                                          stride, &flat_blocks[0]));
488 
489   // First two blocks are not flat
490   EXPECT_EQ(0, flat_blocks[0]);
491   EXPECT_EQ(0, flat_blocks[1]);
492 
493   // Next 4 blocks are flat.
494   EXPECT_EQ(255, flat_blocks[2]);
495   EXPECT_EQ(255, flat_blocks[3]);
496   EXPECT_EQ(255, flat_blocks[4]);
497   EXPECT_EQ(255, flat_blocks[5]);
498 
499   // Last 2 are not flat by threshold
500   EXPECT_EQ(0, flat_blocks[6]);
501   EXPECT_EQ(0, flat_blocks[7]);
502 
503   // Add the noise from non-flat block 1 to every block.
504   for (int y = 0; y < kBlockSize; ++y) {
505     for (int x = 0; x < kBlockSize * num_blocks_w; ++x) {
506       this->data_[y * stride + x] +=
507           (this->data_[y * stride + x % kBlockSize + kBlockSize] -
508            (128 << shift));
509     }
510   }
511   // Now the scored selection will pick the one that is most likely flat (block
512   // 0)
513   EXPECT_EQ(1, aom_flat_block_finder_run(&flat_block_finder,
514                                          (uint8_t *)&this->data_[0], w, h,
515                                          stride, &flat_blocks[0]));
516   EXPECT_EQ(1, flat_blocks[0]);
517   EXPECT_EQ(0, flat_blocks[1]);
518   EXPECT_EQ(0, flat_blocks[2]);
519   EXPECT_EQ(0, flat_blocks[3]);
520   EXPECT_EQ(0, flat_blocks[4]);
521   EXPECT_EQ(0, flat_blocks[5]);
522   EXPECT_EQ(0, flat_blocks[6]);
523   EXPECT_EQ(0, flat_blocks[7]);
524 
525   aom_flat_block_finder_free(&flat_block_finder);
526 }
527 
528 REGISTER_TYPED_TEST_SUITE_P(FlatBlockEstimatorTest, ExtractBlock,
529                             FindFlatBlocks);
530 
531 typedef ::testing::Types<BitDepthParams<uint8_t, 8, false>,   // lowbd
532                          BitDepthParams<uint16_t, 8, true>,   // lowbd in 16-bit
533                          BitDepthParams<uint16_t, 10, true>,  // highbd data
534                          BitDepthParams<uint16_t, 12, true> >
535     AllBitDepthParams;
536 INSTANTIATE_TYPED_TEST_SUITE_P(FlatBlockInstatiation, FlatBlockEstimatorTest,
537                                AllBitDepthParams);
538 
539 template <typename T>
540 class NoiseModelUpdateTest : public ::testing::Test, public T {
541  public:
542   static const int kWidth = 128;
543   static const int kHeight = 128;
544   static const int kBlockSize = 16;
545   static const int kNumBlocksX = kWidth / kBlockSize;
546   static const int kNumBlocksY = kHeight / kBlockSize;
547 
SetUp()548   virtual void SetUp() {
549     const aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, 3,
550                                               T::kBitDepth, T::kUseHighBD };
551     ASSERT_TRUE(aom_noise_model_init(&model_, params));
552 
553     random_.Reset(100171);
554 
555     data_.resize(kWidth * kHeight * 3);
556     denoised_.resize(kWidth * kHeight * 3);
557     noise_.resize(kWidth * kHeight * 3);
558     renoise_.resize(kWidth * kHeight);
559     flat_blocks_.resize(kNumBlocksX * kNumBlocksY);
560 
561     for (int c = 0, offset = 0; c < 3; ++c, offset += kWidth * kHeight) {
562       data_ptr_[c] = &data_[offset];
563       noise_ptr_[c] = &noise_[offset];
564       denoised_ptr_[c] = &denoised_[offset];
565       strides_[c] = kWidth;
566 
567       data_ptr_raw_[c] = (uint8_t *)&data_[offset];
568       denoised_ptr_raw_[c] = (uint8_t *)&denoised_[offset];
569     }
570     chroma_sub_[0] = 0;
571     chroma_sub_[1] = 0;
572   }
573 
NoiseModelUpdate(int block_size=kBlockSize)574   int NoiseModelUpdate(int block_size = kBlockSize) {
575     return aom_noise_model_update(&model_, data_ptr_raw_, denoised_ptr_raw_,
576                                   kWidth, kHeight, strides_, chroma_sub_,
577                                   &flat_blocks_[0], block_size);
578   }
579 
TearDown()580   void TearDown() { aom_noise_model_free(&model_); }
581 
582  protected:
583   aom_noise_model_t model_;
584   std::vector<typename T::data_type_t> data_;
585   std::vector<typename T::data_type_t> denoised_;
586 
587   std::vector<double> noise_;
588   std::vector<double> renoise_;
589   std::vector<uint8_t> flat_blocks_;
590 
591   typename T::data_type_t *data_ptr_[3];
592   typename T::data_type_t *denoised_ptr_[3];
593 
594   double *noise_ptr_[3];
595   int strides_[3];
596   int chroma_sub_[2];
597   libaom_test::ACMRandom random_;
598 
599  private:
600   uint8_t *data_ptr_raw_[3];
601   uint8_t *denoised_ptr_raw_[3];
602 };
603 
604 TYPED_TEST_SUITE_P(NoiseModelUpdateTest);
605 
TYPED_TEST_P(NoiseModelUpdateTest,UpdateFailsNoFlatBlocks)606 TYPED_TEST_P(NoiseModelUpdateTest, UpdateFailsNoFlatBlocks) {
607   EXPECT_EQ(AOM_NOISE_STATUS_INSUFFICIENT_FLAT_BLOCKS,
608             this->NoiseModelUpdate());
609 }
610 
TYPED_TEST_P(NoiseModelUpdateTest,UpdateSuccessForZeroNoiseAllFlat)611 TYPED_TEST_P(NoiseModelUpdateTest, UpdateSuccessForZeroNoiseAllFlat) {
612   this->flat_blocks_.assign(this->flat_blocks_.size(), 1);
613   this->denoised_.assign(this->denoised_.size(), 128);
614   this->data_.assign(this->denoised_.size(), 128);
615   EXPECT_EQ(AOM_NOISE_STATUS_INTERNAL_ERROR, this->NoiseModelUpdate());
616 }
617 
TYPED_TEST_P(NoiseModelUpdateTest,UpdateFailsBlockSizeTooSmall)618 TYPED_TEST_P(NoiseModelUpdateTest, UpdateFailsBlockSizeTooSmall) {
619   this->flat_blocks_.assign(this->flat_blocks_.size(), 1);
620   this->denoised_.assign(this->denoised_.size(), 128);
621   this->data_.assign(this->denoised_.size(), 128);
622   EXPECT_EQ(AOM_NOISE_STATUS_INVALID_ARGUMENT,
623             this->NoiseModelUpdate(6 /* block_size=6 is too small*/));
624 }
625 
TYPED_TEST_P(NoiseModelUpdateTest,UpdateSuccessForWhiteRandomNoise)626 TYPED_TEST_P(NoiseModelUpdateTest, UpdateSuccessForWhiteRandomNoise) {
627   aom_noise_model_t &model = this->model_;
628   const int kWidth = this->kWidth;
629   const int kHeight = this->kHeight;
630 
631   const int shift = this->kBitDepth - 8;
632   for (int y = 0; y < kHeight; ++y) {
633     for (int x = 0; x < kWidth; ++x) {
634       this->data_ptr_[0][y * kWidth + x] =
635           int(64 + y + randn(&this->random_, 1)) << shift;
636       this->denoised_ptr_[0][y * kWidth + x] = (64 + y) << shift;
637       // Make the chroma planes completely correlated with the Y plane
638       for (int c = 1; c < 3; ++c) {
639         this->data_ptr_[c][y * kWidth + x] = this->data_ptr_[0][y * kWidth + x];
640         this->denoised_ptr_[c][y * kWidth + x] =
641             this->denoised_ptr_[0][y * kWidth + x];
642       }
643     }
644   }
645   this->flat_blocks_.assign(this->flat_blocks_.size(), 1);
646   EXPECT_EQ(AOM_NOISE_STATUS_OK, this->NoiseModelUpdate());
647 
648   const double kCoeffEps = 0.075;
649   const int n = model.n;
650   for (int c = 0; c < 3; ++c) {
651     for (int i = 0; i < n; ++i) {
652       EXPECT_NEAR(0, model.latest_state[c].eqns.x[i], kCoeffEps);
653       EXPECT_NEAR(0, model.combined_state[c].eqns.x[i], kCoeffEps);
654     }
655     // The second and third channels are highly correlated with the first.
656     if (c > 0) {
657       ASSERT_EQ(n + 1, model.latest_state[c].eqns.n);
658       ASSERT_EQ(n + 1, model.combined_state[c].eqns.n);
659 
660       EXPECT_NEAR(1, model.latest_state[c].eqns.x[n], kCoeffEps);
661       EXPECT_NEAR(1, model.combined_state[c].eqns.x[n], kCoeffEps);
662     }
663   }
664 
665   // The fitted noise strength should be close to the standard deviation
666   // for all intensity bins.
667   const double kStdEps = 0.1;
668   const double normalize = 1 << shift;
669 
670   for (int i = 0; i < model.latest_state[0].strength_solver.eqns.n; ++i) {
671     EXPECT_NEAR(1.0,
672                 model.latest_state[0].strength_solver.eqns.x[i] / normalize,
673                 kStdEps);
674     EXPECT_NEAR(1.0,
675                 model.combined_state[0].strength_solver.eqns.x[i] / normalize,
676                 kStdEps);
677   }
678 
679   aom_noise_strength_lut_t lut;
680   aom_noise_strength_solver_fit_piecewise(
681       &model.latest_state[0].strength_solver, -1, &lut);
682   ASSERT_EQ(2, lut.num_points);
683   EXPECT_NEAR(0.0, lut.points[0][0], 1e-5);
684   EXPECT_NEAR(1.0, lut.points[0][1] / normalize, kStdEps);
685   EXPECT_NEAR((1 << this->kBitDepth) - 1, lut.points[1][0], 1e-5);
686   EXPECT_NEAR(1.0, lut.points[1][1] / normalize, kStdEps);
687   aom_noise_strength_lut_free(&lut);
688 }
689 
TYPED_TEST_P(NoiseModelUpdateTest,UpdateSuccessForScaledWhiteNoise)690 TYPED_TEST_P(NoiseModelUpdateTest, UpdateSuccessForScaledWhiteNoise) {
691   aom_noise_model_t &model = this->model_;
692   const int kWidth = this->kWidth;
693   const int kHeight = this->kHeight;
694 
695   const double kCoeffEps = 0.055;
696   const double kLowStd = 1;
697   const double kHighStd = 4;
698   const int shift = this->kBitDepth - 8;
699   for (int y = 0; y < kHeight; ++y) {
700     for (int x = 0; x < kWidth; ++x) {
701       for (int c = 0; c < 3; ++c) {
702         // The image data is bimodal:
703         // Bottom half has low intensity and low noise strength
704         // Top half has high intensity and high noise strength
705         const int avg = (y < kHeight / 2) ? 4 : 245;
706         const double std = (y < kHeight / 2) ? kLowStd : kHighStd;
707         this->data_ptr_[c][y * kWidth + x] =
708             ((uint8_t)std::min((int)255,
709                                (int)(2 + avg + randn(&this->random_, std))))
710             << shift;
711         this->denoised_ptr_[c][y * kWidth + x] = (2 + avg) << shift;
712       }
713     }
714   }
715   // Label all blocks as flat for the update
716   this->flat_blocks_.assign(this->flat_blocks_.size(), 1);
717   EXPECT_EQ(AOM_NOISE_STATUS_OK, this->NoiseModelUpdate());
718 
719   const int n = model.n;
720   // The noise is uncorrelated spatially and with the y channel.
721   // All coefficients should be reasonably close to zero.
722   for (int c = 0; c < 3; ++c) {
723     for (int i = 0; i < n; ++i) {
724       EXPECT_NEAR(0, model.latest_state[c].eqns.x[i], kCoeffEps);
725       EXPECT_NEAR(0, model.combined_state[c].eqns.x[i], kCoeffEps);
726     }
727     if (c > 0) {
728       ASSERT_EQ(n + 1, model.latest_state[c].eqns.n);
729       ASSERT_EQ(n + 1, model.combined_state[c].eqns.n);
730 
731       // The correlation to the y channel should be low (near zero)
732       EXPECT_NEAR(0, model.latest_state[c].eqns.x[n], kCoeffEps);
733       EXPECT_NEAR(0, model.combined_state[c].eqns.x[n], kCoeffEps);
734     }
735   }
736 
737   // Noise strength should vary between kLowStd and kHighStd.
738   const double kStdEps = 0.15;
739   // We have to normalize fitted standard deviation based on bit depth.
740   const double normalize = (1 << shift);
741 
742   ASSERT_EQ(20, model.latest_state[0].strength_solver.eqns.n);
743   for (int i = 0; i < model.latest_state[0].strength_solver.eqns.n; ++i) {
744     const double a = i / 19.0;
745     const double expected = (kLowStd * (1.0 - a) + kHighStd * a);
746     EXPECT_NEAR(expected,
747                 model.latest_state[0].strength_solver.eqns.x[i] / normalize,
748                 kStdEps);
749     EXPECT_NEAR(expected,
750                 model.combined_state[0].strength_solver.eqns.x[i] / normalize,
751                 kStdEps);
752   }
753 
754   // If we fit a piecewise linear model, there should be two points:
755   // one near kLowStd at 0, and the other near kHighStd and 255.
756   aom_noise_strength_lut_t lut;
757   aom_noise_strength_solver_fit_piecewise(
758       &model.latest_state[0].strength_solver, 2, &lut);
759   ASSERT_EQ(2, lut.num_points);
760   EXPECT_NEAR(0, lut.points[0][0], 1e-4);
761   EXPECT_NEAR(kLowStd, lut.points[0][1] / normalize, kStdEps);
762   EXPECT_NEAR((1 << this->kBitDepth) - 1, lut.points[1][0], 1e-5);
763   EXPECT_NEAR(kHighStd, lut.points[1][1] / normalize, kStdEps);
764   aom_noise_strength_lut_free(&lut);
765 }
766 
TYPED_TEST_P(NoiseModelUpdateTest,UpdateSuccessForCorrelatedNoise)767 TYPED_TEST_P(NoiseModelUpdateTest, UpdateSuccessForCorrelatedNoise) {
768   aom_noise_model_t &model = this->model_;
769   const int kWidth = this->kWidth;
770   const int kHeight = this->kHeight;
771   const int kNumCoeffs = 24;
772   const double kStd = 4;
773   const double kStdEps = 0.3;
774   const double kCoeffEps = 0.065;
775   // Use different coefficients for each channel
776   const double kCoeffs[3][24] = {
777     { 0.02884, -0.03356, 0.00633,  0.01757,  0.02849,  -0.04620,
778       0.02833, -0.07178, 0.07076,  -0.11603, -0.10413, -0.16571,
779       0.05158, -0.07969, 0.02640,  -0.07191, 0.02530,  0.41968,
780       0.21450, -0.00702, -0.01401, -0.03676, -0.08713, 0.44196 },
781     { 0.00269, -0.01291, -0.01513, 0.07234,  0.03208,   0.00477,
782       0.00226, -0.00254, 0.03533,  0.12841,  -0.25970,  -0.06336,
783       0.05238, -0.00845, -0.03118, 0.09043,  -0.36558,  0.48903,
784       0.00595, -0.11938, 0.02106,  0.095956, -0.350139, 0.59305 },
785     { -0.00643, -0.01080, -0.01466, 0.06951, 0.03707,  -0.00482,
786       0.00817,  -0.00909, 0.02949,  0.12181, -0.25210, -0.07886,
787       0.06083,  -0.01210, -0.03108, 0.08944, -0.35875, 0.49150,
788       0.00415,  -0.12905, 0.02870,  0.09740, -0.34610, 0.58824 },
789   };
790 
791   ASSERT_EQ(model.n, kNumCoeffs);
792   this->chroma_sub_[0] = this->chroma_sub_[1] = 1;
793 
794   this->flat_blocks_.assign(this->flat_blocks_.size(), 1);
795 
796   // Add different noise onto each plane
797   const int shift = this->kBitDepth - 8;
798   for (int c = 0; c < 3; ++c) {
799     noise_synth(&this->random_, model.params.lag, model.n, model.coords,
800                 kCoeffs[c], this->noise_ptr_[c], kWidth, kHeight);
801     const int x_shift = c > 0 ? this->chroma_sub_[0] : 0;
802     const int y_shift = c > 0 ? this->chroma_sub_[1] : 0;
803     for (int y = 0; y < (kHeight >> y_shift); ++y) {
804       for (int x = 0; x < (kWidth >> x_shift); ++x) {
805         const uint8_t value = 64 + x / 2 + y / 4;
806         this->data_ptr_[c][y * kWidth + x] =
807             (uint8_t(value + this->noise_ptr_[c][y * kWidth + x] * kStd))
808             << shift;
809         this->denoised_ptr_[c][y * kWidth + x] = value << shift;
810       }
811     }
812   }
813   EXPECT_EQ(AOM_NOISE_STATUS_OK, this->NoiseModelUpdate());
814 
815   // For the Y plane, the solved coefficients should be close to the original
816   const int n = model.n;
817   for (int c = 0; c < 3; ++c) {
818     for (int i = 0; i < n; ++i) {
819       EXPECT_NEAR(kCoeffs[c][i], model.latest_state[c].eqns.x[i], kCoeffEps);
820       EXPECT_NEAR(kCoeffs[c][i], model.combined_state[c].eqns.x[i], kCoeffEps);
821     }
822     // The chroma planes should be uncorrelated with the luma plane
823     if (c > 0) {
824       EXPECT_NEAR(0, model.latest_state[c].eqns.x[n], kCoeffEps);
825       EXPECT_NEAR(0, model.combined_state[c].eqns.x[n], kCoeffEps);
826     }
827     // Correlation between the coefficient vector and the fitted coefficients
828     // should be close to 1.
829     EXPECT_LT(0.98, aom_normalized_cross_correlation(
830                         model.latest_state[c].eqns.x, kCoeffs[c], kNumCoeffs));
831 
832     noise_synth(&this->random_, model.params.lag, model.n, model.coords,
833                 model.latest_state[c].eqns.x, &this->renoise_[0], kWidth,
834                 kHeight);
835 
836     EXPECT_TRUE(aom_noise_data_validate(&this->renoise_[0], kWidth, kHeight));
837   }
838 
839   // Check fitted noise strength
840   const double normalize = 1 << shift;
841   for (int c = 0; c < 3; ++c) {
842     for (int i = 0; i < model.latest_state[c].strength_solver.eqns.n; ++i) {
843       EXPECT_NEAR(kStd,
844                   model.latest_state[c].strength_solver.eqns.x[i] / normalize,
845                   kStdEps);
846     }
847   }
848 }
849 
TYPED_TEST_P(NoiseModelUpdateTest,NoiseStrengthChangeSignalsDifferentNoiseType)850 TYPED_TEST_P(NoiseModelUpdateTest,
851              NoiseStrengthChangeSignalsDifferentNoiseType) {
852   aom_noise_model_t &model = this->model_;
853   const int kWidth = this->kWidth;
854   const int kHeight = this->kHeight;
855   const int kBlockSize = this->kBlockSize;
856   // Create a gradient image with std = 2 uncorrelated noise
857   const double kStd = 2;
858   const int shift = this->kBitDepth - 8;
859 
860   for (int i = 0; i < kWidth * kHeight; ++i) {
861     const uint8_t val = (i % kWidth) < kWidth / 2 ? 64 : 192;
862     for (int c = 0; c < 3; ++c) {
863       this->noise_ptr_[c][i] = randn(&this->random_, 1);
864       this->data_ptr_[c][i] = ((uint8_t)(this->noise_ptr_[c][i] * kStd + val))
865                               << shift;
866       this->denoised_ptr_[c][i] = val << shift;
867     }
868   }
869   this->flat_blocks_.assign(this->flat_blocks_.size(), 1);
870   EXPECT_EQ(AOM_NOISE_STATUS_OK, this->NoiseModelUpdate());
871 
872   const int kNumBlocks = kWidth * kHeight / kBlockSize / kBlockSize;
873   EXPECT_EQ(kNumBlocks, model.latest_state[0].strength_solver.num_equations);
874   EXPECT_EQ(kNumBlocks, model.latest_state[1].strength_solver.num_equations);
875   EXPECT_EQ(kNumBlocks, model.latest_state[2].strength_solver.num_equations);
876   EXPECT_EQ(kNumBlocks, model.combined_state[0].strength_solver.num_equations);
877   EXPECT_EQ(kNumBlocks, model.combined_state[1].strength_solver.num_equations);
878   EXPECT_EQ(kNumBlocks, model.combined_state[2].strength_solver.num_equations);
879 
880   // Bump up noise by an insignificant amount
881   for (int i = 0; i < kWidth * kHeight; ++i) {
882     const uint8_t val = (i % kWidth) < kWidth / 2 ? 64 : 192;
883     this->data_ptr_[0][i] =
884         ((uint8_t)(this->noise_ptr_[0][i] * (kStd + 0.085) + val)) << shift;
885   }
886   EXPECT_EQ(AOM_NOISE_STATUS_OK, this->NoiseModelUpdate());
887 
888   const double kARGainTolerance = 0.02;
889   for (int c = 0; c < 3; ++c) {
890     EXPECT_EQ(kNumBlocks, model.latest_state[c].strength_solver.num_equations);
891     EXPECT_EQ(15250, model.latest_state[c].num_observations);
892     EXPECT_NEAR(1, model.latest_state[c].ar_gain, kARGainTolerance);
893 
894     EXPECT_EQ(2 * kNumBlocks,
895               model.combined_state[c].strength_solver.num_equations);
896     EXPECT_EQ(2 * 15250, model.combined_state[c].num_observations);
897     EXPECT_NEAR(1, model.combined_state[c].ar_gain, kARGainTolerance);
898   }
899 
900   // Bump up the noise strength on half the image for one channel by a
901   // significant amount.
902   for (int i = 0; i < kWidth * kHeight; ++i) {
903     const uint8_t val = (i % kWidth) < kWidth / 2 ? 64 : 128;
904     if (i % kWidth < kWidth / 2) {
905       this->data_ptr_[0][i] =
906           ((uint8_t)(randn(&this->random_, kStd + 0.5) + val)) << shift;
907     }
908   }
909   EXPECT_EQ(AOM_NOISE_STATUS_DIFFERENT_NOISE_TYPE, this->NoiseModelUpdate());
910 
911   // Since we didn't update the combined state, it should still be at 2 *
912   // num_blocks
913   EXPECT_EQ(kNumBlocks, model.latest_state[0].strength_solver.num_equations);
914   EXPECT_EQ(2 * kNumBlocks,
915             model.combined_state[0].strength_solver.num_equations);
916 
917   // In normal operation, the "latest" estimate can be saved to the "combined"
918   // state for continued updates.
919   aom_noise_model_save_latest(&model);
920   for (int c = 0; c < 3; ++c) {
921     EXPECT_EQ(kNumBlocks, model.latest_state[c].strength_solver.num_equations);
922     EXPECT_EQ(15250, model.latest_state[c].num_observations);
923     EXPECT_NEAR(1, model.latest_state[c].ar_gain, kARGainTolerance);
924 
925     EXPECT_EQ(kNumBlocks,
926               model.combined_state[c].strength_solver.num_equations);
927     EXPECT_EQ(15250, model.combined_state[c].num_observations);
928     EXPECT_NEAR(1, model.combined_state[c].ar_gain, kARGainTolerance);
929   }
930 }
931 
TYPED_TEST_P(NoiseModelUpdateTest,NoiseCoeffsSignalsDifferentNoiseType)932 TYPED_TEST_P(NoiseModelUpdateTest, NoiseCoeffsSignalsDifferentNoiseType) {
933   aom_noise_model_t &model = this->model_;
934   const int kWidth = this->kWidth;
935   const int kHeight = this->kHeight;
936   const double kCoeffs[2][24] = {
937     { 0.02884, -0.03356, 0.00633,  0.01757,  0.02849,  -0.04620,
938       0.02833, -0.07178, 0.07076,  -0.11603, -0.10413, -0.16571,
939       0.05158, -0.07969, 0.02640,  -0.07191, 0.02530,  0.41968,
940       0.21450, -0.00702, -0.01401, -0.03676, -0.08713, 0.44196 },
941     { 0.00269, -0.01291, -0.01513, 0.07234,  0.03208,   0.00477,
942       0.00226, -0.00254, 0.03533,  0.12841,  -0.25970,  -0.06336,
943       0.05238, -0.00845, -0.03118, 0.09043,  -0.36558,  0.48903,
944       0.00595, -0.11938, 0.02106,  0.095956, -0.350139, 0.59305 }
945   };
946 
947   noise_synth(&this->random_, model.params.lag, model.n, model.coords,
948               kCoeffs[0], this->noise_ptr_[0], kWidth, kHeight);
949   for (int i = 0; i < kWidth * kHeight; ++i) {
950     this->data_ptr_[0][i] = (uint8_t)(128 + this->noise_ptr_[0][i]);
951   }
952   this->flat_blocks_.assign(this->flat_blocks_.size(), 1);
953   EXPECT_EQ(AOM_NOISE_STATUS_OK, this->NoiseModelUpdate());
954 
955   // Now try with the second set of AR coefficients
956   noise_synth(&this->random_, model.params.lag, model.n, model.coords,
957               kCoeffs[1], this->noise_ptr_[0], kWidth, kHeight);
958   for (int i = 0; i < kWidth * kHeight; ++i) {
959     this->data_ptr_[0][i] = (uint8_t)(128 + this->noise_ptr_[0][i]);
960   }
961   EXPECT_EQ(AOM_NOISE_STATUS_DIFFERENT_NOISE_TYPE, this->NoiseModelUpdate());
962 }
963 REGISTER_TYPED_TEST_SUITE_P(NoiseModelUpdateTest, UpdateFailsNoFlatBlocks,
964                             UpdateSuccessForZeroNoiseAllFlat,
965                             UpdateFailsBlockSizeTooSmall,
966                             UpdateSuccessForWhiteRandomNoise,
967                             UpdateSuccessForScaledWhiteNoise,
968                             UpdateSuccessForCorrelatedNoise,
969                             NoiseStrengthChangeSignalsDifferentNoiseType,
970                             NoiseCoeffsSignalsDifferentNoiseType);
971 
972 INSTANTIATE_TYPED_TEST_SUITE_P(NoiseModelUpdateTestInstatiation,
973                                NoiseModelUpdateTest, AllBitDepthParams);
974 
TEST(NoiseModelGetGrainParameters,TestLagSize)975 TEST(NoiseModelGetGrainParameters, TestLagSize) {
976   aom_film_grain_t film_grain;
977   for (int lag = 1; lag <= 3; ++lag) {
978     aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, lag, 8, 0 };
979     aom_noise_model_t model;
980     EXPECT_TRUE(aom_noise_model_init(&model, params));
981     EXPECT_TRUE(aom_noise_model_get_grain_parameters(&model, &film_grain));
982     EXPECT_EQ(lag, film_grain.ar_coeff_lag);
983     aom_noise_model_free(&model);
984   }
985 
986   aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, 4, 8, 0 };
987   aom_noise_model_t model;
988   EXPECT_TRUE(aom_noise_model_init(&model, params));
989   EXPECT_FALSE(aom_noise_model_get_grain_parameters(&model, &film_grain));
990   aom_noise_model_free(&model);
991 }
992 
TEST(NoiseModelGetGrainParameters,TestARCoeffShiftBounds)993 TEST(NoiseModelGetGrainParameters, TestARCoeffShiftBounds) {
994   struct TestCase {
995     double max_input_value;
996     int expected_ar_coeff_shift;
997     int expected_value;
998   };
999   const int lag = 1;
1000   const int kNumTestCases = 19;
1001   const TestCase test_cases[] = {
1002     // Test cases for ar_coeff_shift = 9
1003     { 0, 9, 0 },
1004     { 0.125, 9, 64 },
1005     { -0.125, 9, -64 },
1006     { 0.2499, 9, 127 },
1007     { -0.25, 9, -128 },
1008     // Test cases for ar_coeff_shift = 8
1009     { 0.25, 8, 64 },
1010     { -0.2501, 8, -64 },
1011     { 0.499, 8, 127 },
1012     { -0.5, 8, -128 },
1013     // Test cases for ar_coeff_shift = 7
1014     { 0.5, 7, 64 },
1015     { -0.5001, 7, -64 },
1016     { 0.999, 7, 127 },
1017     { -1, 7, -128 },
1018     // Test cases for ar_coeff_shift = 6
1019     { 1.0, 6, 64 },
1020     { -1.0001, 6, -64 },
1021     { 2.0, 6, 127 },
1022     { -2.0, 6, -128 },
1023     { 4, 6, 127 },
1024     { -4, 6, -128 },
1025   };
1026   aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, lag, 8, 0 };
1027   aom_noise_model_t model;
1028   EXPECT_TRUE(aom_noise_model_init(&model, params));
1029 
1030   for (int i = 0; i < kNumTestCases; ++i) {
1031     const TestCase &test_case = test_cases[i];
1032     model.combined_state[0].eqns.x[0] = test_case.max_input_value;
1033 
1034     aom_film_grain_t film_grain;
1035     EXPECT_TRUE(aom_noise_model_get_grain_parameters(&model, &film_grain));
1036     EXPECT_EQ(1, film_grain.ar_coeff_lag);
1037     EXPECT_EQ(test_case.expected_ar_coeff_shift, film_grain.ar_coeff_shift);
1038     EXPECT_EQ(test_case.expected_value, film_grain.ar_coeffs_y[0]);
1039   }
1040   aom_noise_model_free(&model);
1041 }
1042 
TEST(NoiseModelGetGrainParameters,TestNoiseStrengthShiftBounds)1043 TEST(NoiseModelGetGrainParameters, TestNoiseStrengthShiftBounds) {
1044   struct TestCase {
1045     double max_input_value;
1046     int expected_scaling_shift;
1047     int expected_value;
1048   };
1049   const int kNumTestCases = 10;
1050   const TestCase test_cases[] = {
1051     { 0, 11, 0 },      { 1, 11, 64 },     { 2, 11, 128 }, { 3.99, 11, 255 },
1052     { 4, 10, 128 },    { 7.99, 10, 255 }, { 8, 9, 128 },  { 16, 8, 128 },
1053     { 31.99, 8, 255 }, { 64, 8, 255 },  // clipped
1054   };
1055   const int lag = 1;
1056   aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, lag, 8, 0 };
1057   aom_noise_model_t model;
1058   EXPECT_TRUE(aom_noise_model_init(&model, params));
1059 
1060   for (int i = 0; i < kNumTestCases; ++i) {
1061     const TestCase &test_case = test_cases[i];
1062     aom_equation_system_t &eqns = model.combined_state[0].strength_solver.eqns;
1063     // Set the fitted scale parameters to be a constant value.
1064     for (int j = 0; j < eqns.n; ++j) {
1065       eqns.x[j] = test_case.max_input_value;
1066     }
1067     aom_film_grain_t film_grain;
1068     EXPECT_TRUE(aom_noise_model_get_grain_parameters(&model, &film_grain));
1069     // We expect a single constant segemnt
1070     EXPECT_EQ(test_case.expected_scaling_shift, film_grain.scaling_shift);
1071     EXPECT_EQ(test_case.expected_value, film_grain.scaling_points_y[0][1]);
1072     EXPECT_EQ(test_case.expected_value, film_grain.scaling_points_y[1][1]);
1073   }
1074   aom_noise_model_free(&model);
1075 }
1076 
1077 // The AR coefficients are the same inputs used to generate "Test 2" in the test
1078 // vectors
TEST(NoiseModelGetGrainParameters,GetGrainParametersReal)1079 TEST(NoiseModelGetGrainParameters, GetGrainParametersReal) {
1080   const double kInputCoeffsY[] = { 0.0315,  0.0073,  0.0218,  0.00235, 0.00511,
1081                                    -0.0222, 0.0627,  -0.022,  0.05575, -0.1816,
1082                                    0.0107,  -0.1966, 0.00065, -0.0809, 0.04934,
1083                                    -0.1349, -0.0352, 0.41772, 0.27973, 0.04207,
1084                                    -0.0429, -0.1372, 0.06193, 0.52032 };
1085   const double kInputCoeffsCB[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,
1086                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5 };
1087   const double kInputCoeffsCR[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   0,
1088                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.5 };
1089   const int kExpectedARCoeffsY[] = { 4,  1,   3,  0,   1,  -3,  8, -3,
1090                                      7,  -23, 1,  -25, 0,  -10, 6, -17,
1091                                      -5, 53,  36, 5,   -5, -18, 8, 67 };
1092   const int kExpectedARCoeffsCB[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1093                                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84 };
1094   const int kExpectedARCoeffsCR[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   0,
1095                                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -126 };
1096   // Scaling function is initialized analytically with a sqrt function.
1097   const int kNumScalingPointsY = 12;
1098   const int kExpectedScalingPointsY[][2] = {
1099     { 0, 0 },     { 13, 44 },   { 27, 62 },   { 40, 76 },
1100     { 54, 88 },   { 67, 98 },   { 94, 117 },  { 121, 132 },
1101     { 148, 146 }, { 174, 159 }, { 201, 171 }, { 255, 192 },
1102   };
1103 
1104   const int lag = 3;
1105   aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, lag, 8, 0 };
1106   aom_noise_model_t model;
1107   EXPECT_TRUE(aom_noise_model_init(&model, params));
1108 
1109   // Setup the AR coeffs
1110   memcpy(model.combined_state[0].eqns.x, kInputCoeffsY, sizeof(kInputCoeffsY));
1111   memcpy(model.combined_state[1].eqns.x, kInputCoeffsCB,
1112          sizeof(kInputCoeffsCB));
1113   memcpy(model.combined_state[2].eqns.x, kInputCoeffsCR,
1114          sizeof(kInputCoeffsCR));
1115   for (int i = 0; i < model.combined_state[0].strength_solver.num_bins; ++i) {
1116     const double x =
1117         ((double)i) / (model.combined_state[0].strength_solver.num_bins - 1.0);
1118     model.combined_state[0].strength_solver.eqns.x[i] = 6 * sqrt(x);
1119     model.combined_state[1].strength_solver.eqns.x[i] = 3;
1120     model.combined_state[2].strength_solver.eqns.x[i] = 2;
1121 
1122     // Inject some observations into the strength solver, as during film grain
1123     // parameter extraction an estimate of the average strength will be used to
1124     // adjust correlation.
1125     const int n = model.combined_state[0].strength_solver.num_bins;
1126     for (int j = 0; j < model.combined_state[0].strength_solver.num_bins; ++j) {
1127       model.combined_state[0].strength_solver.eqns.A[i * n + j] = 1;
1128       model.combined_state[1].strength_solver.eqns.A[i * n + j] = 1;
1129       model.combined_state[2].strength_solver.eqns.A[i * n + j] = 1;
1130     }
1131   }
1132 
1133   aom_film_grain_t film_grain;
1134   EXPECT_TRUE(aom_noise_model_get_grain_parameters(&model, &film_grain));
1135   EXPECT_EQ(lag, film_grain.ar_coeff_lag);
1136   EXPECT_EQ(3, film_grain.ar_coeff_lag);
1137   EXPECT_EQ(7, film_grain.ar_coeff_shift);
1138   EXPECT_EQ(10, film_grain.scaling_shift);
1139   EXPECT_EQ(kNumScalingPointsY, film_grain.num_y_points);
1140   EXPECT_EQ(1, film_grain.update_parameters);
1141   EXPECT_EQ(1, film_grain.apply_grain);
1142 
1143   const int kNumARCoeffs = 24;
1144   for (int i = 0; i < kNumARCoeffs; ++i) {
1145     EXPECT_EQ(kExpectedARCoeffsY[i], film_grain.ar_coeffs_y[i]);
1146   }
1147   for (int i = 0; i < kNumARCoeffs + 1; ++i) {
1148     EXPECT_EQ(kExpectedARCoeffsCB[i], film_grain.ar_coeffs_cb[i]);
1149   }
1150   for (int i = 0; i < kNumARCoeffs + 1; ++i) {
1151     EXPECT_EQ(kExpectedARCoeffsCR[i], film_grain.ar_coeffs_cr[i]);
1152   }
1153   for (int i = 0; i < kNumScalingPointsY; ++i) {
1154     EXPECT_EQ(kExpectedScalingPointsY[i][0], film_grain.scaling_points_y[i][0]);
1155     EXPECT_EQ(kExpectedScalingPointsY[i][1], film_grain.scaling_points_y[i][1]);
1156   }
1157 
1158   // CB strength should just be a piecewise segment
1159   EXPECT_EQ(2, film_grain.num_cb_points);
1160   EXPECT_EQ(0, film_grain.scaling_points_cb[0][0]);
1161   EXPECT_EQ(255, film_grain.scaling_points_cb[1][0]);
1162   EXPECT_EQ(96, film_grain.scaling_points_cb[0][1]);
1163   EXPECT_EQ(96, film_grain.scaling_points_cb[1][1]);
1164 
1165   // CR strength should just be a piecewise segment
1166   EXPECT_EQ(2, film_grain.num_cr_points);
1167   EXPECT_EQ(0, film_grain.scaling_points_cr[0][0]);
1168   EXPECT_EQ(255, film_grain.scaling_points_cr[1][0]);
1169   EXPECT_EQ(64, film_grain.scaling_points_cr[0][1]);
1170   EXPECT_EQ(64, film_grain.scaling_points_cr[1][1]);
1171 
1172   EXPECT_EQ(128, film_grain.cb_mult);
1173   EXPECT_EQ(192, film_grain.cb_luma_mult);
1174   EXPECT_EQ(256, film_grain.cb_offset);
1175   EXPECT_EQ(128, film_grain.cr_mult);
1176   EXPECT_EQ(192, film_grain.cr_luma_mult);
1177   EXPECT_EQ(256, film_grain.cr_offset);
1178   EXPECT_EQ(0, film_grain.chroma_scaling_from_luma);
1179   EXPECT_EQ(0, film_grain.grain_scale_shift);
1180 
1181   aom_noise_model_free(&model);
1182 }
1183 
1184 template <typename T>
1185 class WienerDenoiseTest : public ::testing::Test, public T {
1186  public:
SetUpTestSuite()1187   static void SetUpTestSuite() { aom_dsp_rtcd(); }
1188 
1189  protected:
SetUp()1190   void SetUp() {
1191     static const float kNoiseLevel = 5.f;
1192     static const float kStd = 4.0;
1193     static const double kMaxValue = (1 << T::kBitDepth) - 1;
1194 
1195     chroma_sub_[0] = 1;
1196     chroma_sub_[1] = 1;
1197     stride_[0] = kWidth;
1198     stride_[1] = kWidth / 2;
1199     stride_[2] = kWidth / 2;
1200     for (int k = 0; k < 3; ++k) {
1201       data_[k].resize(kWidth * kHeight);
1202       denoised_[k].resize(kWidth * kHeight);
1203       noise_psd_[k].resize(kBlockSize * kBlockSize);
1204     }
1205 
1206     const double kCoeffsY[] = { 0.0406, -0.116, -0.078, -0.152, 0.0033, -0.093,
1207                                 0.048,  0.404,  0.2353, -0.035, -0.093, 0.441 };
1208     const int kCoords[12][2] = {
1209       { -2, -2 }, { -1, -2 }, { 0, -2 }, { 1, -2 }, { 2, -2 }, { -2, -1 },
1210       { -1, -1 }, { 0, -1 },  { 1, -1 }, { 2, -1 }, { -2, 0 }, { -1, 0 }
1211     };
1212     const int kLag = 2;
1213     const int kLength = 12;
1214     libaom_test::ACMRandom random;
1215     std::vector<double> noise(kWidth * kHeight);
1216     noise_synth(&random, kLag, kLength, kCoords, kCoeffsY, &noise[0], kWidth,
1217                 kHeight);
1218     noise_psd_[0] = get_noise_psd(&noise[0], kWidth, kHeight, kBlockSize);
1219     for (int i = 0; i < kBlockSize * kBlockSize; ++i) {
1220       noise_psd_[0][i] = (float)(noise_psd_[0][i] * kStd * kStd * kScaleNoise *
1221                                  kScaleNoise / (kMaxValue * kMaxValue));
1222     }
1223 
1224     float psd_value =
1225         aom_noise_psd_get_default_value(kBlockSizeChroma, kNoiseLevel);
1226     for (int i = 0; i < kBlockSizeChroma * kBlockSizeChroma; ++i) {
1227       noise_psd_[1][i] = psd_value;
1228       noise_psd_[2][i] = psd_value;
1229     }
1230     for (int y = 0; y < kHeight; ++y) {
1231       for (int x = 0; x < kWidth; ++x) {
1232         data_[0][y * stride_[0] + x] = (typename T::data_type_t)fclamp(
1233             (x + noise[y * stride_[0] + x] * kStd) * kScaleNoise, 0, kMaxValue);
1234       }
1235     }
1236 
1237     for (int c = 1; c < 3; ++c) {
1238       for (int y = 0; y < (kHeight >> 1); ++y) {
1239         for (int x = 0; x < (kWidth >> 1); ++x) {
1240           data_[c][y * stride_[c] + x] = (typename T::data_type_t)fclamp(
1241               (x + randn(&random, kStd)) * kScaleNoise, 0, kMaxValue);
1242         }
1243       }
1244     }
1245     for (int k = 0; k < 3; ++k) {
1246       noise_psd_ptrs_[k] = &noise_psd_[k][0];
1247     }
1248   }
1249   static const int kBlockSize = 32;
1250   static const int kBlockSizeChroma = 16;
1251   static const int kWidth = 256;
1252   static const int kHeight = 256;
1253   static const int kScaleNoise = 1 << (T::kBitDepth - 8);
1254 
1255   std::vector<typename T::data_type_t> data_[3];
1256   std::vector<typename T::data_type_t> denoised_[3];
1257   std::vector<float> noise_psd_[3];
1258   int chroma_sub_[2];
1259   float *noise_psd_ptrs_[3];
1260   int stride_[3];
1261 };
1262 
1263 TYPED_TEST_SUITE_P(WienerDenoiseTest);
1264 
TYPED_TEST_P(WienerDenoiseTest,InvalidBlockSize)1265 TYPED_TEST_P(WienerDenoiseTest, InvalidBlockSize) {
1266   const uint8_t *const data_ptrs[3] = {
1267     reinterpret_cast<uint8_t *>(&this->data_[0][0]),
1268     reinterpret_cast<uint8_t *>(&this->data_[1][0]),
1269     reinterpret_cast<uint8_t *>(&this->data_[2][0]),
1270   };
1271   uint8_t *denoised_ptrs[3] = {
1272     reinterpret_cast<uint8_t *>(&this->denoised_[0][0]),
1273     reinterpret_cast<uint8_t *>(&this->denoised_[1][0]),
1274     reinterpret_cast<uint8_t *>(&this->denoised_[2][0]),
1275   };
1276   EXPECT_EQ(0, aom_wiener_denoise_2d(data_ptrs, denoised_ptrs, this->kWidth,
1277                                      this->kHeight, this->stride_,
1278                                      this->chroma_sub_, this->noise_psd_ptrs_,
1279                                      18, this->kBitDepth, this->kUseHighBD));
1280   EXPECT_EQ(0, aom_wiener_denoise_2d(data_ptrs, denoised_ptrs, this->kWidth,
1281                                      this->kHeight, this->stride_,
1282                                      this->chroma_sub_, this->noise_psd_ptrs_,
1283                                      48, this->kBitDepth, this->kUseHighBD));
1284   EXPECT_EQ(0, aom_wiener_denoise_2d(data_ptrs, denoised_ptrs, this->kWidth,
1285                                      this->kHeight, this->stride_,
1286                                      this->chroma_sub_, this->noise_psd_ptrs_,
1287                                      64, this->kBitDepth, this->kUseHighBD));
1288 }
1289 
TYPED_TEST_P(WienerDenoiseTest,InvalidChromaSubsampling)1290 TYPED_TEST_P(WienerDenoiseTest, InvalidChromaSubsampling) {
1291   const uint8_t *const data_ptrs[3] = {
1292     reinterpret_cast<uint8_t *>(&this->data_[0][0]),
1293     reinterpret_cast<uint8_t *>(&this->data_[1][0]),
1294     reinterpret_cast<uint8_t *>(&this->data_[2][0]),
1295   };
1296   uint8_t *denoised_ptrs[3] = {
1297     reinterpret_cast<uint8_t *>(&this->denoised_[0][0]),
1298     reinterpret_cast<uint8_t *>(&this->denoised_[1][0]),
1299     reinterpret_cast<uint8_t *>(&this->denoised_[2][0]),
1300   };
1301   int chroma_sub[2] = { 1, 0 };
1302   EXPECT_EQ(0, aom_wiener_denoise_2d(data_ptrs, denoised_ptrs, this->kWidth,
1303                                      this->kHeight, this->stride_, chroma_sub,
1304                                      this->noise_psd_ptrs_, 32, this->kBitDepth,
1305                                      this->kUseHighBD));
1306 
1307   chroma_sub[0] = 0;
1308   chroma_sub[1] = 1;
1309   EXPECT_EQ(0, aom_wiener_denoise_2d(data_ptrs, denoised_ptrs, this->kWidth,
1310                                      this->kHeight, this->stride_, chroma_sub,
1311                                      this->noise_psd_ptrs_, 32, this->kBitDepth,
1312                                      this->kUseHighBD));
1313 }
1314 
TYPED_TEST_P(WienerDenoiseTest,GradientTest)1315 TYPED_TEST_P(WienerDenoiseTest, GradientTest) {
1316   const int kWidth = this->kWidth;
1317   const int kHeight = this->kHeight;
1318   const int kBlockSize = this->kBlockSize;
1319   const uint8_t *const data_ptrs[3] = {
1320     reinterpret_cast<uint8_t *>(&this->data_[0][0]),
1321     reinterpret_cast<uint8_t *>(&this->data_[1][0]),
1322     reinterpret_cast<uint8_t *>(&this->data_[2][0]),
1323   };
1324   uint8_t *denoised_ptrs[3] = {
1325     reinterpret_cast<uint8_t *>(&this->denoised_[0][0]),
1326     reinterpret_cast<uint8_t *>(&this->denoised_[1][0]),
1327     reinterpret_cast<uint8_t *>(&this->denoised_[2][0]),
1328   };
1329   const int ret = aom_wiener_denoise_2d(
1330       data_ptrs, denoised_ptrs, kWidth, kHeight, this->stride_,
1331       this->chroma_sub_, this->noise_psd_ptrs_, this->kBlockSize,
1332       this->kBitDepth, this->kUseHighBD);
1333   EXPECT_EQ(1, ret);
1334 
1335   // Check the noise on the denoised image (from the analytical gradient)
1336   // and make sure that it is less than what we added.
1337   for (int c = 0; c < 3; ++c) {
1338     std::vector<double> measured_noise(kWidth * kHeight);
1339 
1340     double var = 0;
1341     const int shift = (c > 0);
1342     for (int x = 0; x < (kWidth >> shift); ++x) {
1343       for (int y = 0; y < (kHeight >> shift); ++y) {
1344         const double diff = this->denoised_[c][y * this->stride_[c] + x] -
1345                             x * this->kScaleNoise;
1346         var += diff * diff;
1347         measured_noise[y * kWidth + x] = diff;
1348       }
1349     }
1350     var /= (kWidth * kHeight);
1351     const double std = sqrt(std::max(0.0, var));
1352     EXPECT_LE(std, 1.25f * this->kScaleNoise);
1353     if (c == 0) {
1354       std::vector<float> measured_psd =
1355           get_noise_psd(&measured_noise[0], kWidth, kHeight, kBlockSize);
1356       std::vector<double> measured_psd_d(kBlockSize * kBlockSize);
1357       std::vector<double> noise_psd_d(kBlockSize * kBlockSize);
1358       std::copy(measured_psd.begin(), measured_psd.end(),
1359                 measured_psd_d.begin());
1360       std::copy(this->noise_psd_[0].begin(), this->noise_psd_[0].end(),
1361                 noise_psd_d.begin());
1362       EXPECT_LT(
1363           aom_normalized_cross_correlation(&measured_psd_d[0], &noise_psd_d[0],
1364                                            (int)(noise_psd_d.size())),
1365           0.35);
1366     }
1367   }
1368 }
1369 
1370 REGISTER_TYPED_TEST_SUITE_P(WienerDenoiseTest, InvalidBlockSize,
1371                             InvalidChromaSubsampling, GradientTest);
1372 
1373 INSTANTIATE_TYPED_TEST_SUITE_P(WienerDenoiseTestInstatiation, WienerDenoiseTest,
1374                                AllBitDepthParams);
1375