Neil Birkbeck | ed25a61 | 2017-12-21 13:18:32 -0800 | [diff] [blame] | 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 | |
| 17 | #include "aom_dsp/noise_util.h" |
| 18 | #include "aom_mem/aom_mem.h" |
| 19 | |
| 20 | // Return normally distrbuted values with standard deviation of sigma. |
| 21 | double aom_randn(double sigma) { |
| 22 | while (1) { |
| 23 | const double u = 2.0 * ((double)rand()) / RAND_MAX - 1.0; |
| 24 | const double v = 2.0 * ((double)rand()) / RAND_MAX - 1.0; |
| 25 | const double s = u * u + v * v; |
| 26 | if (s > 0 && s < 1) { |
| 27 | return sigma * (u * sqrt(-2.0 * log(s) / s)); |
| 28 | } |
| 29 | } |
| 30 | return 0; |
| 31 | } |
| 32 | |
| 33 | double aom_normalized_cross_correlation(const double *a, const double *b, |
| 34 | int n) { |
| 35 | double c = 0; |
| 36 | double a_len = 0; |
| 37 | double b_len = 0; |
| 38 | for (int i = 0; i < n; ++i) { |
| 39 | a_len += a[i] * a[i]; |
| 40 | b_len += b[i] * b[i]; |
| 41 | c += a[i] * b[i]; |
| 42 | } |
| 43 | return c / (sqrt(a_len) * sqrt(b_len)); |
| 44 | } |
| 45 | |
| 46 | void aom_noise_synth(int lag, int n, const int (*coords)[2], |
| 47 | const double *coeffs, double *data, int w, int h) { |
| 48 | const int pad_size = 3 * lag; |
| 49 | const int padded_w = w + pad_size; |
| 50 | const int padded_h = h + pad_size; |
| 51 | int x = 0, y = 0; |
| 52 | double *padded = (double *)aom_malloc(padded_w * padded_h * sizeof(*padded)); |
| 53 | |
| 54 | for (y = 0; y < padded_h; ++y) { |
| 55 | for (x = 0; x < padded_w; ++x) { |
| 56 | padded[y * padded_w + x] = aom_randn(1.0); |
| 57 | } |
| 58 | } |
| 59 | for (y = lag; y < padded_h; ++y) { |
| 60 | for (x = lag; x < padded_w; ++x) { |
| 61 | double sum = 0; |
| 62 | int i = 0; |
| 63 | for (i = 0; i < n; ++i) { |
| 64 | const int dx = coords[i][0]; |
| 65 | const int dy = coords[i][1]; |
| 66 | sum += padded[(y + dy) * padded_w + (x + dx)] * coeffs[i]; |
| 67 | } |
| 68 | padded[y * padded_w + x] += sum; |
| 69 | } |
| 70 | } |
| 71 | // Copy over the padded rows to the output |
| 72 | for (y = 0; y < h; ++y) { |
| 73 | memcpy(data + y * w, padded + y * padded_w, sizeof(*data) * w); |
| 74 | } |
| 75 | aom_free(padded); |
| 76 | } |
| 77 | |
| 78 | int aom_noise_data_validate(const double *data, int w, int h) { |
| 79 | const double kVarianceThreshold = 2; |
| 80 | const double kMeanThreshold = 2; |
| 81 | |
| 82 | int x = 0, y = 0; |
| 83 | int ret_value = 1; |
| 84 | double var = 0, mean = 0; |
| 85 | double *mean_x, *mean_y, *var_x, *var_y; |
| 86 | |
| 87 | // Check that noise variance is not increasing in x or y |
| 88 | // and that the data is zero mean. |
| 89 | mean_x = (double *)aom_malloc(sizeof(*mean_x) * w); |
| 90 | var_x = (double *)aom_malloc(sizeof(*var_x) * w); |
| 91 | mean_y = (double *)aom_malloc(sizeof(*mean_x) * h); |
| 92 | var_y = (double *)aom_malloc(sizeof(*var_y) * h); |
| 93 | |
| 94 | memset(mean_x, 0, sizeof(*mean_x) * w); |
| 95 | memset(var_x, 0, sizeof(*var_x) * w); |
| 96 | memset(mean_y, 0, sizeof(*mean_y) * h); |
| 97 | memset(var_y, 0, sizeof(*var_y) * h); |
| 98 | |
| 99 | for (y = 0; y < h; ++y) { |
| 100 | for (x = 0; x < w; ++x) { |
| 101 | const double d = data[y * w + x]; |
| 102 | var_x[x] += d * d; |
| 103 | var_y[y] += d * d; |
| 104 | mean_x[x] += d; |
| 105 | mean_y[y] += d; |
| 106 | var += d * d; |
| 107 | mean += d; |
| 108 | } |
| 109 | } |
| 110 | mean /= (w * h); |
| 111 | var = var / (w * h) - mean * mean; |
| 112 | |
| 113 | for (y = 0; y < h; ++y) { |
| 114 | mean_y[y] /= h; |
| 115 | var_y[y] = var_y[y] / h - mean_y[y] * mean_y[y]; |
| 116 | if (fabs(var_y[y] - var) >= kVarianceThreshold) { |
| 117 | fprintf(stderr, "Variance distance too large %f %f\n", var_y[y], var); |
| 118 | ret_value = 0; |
| 119 | break; |
| 120 | } |
| 121 | if (fabs(mean_y[y] - mean) >= kMeanThreshold) { |
| 122 | fprintf(stderr, "Mean distance too large %f %f\n", mean_y[y], mean); |
| 123 | ret_value = 0; |
| 124 | break; |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | for (x = 0; x < w; ++x) { |
| 129 | mean_x[x] /= w; |
| 130 | var_x[x] = var_x[x] / w - mean_x[x] * mean_x[x]; |
| 131 | if (fabs(var_x[x] - var) >= kVarianceThreshold) { |
| 132 | fprintf(stderr, "Variance distance too large %f %f\n", var_x[x], var); |
| 133 | ret_value = 0; |
| 134 | break; |
| 135 | } |
| 136 | if (fabs(mean_x[x] - mean) >= kMeanThreshold) { |
| 137 | fprintf(stderr, "Mean distance too large %f %f\n", mean_x[x], mean); |
| 138 | ret_value = 0; |
| 139 | break; |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | aom_free(mean_x); |
| 144 | aom_free(mean_y); |
| 145 | aom_free(var_x); |
| 146 | aom_free(var_y); |
| 147 | |
| 148 | return ret_value; |
| 149 | } |