libvmaf/src/feature/ansnr_tools.c (131 lines of code) (raw):
/**
*
* Copyright 2016-2020 Netflix, Inc.
*
* Licensed under the BSD+Patent License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSDplusPatent
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stddef.h>
#include "mem.h"
#include "ansnr_options.h"
#include "ansnr_tools.h"
#if 1
const float ansnr_filter1d_ref_s[3] = { 0.250138193, 0.499723613, 0.250138193 };
const float ansnr_filter1d_dis_s[5] = { 0.054488685, 0.244201347, 0.402619958, 0.244201347, 0.054488685 };
#else
const float ansnr_filter1d_ref_s[3] = { 0x1.00243ap-2, 0x1.ffb78cp-2, 0x1.00243ap-2 };
const float ansnr_filter1d_dis_s[5] = { 0x1.be5f0ep-5, 0x1.f41fd6p-3, 0x1.9c4868p-2, 0x1.f41fd6p-3, 0x1.be5f0ep-5 };
#endif
const int ansnr_filter1d_ref_width = 3;
const int ansnr_filter1d_dis_width = 5;
const float ansnr_filter2d_ref_s[3*3] = {
1.0 / 16.0, 2.0 / 16.0, 1.0 / 16.0,
2.0 / 16.0, 4.0 / 16.0, 2.0 / 16.0,
1.0 / 16.0, 2.0 / 16.0, 1.0 / 16.0
};
const float ansnr_filter2d_dis_s[5*5] = {
2.0 / 571.0, 7.0 / 571.0, 12.0 / 571.0, 7.0 / 571.0, 2.0 / 571.0,
7.0 / 571.0, 31.0 / 571.0, 52.0 / 571.0, 31.0 / 571.0, 7.0 / 571.0,
12.0 / 571.0, 52.0 / 571.0, 127.0 / 571.0, 52.0 / 571.0, 12.0 / 571.0,
7.0 / 571.0, 31.0 / 571.0, 52.0 / 571.0, 31.0 / 571.0, 7.0 / 571.0,
2.0 / 571.0, 7.0 / 571.0, 12.0 / 571.0, 7.0 / 571.0, 2.0 / 571.0
};
const int ansnr_filter2d_ref_width = 3;
const int ansnr_filter2d_dis_width = 5;
void ansnr_mse_s(const float *ref, const float *dis, float *sig, float *noise, int w, int h, int ref_stride, int dis_stride)
{
int ref_px_stride = ref_stride / sizeof(float);
int dis_px_stride = dis_stride / sizeof(float);
int i, j;
float ref_val, dis_val;
float sig_accum = 0;
float noise_accum = 0;
for (i = 0; i < h; ++i) {
float sig_accum_inner = 0;
float noise_accum_inner = 0;
for (j = 0; j < w; ++j) {
ref_val = ref[i * ref_px_stride + j];
dis_val = dis[i * dis_px_stride + j];
sig_accum_inner += ref_val * ref_val;
noise_accum_inner += (ref_val - dis_val) * (ref_val - dis_val);
}
sig_accum += sig_accum_inner;
noise_accum += noise_accum_inner;
}
if (sig)
*sig = sig_accum;
if (noise)
*noise = noise_accum;
}
void ansnr_filter1d_s(const float *f, const float *src, float *dst, int w, int h, int src_stride, int dst_stride, int fwidth)
{
int src_px_stride = src_stride / sizeof(float);
int dst_px_stride = dst_stride / sizeof(float);
float *tmp = aligned_malloc(ALIGN_CEIL(w * sizeof(float)), MAX_ALIGN);
float fcoeff, imgcoeff;
int i, j, fi, fj, ii, jj;
for (i = 0; i < h; ++i) {
/* Vertical pass. */
for (j = 0; j < w; ++j) {
float accum = 0;
for (fi = 0; fi < fwidth; ++fi) {
fcoeff = f[fi];
ii = i - fwidth / 2 + fi;
#ifdef ANSNR_OPT_BORDER_REPLICATE
ii = ii < 0 ? 0 : (ii > h - 1 ? h - 1 : ii);
imgcoeff = src[ii * src_px_stride + j];
#else
if (ii < 0) ii = -ii;
else if (ii >= h) ii = 2 * h - ii - 1;
imgcoeff = src[ii * src_px_stride + j];
#endif
accum += fcoeff * imgcoeff;
}
tmp[j] = accum;
}
/* Horizontal pass. */
for (j = 0; j < w; ++j) {
float accum = 0;
for (fj = 0; fj < fwidth; ++fj) {
fcoeff = f[fj];
jj = j - fwidth / 2 + fj;
#ifdef ANSNR_OPT_BORDER_REPLICATE
jj = jj < 0 ? 0 : (jj > w - 1 ? w - 1 : jj);
imgcoeff = tmp[jj];
#else
if (jj < 0) jj = -jj;
else if (jj >= w) jj = 2 * w - jj - 1;
imgcoeff = tmp[jj];
#endif
accum += fcoeff * imgcoeff;
}
dst[i * dst_px_stride + j] = accum;
}
}
aligned_free(tmp);
}
void ansnr_filter2d_s(const float *f, const float *src, float *dst, int w, int h, int src_stride, int dst_stride, int fwidth)
{
int src_px_stride = src_stride / sizeof(float);
int dst_px_stride = dst_stride / sizeof(float);
float fcoeff, imgcoeff;
int i, j, fi, fj, ii, jj;
for (i = 0; i < h; ++i) {
for (j = 0; j < w; ++j) {
float accum = 0;
for (fi = 0; fi < fwidth; ++fi) {
float accum_inner = 0;
for (fj = 0; fj < fwidth; ++fj) {
fcoeff = f[fi * fwidth + fj];
ii = i - fwidth / 2 + fi;
jj = j - fwidth / 2 + fj;
#ifdef ANSNR_OPT_BORDER_REPLICATE
ii = ii < 0 ? 0 : (ii > h - 1 ? h - 1 : ii);
jj = jj < 0 ? 0 : (jj > w - 1 ? w - 1 : jj);
imgcoeff = src[ii * src_px_stride + jj];
#else
if (ii < 0) ii = -ii;
else if (ii >= h) ii = 2 * h - ii - 1;
if (jj < 0) jj = -jj;
else if (jj >= w) jj = 2 * w - jj - 1;
imgcoeff = src[ii * src_px_stride + jj];
#endif
accum_inner += fcoeff * imgcoeff;
}
accum += accum_inner;
}
dst[i * dst_px_stride + j] = accum;
}
}
}