1 /*
2  *  Copyright (c) 2019 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include <math.h>
12 #include "third_party/googletest/src/include/gtest/gtest.h"
13 #include "vp9/encoder/vp9_non_greedy_mv.h"
14 #include "./vpx_dsp_rtcd.h"
15 
16 namespace {
17 
read_in_mf(const char * filename,int * rows_ptr,int * cols_ptr,MV ** buffer_ptr)18 static void read_in_mf(const char *filename, int *rows_ptr, int *cols_ptr,
19                        MV **buffer_ptr) {
20   FILE *input = fopen(filename, "rb");
21   int row, col;
22   int idx;
23 
24   ASSERT_NE(input, nullptr) << "Cannot open file: " << filename << std::endl;
25 
26   fscanf(input, "%d,%d\n", rows_ptr, cols_ptr);
27 
28   *buffer_ptr = (MV *)malloc((*rows_ptr) * (*cols_ptr) * sizeof(MV));
29 
30   for (idx = 0; idx < (*rows_ptr) * (*cols_ptr); ++idx) {
31     fscanf(input, "%d,%d;", &row, &col);
32     (*buffer_ptr)[idx].row = row;
33     (*buffer_ptr)[idx].col = col;
34   }
35   fclose(input);
36 }
37 
read_in_local_var(const char * filename,int * rows_ptr,int * cols_ptr,int (** M_ptr)[MF_LOCAL_STRUCTURE_SIZE])38 static void read_in_local_var(const char *filename, int *rows_ptr,
39                               int *cols_ptr,
40                               int (**M_ptr)[MF_LOCAL_STRUCTURE_SIZE]) {
41   FILE *input = fopen(filename, "rb");
42   int M00, M01, M10, M11;
43   int idx;
44   int int_type;
45 
46   ASSERT_NE(input, nullptr) << "Cannot open file: " << filename << std::endl;
47 
48   fscanf(input, "%d,%d\n", rows_ptr, cols_ptr);
49 
50   *M_ptr = (int(*)[MF_LOCAL_STRUCTURE_SIZE])malloc(
51       (*rows_ptr) * (*cols_ptr) * MF_LOCAL_STRUCTURE_SIZE * sizeof(int_type));
52 
53   for (idx = 0; idx < (*rows_ptr) * (*cols_ptr); ++idx) {
54     fscanf(input, "%d,%d,%d,%d;", &M00, &M01, &M10, &M11);
55     (*M_ptr)[idx][0] = M00;
56     (*M_ptr)[idx][1] = M01;
57     (*M_ptr)[idx][2] = M10;
58     (*M_ptr)[idx][3] = M11;
59   }
60   fclose(input);
61 }
62 
compare_mf(const MV * mf1,const MV * mf2,int rows,int cols,float * mean_ptr,float * std_ptr)63 static void compare_mf(const MV *mf1, const MV *mf2, int rows, int cols,
64                        float *mean_ptr, float *std_ptr) {
65   float float_type;
66   float *diffs = (float *)malloc(rows * cols * sizeof(float_type));
67   int idx;
68   float accu = 0.0f;
69   for (idx = 0; idx < rows * cols; ++idx) {
70     MV mv1 = mf1[idx];
71     MV mv2 = mf2[idx];
72     float row_diff2 = (float)((mv1.row - mv2.row) * (mv1.row - mv2.row));
73     float col_diff2 = (float)((mv1.col - mv2.col) * (mv1.col - mv2.col));
74     diffs[idx] = sqrt(row_diff2 + col_diff2);
75     accu += diffs[idx];
76   }
77   *mean_ptr = accu / rows / cols;
78   *std_ptr = 0;
79   for (idx = 0; idx < rows * cols; ++idx) {
80     *std_ptr += (diffs[idx] - (*mean_ptr)) * (diffs[idx] - (*mean_ptr));
81   }
82   *std_ptr = sqrt(*std_ptr / rows / cols);
83   free(diffs);
84 }
85 
load_frame_info(const char * filename,YV12_BUFFER_CONFIG * ref_frame_ptr)86 static void load_frame_info(const char *filename,
87                             YV12_BUFFER_CONFIG *ref_frame_ptr) {
88   FILE *input = fopen(filename, "rb");
89   int idx;
90   uint8_t data_type;
91 
92   ASSERT_NE(input, nullptr) << "Cannot open file: " << filename << std::endl;
93 
94   fscanf(input, "%d,%d\n", &(ref_frame_ptr->y_height),
95          &(ref_frame_ptr->y_width));
96 
97   ref_frame_ptr->y_buffer = (uint8_t *)malloc(
98       (ref_frame_ptr->y_width) * (ref_frame_ptr->y_height) * sizeof(data_type));
99 
100   for (idx = 0; idx < (ref_frame_ptr->y_width) * (ref_frame_ptr->y_height);
101        ++idx) {
102     int value;
103     fscanf(input, "%d,", &value);
104     ref_frame_ptr->y_buffer[idx] = (uint8_t)value;
105   }
106 
107   ref_frame_ptr->y_stride = ref_frame_ptr->y_width;
108   fclose(input);
109 }
110 
compare_local_var(const int (* local_var1)[MF_LOCAL_STRUCTURE_SIZE],const int (* local_var2)[MF_LOCAL_STRUCTURE_SIZE],int rows,int cols)111 static int compare_local_var(const int (*local_var1)[MF_LOCAL_STRUCTURE_SIZE],
112                              const int (*local_var2)[MF_LOCAL_STRUCTURE_SIZE],
113                              int rows, int cols) {
114   int diff = 0;
115   int outter_idx, inner_idx;
116   for (outter_idx = 0; outter_idx < rows * cols; ++outter_idx) {
117     for (inner_idx = 0; inner_idx < MF_LOCAL_STRUCTURE_SIZE; ++inner_idx) {
118       diff += abs(local_var1[outter_idx][inner_idx] -
119                   local_var2[outter_idx][inner_idx]);
120     }
121   }
122   return diff / rows / cols;
123 }
124 
TEST(non_greedy_mv,smooth_mf)125 TEST(non_greedy_mv, smooth_mf) {
126   const char *search_mf_file = "non_greedy_mv_test_files/exhaust_16x16.txt";
127   const char *local_var_file = "non_greedy_mv_test_files/localVar_16x16.txt";
128   const char *estimation_file = "non_greedy_mv_test_files/estimation_16x16.txt";
129   const char *ground_truth_file =
130       "non_greedy_mv_test_files/ground_truth_16x16.txt";
131   BLOCK_SIZE bsize = BLOCK_32X32;
132   MV *search_mf = nullptr;
133   MV *smooth_mf = nullptr;
134   MV *estimation = nullptr;
135   MV *ground_truth = nullptr;
136   int(*local_var)[MF_LOCAL_STRUCTURE_SIZE] = nullptr;
137   int rows = 0, cols = 0;
138 
139   int alpha = 100, max_iter = 100;
140 
141   read_in_mf(search_mf_file, &rows, &cols, &search_mf);
142   read_in_local_var(local_var_file, &rows, &cols, &local_var);
143   read_in_mf(estimation_file, &rows, &cols, &estimation);
144   read_in_mf(ground_truth_file, &rows, &cols, &ground_truth);
145 
146   float sm_mean, sm_std;
147   float est_mean, est_std;
148 
149   smooth_mf = (MV *)malloc(rows * cols * sizeof(MV));
150   vp9_get_smooth_motion_field(search_mf, local_var, rows, cols, bsize, alpha,
151                               max_iter, smooth_mf);
152 
153   compare_mf(smooth_mf, ground_truth, rows, cols, &sm_mean, &sm_std);
154   compare_mf(smooth_mf, estimation, rows, cols, &est_mean, &est_std);
155 
156   EXPECT_LE(sm_mean, 3);
157   EXPECT_LE(est_mean, 2);
158 
159   free(search_mf);
160   free(local_var);
161   free(estimation);
162   free(ground_truth);
163   free(smooth_mf);
164 }
165 
TEST(non_greedy_mv,local_var)166 TEST(non_greedy_mv, local_var) {
167   const char *ref_frame_file = "non_greedy_mv_test_files/ref_frame_16x16.txt";
168   const char *cur_frame_file = "non_greedy_mv_test_files/cur_frame_16x16.txt";
169   const char *gt_local_var_file = "non_greedy_mv_test_files/localVar_16x16.txt";
170   const char *search_mf_file = "non_greedy_mv_test_files/exhaust_16x16.txt";
171   BLOCK_SIZE bsize = BLOCK_16X16;
172   int(*gt_local_var)[MF_LOCAL_STRUCTURE_SIZE] = nullptr;
173   int(*est_local_var)[MF_LOCAL_STRUCTURE_SIZE] = nullptr;
174   YV12_BUFFER_CONFIG ref_frame, cur_frame;
175   int rows, cols;
176   MV *search_mf;
177   int int_type;
178   int local_var_diff;
179   vp9_variance_fn_ptr_t fn;
180 
181   load_frame_info(ref_frame_file, &ref_frame);
182   load_frame_info(cur_frame_file, &cur_frame);
183   read_in_mf(search_mf_file, &rows, &cols, &search_mf);
184 
185   fn.sdf = vpx_sad16x16;
186   est_local_var = (int(*)[MF_LOCAL_STRUCTURE_SIZE])malloc(
187       rows * cols * MF_LOCAL_STRUCTURE_SIZE * sizeof(int_type));
188   vp9_get_local_structure(&cur_frame, &ref_frame, search_mf, &fn, rows, cols,
189                           bsize, est_local_var);
190   read_in_local_var(gt_local_var_file, &rows, &cols, &gt_local_var);
191 
192   local_var_diff = compare_local_var(est_local_var, gt_local_var, rows, cols);
193 
194   EXPECT_LE(local_var_diff, 1);
195 
196   free(gt_local_var);
197   free(est_local_var);
198   free(ref_frame.y_buffer);
199 }
200 }  // namespace
201