Coverage Report

Created: 2025-06-22 08:04

/src/aom/aom_dsp/noise_util.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2017, 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 <math.h>
13
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
18
#include "aom_dsp/noise_util.h"
19
#include "aom_dsp/fft_common.h"
20
#include "aom_mem/aom_mem.h"
21
#include "config/aom_dsp_rtcd.h"
22
23
0
float aom_noise_psd_get_default_value(int block_size, float factor) {
24
0
  return (factor * factor / 10000) * block_size * block_size / 8;
25
0
}
26
27
// Internal representation of noise transform. It keeps track of the
28
// transformed data and a temporary working buffer to use during the
29
// transform.
30
struct aom_noise_tx_t {
31
  float *tx_block;
32
  float *temp;
33
  int block_size;
34
  void (*fft)(const float *, float *, float *);
35
  void (*ifft)(const float *, float *, float *);
36
};
37
38
0
struct aom_noise_tx_t *aom_noise_tx_malloc(int block_size) {
39
0
  struct aom_noise_tx_t *noise_tx =
40
0
      (struct aom_noise_tx_t *)aom_malloc(sizeof(struct aom_noise_tx_t));
41
0
  if (!noise_tx) return NULL;
42
0
  memset(noise_tx, 0, sizeof(*noise_tx));
43
0
  switch (block_size) {
44
0
    case 2:
45
0
      noise_tx->fft = aom_fft2x2_float;
46
0
      noise_tx->ifft = aom_ifft2x2_float;
47
0
      break;
48
0
    case 4:
49
0
      noise_tx->fft = aom_fft4x4_float;
50
0
      noise_tx->ifft = aom_ifft4x4_float;
51
0
      break;
52
0
    case 8:
53
0
      noise_tx->fft = aom_fft8x8_float;
54
0
      noise_tx->ifft = aom_ifft8x8_float;
55
0
      break;
56
0
    case 16:
57
0
      noise_tx->fft = aom_fft16x16_float;
58
0
      noise_tx->ifft = aom_ifft16x16_float;
59
0
      break;
60
0
    case 32:
61
0
      noise_tx->fft = aom_fft32x32_float;
62
0
      noise_tx->ifft = aom_ifft32x32_float;
63
0
      break;
64
0
    default:
65
0
      aom_free(noise_tx);
66
0
      fprintf(stderr, "Unsupported block size %d\n", block_size);
67
0
      return NULL;
68
0
  }
69
0
  noise_tx->block_size = block_size;
70
0
  noise_tx->tx_block = (float *)aom_memalign(
71
0
      32, 2 * sizeof(*noise_tx->tx_block) * block_size * block_size);
72
0
  noise_tx->temp = (float *)aom_memalign(
73
0
      32, 2 * sizeof(*noise_tx->temp) * block_size * block_size);
74
0
  if (!noise_tx->tx_block || !noise_tx->temp) {
75
0
    aom_noise_tx_free(noise_tx);
76
0
    return NULL;
77
0
  }
78
  // Clear the buffers up front. Some outputs of the forward transform are
79
  // real only (the imaginary component will never be touched)
80
0
  memset(noise_tx->tx_block, 0,
81
0
         2 * sizeof(*noise_tx->tx_block) * block_size * block_size);
82
0
  memset(noise_tx->temp, 0,
83
0
         2 * sizeof(*noise_tx->temp) * block_size * block_size);
84
0
  return noise_tx;
85
0
}
86
87
0
void aom_noise_tx_forward(struct aom_noise_tx_t *noise_tx, const float *data) {
88
0
  noise_tx->fft(data, noise_tx->temp, noise_tx->tx_block);
89
0
}
90
91
0
void aom_noise_tx_filter(struct aom_noise_tx_t *noise_tx, const float *psd) {
92
0
  const int block_size = noise_tx->block_size;
93
0
  const float kBeta = 1.1f;
94
0
  const float kEps = 1e-6f;
95
0
  for (int y = 0; y < block_size; ++y) {
96
0
    for (int x = 0; x < block_size; ++x) {
97
0
      int i = y * block_size + x;
98
0
      float *c = noise_tx->tx_block + 2 * i;
99
0
      const float c0 = AOMMAX((float)fabs(c[0]), 1e-8f);
100
0
      const float c1 = AOMMAX((float)fabs(c[1]), 1e-8f);
101
0
      const float p = c0 * c0 + c1 * c1;
102
0
      if (p > kBeta * psd[i] && p > 1e-6) {
103
0
        noise_tx->tx_block[2 * i + 0] *= (p - psd[i]) / AOMMAX(p, kEps);
104
0
        noise_tx->tx_block[2 * i + 1] *= (p - psd[i]) / AOMMAX(p, kEps);
105
0
      } else {
106
0
        noise_tx->tx_block[2 * i + 0] *= (kBeta - 1.0f) / kBeta;
107
0
        noise_tx->tx_block[2 * i + 1] *= (kBeta - 1.0f) / kBeta;
108
0
      }
109
0
    }
110
0
  }
111
0
}
112
113
0
void aom_noise_tx_inverse(struct aom_noise_tx_t *noise_tx, float *data) {
114
0
  const int n = noise_tx->block_size * noise_tx->block_size;
115
0
  noise_tx->ifft(noise_tx->tx_block, noise_tx->temp, data);
116
0
  for (int i = 0; i < n; ++i) {
117
0
    data[i] /= n;
118
0
  }
119
0
}
120
121
void aom_noise_tx_add_energy(const struct aom_noise_tx_t *noise_tx,
122
0
                             float *psd) {
123
0
  const int block_size = noise_tx->block_size;
124
0
  for (int yb = 0; yb < block_size; ++yb) {
125
0
    for (int xb = 0; xb <= block_size / 2; ++xb) {
126
0
      float *c = noise_tx->tx_block + 2 * (yb * block_size + xb);
127
0
      psd[yb * block_size + xb] += c[0] * c[0] + c[1] * c[1];
128
0
    }
129
0
  }
130
0
}
131
132
0
void aom_noise_tx_free(struct aom_noise_tx_t *noise_tx) {
133
0
  if (!noise_tx) return;
134
0
  aom_free(noise_tx->tx_block);
135
0
  aom_free(noise_tx->temp);
136
0
  aom_free(noise_tx);
137
0
}
138
139
double aom_normalized_cross_correlation(const double *a, const double *b,
140
0
                                        int n) {
141
0
  double c = 0;
142
0
  double a_len = 0;
143
0
  double b_len = 0;
144
0
  for (int i = 0; i < n; ++i) {
145
0
    a_len += a[i] * a[i];
146
0
    b_len += b[i] * b[i];
147
0
    c += a[i] * b[i];
148
0
  }
149
0
  return c / (sqrt(a_len) * sqrt(b_len));
150
0
}
151
152
0
int aom_noise_data_validate(const double *data, int w, int h) {
153
0
  const double kVarianceThreshold = 2;
154
0
  const double kMeanThreshold = 2;
155
156
0
  int x = 0, y = 0;
157
0
  int ret_value = 1;
158
0
  double var = 0, mean = 0;
159
0
  double *mean_x, *mean_y, *var_x, *var_y;
160
161
  // Check that noise variance is not increasing in x or y
162
  // and that the data is zero mean.
163
0
  mean_x = (double *)aom_calloc(w, sizeof(*mean_x));
164
0
  var_x = (double *)aom_calloc(w, sizeof(*var_x));
165
0
  mean_y = (double *)aom_calloc(h, sizeof(*mean_x));
166
0
  var_y = (double *)aom_calloc(h, sizeof(*var_y));
167
0
  if (!(mean_x && var_x && mean_y && var_y)) {
168
0
    aom_free(mean_x);
169
0
    aom_free(mean_y);
170
0
    aom_free(var_x);
171
0
    aom_free(var_y);
172
0
    return 0;
173
0
  }
174
175
0
  for (y = 0; y < h; ++y) {
176
0
    for (x = 0; x < w; ++x) {
177
0
      const double d = data[y * w + x];
178
0
      var_x[x] += d * d;
179
0
      var_y[y] += d * d;
180
0
      mean_x[x] += d;
181
0
      mean_y[y] += d;
182
0
      var += d * d;
183
0
      mean += d;
184
0
    }
185
0
  }
186
0
  mean /= (w * h);
187
0
  var = var / (w * h) - mean * mean;
188
189
0
  for (y = 0; y < h; ++y) {
190
0
    mean_y[y] /= h;
191
0
    var_y[y] = var_y[y] / h - mean_y[y] * mean_y[y];
192
0
    if (fabs(var_y[y] - var) >= kVarianceThreshold) {
193
0
      fprintf(stderr, "Variance distance too large %f %f\n", var_y[y], var);
194
0
      ret_value = 0;
195
0
      break;
196
0
    }
197
0
    if (fabs(mean_y[y] - mean) >= kMeanThreshold) {
198
0
      fprintf(stderr, "Mean distance too large %f %f\n", mean_y[y], mean);
199
0
      ret_value = 0;
200
0
      break;
201
0
    }
202
0
  }
203
204
0
  for (x = 0; x < w; ++x) {
205
0
    mean_x[x] /= w;
206
0
    var_x[x] = var_x[x] / w - mean_x[x] * mean_x[x];
207
0
    if (fabs(var_x[x] - var) >= kVarianceThreshold) {
208
0
      fprintf(stderr, "Variance distance too large %f %f\n", var_x[x], var);
209
0
      ret_value = 0;
210
0
      break;
211
0
    }
212
0
    if (fabs(mean_x[x] - mean) >= kMeanThreshold) {
213
0
      fprintf(stderr, "Mean distance too large %f %f\n", mean_x[x], mean);
214
0
      ret_value = 0;
215
0
      break;
216
0
    }
217
0
  }
218
219
0
  aom_free(mean_x);
220
0
  aom_free(mean_y);
221
0
  aom_free(var_x);
222
0
  aom_free(var_y);
223
224
0
  return ret_value;
225
0
}