libvmaf
Loading...
Searching...
No Matches
adm_tools.h
Go to the documentation of this file.
1
18
19#include <math.h>
20#include "common/macros.h"
21#include "barten_csf_tools.h"
22#include "adm_csf_tools.h"
23
24#ifndef M_PI
25#define M_PI 3.14159265358979323846264338327
26#endif
27
28#pragma once
29
30#ifndef ADM_TOOLS_H_
31#define ADM_TOOLS_H_
32
33// i = 0, j = 0: indices y: 1,0,1, x: 1,0,1
34#define ADM_CM_THRESH_S_0_0(angles,flt_angles,src_px_stride,accum,w,h,i,j) \
35{ \
36 *accum = 0; \
37 for (int theta = 0; theta < 3; ++theta) { \
38 const float *src_ptr = angles[theta]; \
39 const float *flt_ptr = flt_angles[theta]; \
40 float sum = 0; \
41 sum += flt_ptr[src_px_stride + 1]; \
42 sum += flt_ptr[src_px_stride]; \
43 sum += flt_ptr[src_px_stride + 1]; \
44 sum += flt_ptr[1]; \
45 sum += FLOAT_ONE_BY_15 * fabsf(src_ptr[0]); \
46 sum += flt_ptr[1]; \
47 sum += flt_ptr[src_px_stride + 1]; \
48 sum += flt_ptr[src_px_stride]; \
49 sum += flt_ptr[src_px_stride + 1]; \
50 *accum += sum; \
51 } \
52}
53
54// i = 0, j = w-1: indices y: 1,0,1, x: w-2, w-1, w-1
55#define ADM_CM_THRESH_S_0_W_M_1(angles,flt_angles,src_px_stride,accum,w,h,i,j) \
56{ \
57 *accum = 0; \
58 for (int theta = 0; theta < 3; ++theta) { \
59 const float *src_ptr = angles[theta]; \
60 const float *flt_ptr = flt_angles[theta]; \
61 float sum = 0; \
62 sum += flt_ptr[src_px_stride + w - 2]; \
63 sum += flt_ptr[src_px_stride + w - 1]; \
64 sum += flt_ptr[src_px_stride + w - 1]; \
65 sum += flt_ptr[w - 2]; \
66 sum += FLOAT_ONE_BY_15 * fabsf(src_ptr[w - 1]); \
67 sum += flt_ptr[w - 1]; \
68 sum += flt_ptr[src_px_stride + w - 2]; \
69 sum += flt_ptr[src_px_stride + w - 1]; \
70 sum += flt_ptr[src_px_stride + w - 1]; \
71 *accum += sum; \
72 } \
73}
74
75// i = 0, j = 1, ..., w-2: indices y: 1,0,1, x: j-1,j,j+1
76#define ADM_CM_THRESH_S_0_J(angles,flt_angles,src_px_stride,accum,w,h,i,j) \
77{ \
78 *accum = 0; \
79 for (int theta = 0; theta < 3; ++theta) { \
80 const float *src_ptr = angles[theta]; \
81 const float *flt_ptr = flt_angles[theta]; \
82 float sum = 0; \
83 sum += flt_ptr[src_px_stride + j - 1]; \
84 sum += flt_ptr[src_px_stride + j]; \
85 sum += flt_ptr[src_px_stride + j + 1]; \
86 sum += flt_ptr[j - 1]; \
87 sum += FLOAT_ONE_BY_15 * fabsf(src_ptr[j]); \
88 sum += flt_ptr[j + 1]; \
89 sum += flt_ptr[src_px_stride + j - 1]; \
90 sum += flt_ptr[src_px_stride + j]; \
91 sum += flt_ptr[src_px_stride + j + 1]; \
92 *accum += sum; \
93 } \
94}
95
96// i = h-1, j = 0: indices y: h-2,h-1,h-1, x: 1,0,1
97#define ADM_CM_THRESH_S_H_M_1_0(angles,flt_angles,src_px_stride,accum,w,h,i,j) \
98{ \
99 *accum = 0; \
100 for (int theta = 0; theta < 3; ++theta) { \
101 const float *src_ptr = angles[theta]; \
102 const float *flt_ptr = flt_angles[theta]; \
103 float sum = 0; \
104 src_ptr += (src_px_stride * (h - 2)); \
105 flt_ptr += (src_px_stride * (h - 2)); \
106 sum += flt_ptr[1]; \
107 sum += flt_ptr[0]; \
108 sum += flt_ptr[1]; \
109 src_ptr += src_px_stride; \
110 flt_ptr += src_px_stride; \
111 sum += flt_ptr[1]; \
112 sum += FLOAT_ONE_BY_15 * fabsf(src_ptr[0]); \
113 sum += flt_ptr[1]; \
114 sum += flt_ptr[1]; \
115 sum += flt_ptr[0]; \
116 sum += flt_ptr[1]; \
117 *accum += sum; \
118 } \
119}
120
121// i = h-1, j = w-1: indices y: h-2,h-1,h-1, x: w-2, w-1, w-1
122#define ADM_CM_THRESH_S_H_M_1_W_M_1(angles,flt_angles,src_px_stride,accum,w,h,i,j) \
123{ \
124 *accum = 0; \
125 for (int theta = 0; theta < 3; ++theta) { \
126 const float *src_ptr = angles[theta]; \
127 const float *flt_ptr = flt_angles[theta]; \
128 float sum = 0; \
129 src_ptr += (src_px_stride * (h - 2)); \
130 flt_ptr += (src_px_stride * (h - 2)); \
131 sum += flt_ptr[w - 2]; \
132 sum += flt_ptr[w - 1]; \
133 sum += flt_ptr[w - 1]; \
134 src_ptr += src_px_stride; \
135 flt_ptr += src_px_stride; \
136 sum += flt_ptr[w - 2]; \
137 sum += FLOAT_ONE_BY_15 * fabsf(src_ptr[w - 1]); \
138 sum += flt_ptr[w - 1]; \
139 sum += flt_ptr[w - 2]; \
140 sum += flt_ptr[w - 1]; \
141 sum += flt_ptr[w - 1]; \
142 *accum += sum; \
143 } \
144}
145
146// i = h-1, j = 1, ..., w-2: indices y: h-2,h-1,h-1, x: j-1,j,j+1
147#define ADM_CM_THRESH_S_H_M_1_J(angles,flt_angles,src_px_stride,accum,w,h,i,j) \
148{ \
149 *accum = 0; \
150 for (int theta = 0; theta < 3; ++theta) { \
151 const float *src_ptr = angles[theta]; \
152 const float *flt_ptr = flt_angles[theta]; \
153 float sum = 0; \
154 src_ptr += (src_px_stride * (h - 2)); \
155 flt_ptr += (src_px_stride * (h - 2)); \
156 sum += flt_ptr[j - 1];\
157 sum += flt_ptr[j]; \
158 sum += flt_ptr[j + 1]; \
159 src_ptr += src_px_stride; \
160 flt_ptr += src_px_stride; \
161 sum += flt_ptr[j - 1]; \
162 sum += FLOAT_ONE_BY_15 * fabsf(src_ptr[j]); \
163 sum += flt_ptr[j + 1]; \
164 sum += flt_ptr[j - 1]; \
165 sum += flt_ptr[j]; \
166 sum += flt_ptr[j + 1]; \
167 *accum += sum; \
168 } \
169}
170
171// i = 1,..,h-2, j = 1,..,w-2: indices y: i-1,i,i+1, x: j-1,j,j+1
172#define ADM_CM_THRESH_S_I_J(angles,flt_angles,src_px_stride,accum,w,h,i,j) \
173{ \
174 *accum = 0; \
175 for (int theta = 0; theta < 3; ++theta) { \
176 const float *src_ptr = angles[theta]; \
177 const float *flt_ptr = flt_angles[theta]; \
178 float sum = 0; \
179 src_ptr += (src_px_stride * (i - 1)); \
180 flt_ptr += (src_px_stride * (i - 1)); \
181 sum += flt_ptr[j - 1]; \
182 sum += flt_ptr[j]; \
183 sum += flt_ptr[j + 1]; \
184 src_ptr += src_px_stride; \
185 flt_ptr += src_px_stride; \
186 sum += flt_ptr[j - 1]; \
187 sum += FLOAT_ONE_BY_15 * fabsf(src_ptr[j]); \
188 sum += flt_ptr[j + 1]; \
189 src_ptr += src_px_stride; \
190 flt_ptr += src_px_stride; \
191 sum += flt_ptr[j - 1]; \
192 sum += flt_ptr[j]; \
193 sum += flt_ptr[j + 1]; \
194 *accum += sum; \
195 } \
196}
197
198// i = 1,..,h-2, j = 0: indices y: i-1,i,i+1, x: 1,0,1
199#define ADM_CM_THRESH_S_I_0(angles,flt_angles,src_px_stride,accum,w,h,i,j) \
200{ \
201 *accum = 0; \
202 for (int theta = 0; theta < 3; ++theta) { \
203 const float *src_ptr = angles[theta]; \
204 const float *flt_ptr = flt_angles[theta]; \
205 float sum = 0; \
206 src_ptr += (src_px_stride * (i - 1)); \
207 flt_ptr += (src_px_stride * (i - 1)); \
208 sum += flt_ptr[1]; \
209 sum += flt_ptr[0]; \
210 sum += flt_ptr[1]; \
211 src_ptr += src_px_stride; \
212 flt_ptr += src_px_stride; \
213 sum += flt_ptr[1]; \
214 sum += FLOAT_ONE_BY_15 * fabsf(src_ptr[0]); \
215 sum += flt_ptr[1]; \
216 src_ptr += src_px_stride; \
217 flt_ptr += src_px_stride; \
218 sum += flt_ptr[1]; \
219 sum += flt_ptr[0]; \
220 sum += flt_ptr[1]; \
221 *accum += sum; \
222 } \
223}
224
225// i = 1,..,h-2, j = w-1: indices y: i-1,i,i+1, x: w-2,w-1,w-1
226#define ADM_CM_THRESH_S_I_W_M_1(angles,flt_angles,src_px_stride,accum,w,h,i,j) \
227{ \
228 *accum = 0; \
229 for (int theta = 0; theta < 3; ++theta) { \
230 const float *src_ptr = angles[theta]; \
231 const float *flt_ptr = flt_angles[theta]; \
232 float sum = 0; \
233 src_ptr += (src_px_stride * (i-1)); \
234 flt_ptr += (src_px_stride * (i - 1)); \
235 sum += flt_ptr[w - 2]; \
236 sum += flt_ptr[w - 1]; \
237 sum += flt_ptr[w - 1]; \
238 src_ptr += src_px_stride; \
239 flt_ptr += src_px_stride; \
240 sum += flt_ptr[w - 2]; \
241 sum += FLOAT_ONE_BY_15 * fabsf(src_ptr[w - 1]); \
242 sum += flt_ptr[w - 1]; \
243 src_ptr += src_px_stride; \
244 flt_ptr += src_px_stride; \
245 sum += flt_ptr[w - 2]; \
246 sum += flt_ptr[w - 1]; \
247 sum += flt_ptr[w - 1]; \
248 *accum += sum; \
249 } \
250}
251
252typedef struct adm_dwt_band_t_s {
253 float *band_a; /* Low-pass V + low-pass H. */
254 float *band_v; /* Low-pass V + high-pass H. */
255 float *band_h; /* High-pass V + low-pass H. */
256 float *band_d; /* High-pass V + high-pass H. */
258
259typedef struct adm_dwt_band_t_d {
260 double *band_a; /* Low-pass V + low-pass H. */
261 double *band_v; /* Low-pass V + high-pass H. */
262 double *band_h; /* High-pass V + low-pass H. */
263 double *band_d; /* High-pass V + high-pass H. */
265
266float adm_sum_cube_s(const float *x, int w, int h, int stride, double border_factor, double adm_p_norm);
267
268void adm_decouple_s(const adm_dwt_band_t_s *ref, const adm_dwt_band_t_s *dis, const adm_dwt_band_t_s *r, const adm_dwt_band_t_s *a, int w, int h, int ref_stride, int dis_stride, int r_stride, int a_stride, double border_factor, double adm_enhn_gain_limit);
269
270void adm_csf_s(const adm_dwt_band_t_s *src, const adm_dwt_band_t_s *dst, const adm_dwt_band_t_s *flt, int orig_h, int scale, int w, int h, int src_stride, int dst_stride, double border_factor, double adm_norm_view_dist, int adm_ref_display_height, int adm_csf_mode, double luminance_level, double adm_csf_scale, double adm_csf_diag_scale, double adm_f1s0, double adm_f1s1, double adm_f1s2, double adm_f1s3, double adm_f2s0, double adm_f2s1, double adm_f2s2, double adm_f2s3);
271
272void adm_cm_thresh_s(const adm_dwt_band_t_s *src, float *dst, int w, int h, int src_stride, int dst_stride);
273
274float adm_csf_den_scale_s(const adm_dwt_band_t_s *src, int orig_h, int scale, int w, int h, int src_stride, double border_factor, double adm_norm_view_dist, int adm_ref_display_height, int adm_csf_mode, double luminance_level, double adm_csf_scale, double adm_csf_diag_scale, double adm_noise_weight, double adm_p_norm, double adm_f1s0, double adm_f1s1, double adm_f1s2, double adm_f1s3, double adm_f2s0, double adm_f2s1, double adm_f2s2, double adm_f2s3);
275
276float adm_cm_s(const adm_dwt_band_t_s *src, const adm_dwt_band_t_s *dst, const adm_dwt_band_t_s *csf_a, int w, int h, int src_stride, int dst_stride, int csf_a_stride, double border_factor, int scale, double adm_norm_view_dist, int adm_ref_display_height, int adm_csf_mode, double luminance_level, double adm_csf_scale, double adm_csf_diag_scale, double adm_noise_weight, int adm_bypass_cm, double adm_p_norm, double adm_f1s0, double adm_f1s1, double adm_f1s2, double adm_f1s3, double adm_f2s0, double adm_f2s1, double adm_f2s2, double adm_f2s3);
277
278void dwt2_src_indices_filt_s(int **src_ind_y, int **src_ind_x, int w, int h);
279
280void adm_dwt2_s(const float *src, const adm_dwt_band_t_s *dst, int **ind_y, int **ind_x, int w, int h, int src_stride, int dst_stride);
281
282void adm_dwt2_lo_s(const float *src, const adm_dwt_band_t_s *dst, int **ind_y, int **ind_x, int w, int h, int src_stride, int dst_stride);
283
284void adm_dwt2_d(const double *src, const adm_dwt_band_t_d *dst, int **ind_y, int **ind_x, int w, int h, int src_stride, int dst_stride);
285
286/* ================= */
287/* Noise floor model */
288/* ================= */
289
290/*
291 * The following dwt visibility threshold parameters are taken from
292 * "Visibility of Wavelet Quantization Noise"
293 * by A. B. Watson, G. Y. Yang, J. A. Solomon and J. Villasenor
294 * IEEE Trans. on Image Processing, Vol. 6, No 8, Aug. 1997
295 * Page 1170, formula (7) and corresponding Table IV
296 * Table IV has 2 entries for Cb and Cr thresholds
297 * Chose those corresponding to subject "sfl" since they are lower
298 * These thresholds were obtained and modeled for the 7-9 biorthogonal wavelet basis
299 */
301 float a;
302 float k;
303 float f0;
304 float g[4];
305};
306
307// 0 -> Y, 1 -> Cb, 2 -> Cr
308static const struct dwt_model_params dwt_7_9_YCbCr_threshold[3] = {
309 { .a = 0.495, .k = 0.466, .f0 = 0.401, .g = { 1.501, 1.0, 0.534, 1.0} },
310 { .a = 1.633, .k = 0.353, .f0 = 0.209, .g = { 1.520, 1.0, 0.502, 1.0} },
311 { .a = 0.944, .k = 0.521, .f0 = 0.404, .g = { 1.868, 1.0, 0.516, 1.0} }
312};
313
314/*
315 * The following dwt basis function amplitudes, A(lambda,theta), are taken from
316 * "Visibility of Wavelet Quantization Noise"
317 * by A. B. Watson, G. Y. Yang, J. A. Solomon and J. Villasenor
318 * IEEE Trans. on Image Processing, Vol. 6, No 8, Aug. 1997
319 * Page 1172, Table V
320 * The table has been transposed, i.e. it can be used directly to obtain A[lambda][theta]
321 * These amplitudes were calculated for the 7-9 biorthogonal wavelet basis
322 */
323static const float dwt_7_9_basis_function_amplitudes[6][4] = {
324 { 0.62171, 0.67234, 0.72709, 0.67234 },
325 { 0.34537, 0.41317, 0.49428, 0.41317 },
326 { 0.18004, 0.22727, 0.28688, 0.22727 },
327 { 0.091401, 0.11792, 0.15214, 0.11792 },
328 { 0.045943, 0.059758, 0.077727, 0.059758 },
329 { 0.023013, 0.030018, 0.039156, 0.030018 }
330};
331
332/*
333 * lambda = 0 (finest scale), 1, 2, 3 (coarsest scale);
334 * theta = 0 (ll), 1 (lh - vertical), 2 (hh - diagonal), 3(hl - horizontal).
335 */
336static FORCE_INLINE float dwt_quant_step(const struct dwt_model_params *params,
337 int lambda, int theta, double adm_norm_view_dist, int adm_ref_display_height)
338{
339 // Formula (1), page 1165 - display visual resolution (DVR), in pixels/degree of visual angle. This should be 56.55
340 float r = adm_norm_view_dist * adm_ref_display_height * M_PI / 180.0;
341
342 // Formula (9), page 1171
343 float temp = log10(pow(2.0,lambda+1)*params->f0*params->g[theta]/r);
344 float Q = 2.0*params->a*pow(10.0,params->k*temp*temp)/dwt_7_9_basis_function_amplitudes[lambda][theta];
345
346 return Q;
347}
348
349#endif /* ADM_TOOLS_H_ */
float adm_cm_s(const adm_dwt_band_t_s *src, const adm_dwt_band_t_s *dst, const adm_dwt_band_t_s *csf_a, int w, int h, int src_stride, int dst_stride, int csf_a_stride, double border_factor, int scale, double adm_norm_view_dist, int adm_ref_display_height, int adm_csf_mode, double luminance_level, double adm_csf_scale, double adm_csf_diag_scale, double adm_noise_weight, int adm_bypass_cm, double adm_p_norm, double adm_f1s0, double adm_f1s1, double adm_f1s2, double adm_f1s3, double adm_f2s0, double adm_f2s1, double adm_f2s2, double adm_f2s3)
void dwt2_src_indices_filt_s(int **src_ind_y, int **src_ind_x, int w, int h)
float adm_csf_den_scale_s(const adm_dwt_band_t_s *src, int orig_h, int scale, int w, int h, int src_stride, double border_factor, double adm_norm_view_dist, int adm_ref_display_height, int adm_csf_mode, double luminance_level, double adm_csf_scale, double adm_csf_diag_scale, double adm_noise_weight, double adm_p_norm, double adm_f1s0, double adm_f1s1, double adm_f1s2, double adm_f1s3, double adm_f2s0, double adm_f2s1, double adm_f2s2, double adm_f2s3)
void adm_dwt2_d(const double *src, const adm_dwt_band_t_d *dst, int **ind_y, int **ind_x, int w, int h, int src_stride, int dst_stride)
void adm_dwt2_lo_s(const float *src, const adm_dwt_band_t_s *dst, int **ind_y, int **ind_x, int w, int h, int src_stride, int dst_stride)
void adm_dwt2_s(const float *src, const adm_dwt_band_t_s *dst, int **ind_y, int **ind_x, int w, int h, int src_stride, int dst_stride)
void adm_decouple_s(const adm_dwt_band_t_s *ref, const adm_dwt_band_t_s *dis, const adm_dwt_band_t_s *r, const adm_dwt_band_t_s *a, int w, int h, int ref_stride, int dis_stride, int r_stride, int a_stride, double border_factor, double adm_enhn_gain_limit)
void adm_csf_s(const adm_dwt_band_t_s *src, const adm_dwt_band_t_s *dst, const adm_dwt_band_t_s *flt, int orig_h, int scale, int w, int h, int src_stride, int dst_stride, double border_factor, double adm_norm_view_dist, int adm_ref_display_height, int adm_csf_mode, double luminance_level, double adm_csf_scale, double adm_csf_diag_scale, double adm_f1s0, double adm_f1s1, double adm_f1s2, double adm_f1s3, double adm_f2s0, double adm_f2s1, double adm_f2s2, double adm_f2s3)
void adm_cm_thresh_s(const adm_dwt_band_t_s *src, float *dst, int w, int h, int src_stride, int dst_stride)
float adm_sum_cube_s(const float *x, int w, int h, int stride, double border_factor, double adm_p_norm)
#define M_PI
Definition adm_tools.h:25
Definition adm_tools.h:259
double * band_a
Definition adm_tools.h:260
double * band_h
Definition adm_tools.h:262
double * band_v
Definition adm_tools.h:261
double * band_d
Definition adm_tools.h:263
Definition adm_tools.h:252
float * band_v
Definition adm_tools.h:254
float * band_a
Definition adm_tools.h:253
float * band_h
Definition adm_tools.h:255
float * band_d
Definition adm_tools.h:256
Definition adm_tools.h:300
float g[4]
Definition adm_tools.h:304
float f0
Definition adm_tools.h:303
float a
Definition adm_tools.h:301
float k
Definition adm_tools.h:302