in libvmaf/src/feature/adm_tools.c [365:802]
float adm_cm_s(const adm_dwt_band_t_s *src, const adm_dwt_band_t_s *csf_f,
const adm_dwt_band_t_s *csf_a, int w, int h, int src_stride,
int flt_stride, int csf_a_stride, double border_factor, int scale,
double adm_norm_view_dist, int adm_ref_display_height, int adm_csf_mode)
{
(void)flt_stride;
(void)adm_csf_mode;
// for ADM: scales goes from 0 to 3 but in noise floor paper, it goes from
// 1 to 4 (from finest scale to coarsest scale).
// TODO: we will add more CSF functions here
float factor1, factor2;
factor1 = 1.0f / dwt_quant_step(&dwt_7_9_YCbCr_threshold[0], scale, 1, adm_norm_view_dist, adm_ref_display_height);
factor2 = 1.0f / dwt_quant_step(&dwt_7_9_YCbCr_threshold[0], scale, 2, adm_norm_view_dist, adm_ref_display_height);
float rfactor[3] = { factor1, factor1, factor2 };
const float *angles[3] = { csf_a->band_h, csf_a->band_v, csf_a->band_d };
const float *flt_angles[3] = { csf_f->band_h, csf_f->band_v, csf_f->band_d };
int src_px_stride = src_stride / sizeof(float);
int csf_px_stride = csf_a_stride / sizeof(float);
float xh, xv, xd, thr;
float val;
float accum_h = 0, accum_v = 0, accum_d = 0;
float accum_inner_h, accum_inner_v, accum_inner_d;
float num_scale_h, num_scale_v, num_scale_d;
/* The computation of the scales is not required for the regions which lie outside the frame borders */
int left = w * border_factor - 0.5;
int top = h * border_factor - 0.5;
int right = w - left;
int bottom = h - top;
int start_col = (left > 1) ? left : 1;
int end_col = (right < (w - 1)) ? right : (w - 1);
int start_row = (top > 1) ? top : 1;
int end_row = (bottom < (h - 1)) ? bottom : (h - 1);
int i, j;
/* i=0,j=0 */
accum_inner_h = 0;
accum_inner_v = 0;
accum_inner_d = 0;
if ((top <= 0) && (left <= 0))
{
xh = src->band_h[0] * rfactor[0];
xv = src->band_v[0] * rfactor[1];
xd = src->band_d[0] * rfactor[2];
ADM_CM_THRESH_S_0_0(angles, flt_angles, csf_px_stride, &thr, w, h, 0, 0);
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
}
/* i=0, j */
if (top <= 0) {
for (j = start_col; j < end_col; ++j) {
xh = src->band_h[j] * rfactor[0];
xv = src->band_v[j] * rfactor[1];
xd = src->band_d[j] * rfactor[2];
ADM_CM_THRESH_S_0_J(angles, flt_angles, csf_px_stride, &thr, w, h, 0, j);
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
}
}
/* i=0,j=w-1 */
if ((top <= 0) && (right > (w - 1)))
{
xh = src->band_h[w - 1] * rfactor[0];
xv = src->band_v[w - 1] * rfactor[1];
xd = src->band_d[w - 1] * rfactor[2];
ADM_CM_THRESH_S_0_W_M_1(angles, flt_angles, csf_px_stride, &thr, w, h, 0, (w - 1));
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
}
accum_h += accum_inner_h;
accum_v += accum_inner_v;
accum_d += accum_inner_d;
if ((left > 0) && (right <= (w - 1))) /* Completely within frame */
{
for (i = start_row; i < end_row; ++i) {
accum_inner_h = 0;
accum_inner_v = 0;
accum_inner_d = 0;
for (j = start_col; j < end_col; ++j) {
xh = src->band_h[i * src_px_stride + j] * rfactor[0];
xv = src->band_v[i * src_px_stride + j] * rfactor[1];
xd = src->band_d[i * src_px_stride + j] * rfactor[2];
ADM_CM_THRESH_S_I_J(angles, flt_angles, csf_px_stride, &thr, w, h, i, j);
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
}
accum_h += accum_inner_h;
accum_v += accum_inner_v;
accum_d += accum_inner_d;
}
}
else if ((left <= 0) && (right <= (w - 1))) /* Right border within frame, left outside */
{
for (i = start_row; i < end_row; ++i) {
accum_inner_h = 0;
accum_inner_v = 0;
accum_inner_d = 0;
/* j = 0 */
xh = src->band_h[i * src_px_stride] * rfactor[0];
xv = src->band_v[i * src_px_stride] * rfactor[1];
xd = src->band_d[i * src_px_stride] * rfactor[2];
ADM_CM_THRESH_S_I_0(angles, flt_angles, csf_px_stride, &thr, w, h, i, 0);
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
/* j within frame */
for (j = start_col; j < end_col; ++j) {
xh = src->band_h[i * src_px_stride + j] * rfactor[0];
xv = src->band_v[i * src_px_stride + j] * rfactor[1];
xd = src->band_d[i * src_px_stride + j] * rfactor[2];
ADM_CM_THRESH_S_I_J(angles, flt_angles, csf_px_stride, &thr, w, h, i, j);
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
}
accum_h += accum_inner_h;
accum_v += accum_inner_v;
accum_d += accum_inner_d;
}
}
else if ((left > 0) && (right > (w - 1))) /* Left border within frame, right outside */
{
for (i = start_row; i < end_row; ++i) {
accum_inner_h = 0;
accum_inner_v = 0;
accum_inner_d = 0;
/* j within frame */
for (j = start_col; j < end_col; ++j) {
xh = src->band_h[i * src_px_stride + j] * rfactor[0];
xv = src->band_v[i * src_px_stride + j] * rfactor[1];
xd = src->band_d[i * src_px_stride + j] * rfactor[2];
ADM_CM_THRESH_S_I_J(angles, flt_angles, csf_px_stride, &thr, w, h, i, j);
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
}
/* j = w-1 */
xh = src->band_h[i * src_px_stride + w - 1] * rfactor[0];
xv = src->band_v[i * src_px_stride + w - 1] * rfactor[1];
xd = src->band_d[i * src_px_stride + w - 1] * rfactor[2];
ADM_CM_THRESH_S_I_W_M_1(angles, flt_angles, csf_px_stride, &thr, w, h, i, (w - 1));
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
accum_h += accum_inner_h;
accum_v += accum_inner_v;
accum_d += accum_inner_d;
}
}
else /* Both borders outside frame */
{
for (i = start_row; i < end_row; ++i) {
accum_inner_h = 0;
accum_inner_v = 0;
accum_inner_d = 0;
/* j = 0 */
xh = src->band_h[i * src_px_stride] * rfactor[0];
xv = src->band_v[i * src_px_stride] * rfactor[1];
xd = src->band_d[i * src_px_stride] * rfactor[2];
ADM_CM_THRESH_S_I_0(angles, flt_angles, csf_px_stride, &thr, w, h, i, 0);
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
/* j within frame */
for (j = start_col; j < end_col; ++j) {
xh = src->band_h[i * src_px_stride + j] * rfactor[0];
xv = src->band_v[i * src_px_stride + j] * rfactor[1];
xd = src->band_d[i * src_px_stride + j] * rfactor[2];
ADM_CM_THRESH_S_I_J(angles, flt_angles, csf_px_stride, &thr, w, h, i, j);
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
}
/* j = w-1 */
xh = src->band_h[i * src_px_stride + w - 1] * rfactor[0];
xv = src->band_v[i * src_px_stride + w - 1] * rfactor[1];
xd = src->band_d[i * src_px_stride + w - 1] * rfactor[2];
ADM_CM_THRESH_S_I_W_M_1(angles, flt_angles, csf_px_stride, &thr, w, h, i, (w - 1));
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
accum_h += accum_inner_h;
accum_v += accum_inner_v;
accum_d += accum_inner_d;
}
}
accum_inner_h = 0;
accum_inner_v = 0;
accum_inner_d = 0;
/* i=h-1,j=0 */
if ((bottom > (h - 1)) && (left <= 0))
{
xh = src->band_h[(h - 1) * src_px_stride] * rfactor[0];
xv = src->band_v[(h - 1) * src_px_stride] * rfactor[1];
xd = src->band_d[(h - 1) * src_px_stride] * rfactor[2];
ADM_CM_THRESH_S_H_M_1_0(angles, flt_angles, csf_px_stride, &thr, w, h, (h - 1), 0);
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
}
/* i=h-1,j */
if (bottom > (h - 1)) {
for (j = start_col; j < end_col; ++j) {
xh = src->band_h[(h - 1) * src_px_stride + j] * rfactor[0];
xv = src->band_v[(h - 1) * src_px_stride + j] * rfactor[1];
xd = src->band_d[(h - 1) * src_px_stride + j] * rfactor[2];
ADM_CM_THRESH_S_H_M_1_J(angles, flt_angles, csf_px_stride, &thr, w, h, (h - 1), j);
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
}
}
/* i-h-1,j=w-1 */
if ((bottom > (h - 1)) && (right > (w - 1)))
{
xh = src->band_h[(h - 1) * src_px_stride + w - 1] * rfactor[0];
xv = src->band_v[(h - 1) * src_px_stride + w - 1] * rfactor[1];
xd = src->band_d[(h - 1) * src_px_stride + w - 1] * rfactor[2];
ADM_CM_THRESH_S_H_M_1_W_M_1(angles, flt_angles, csf_px_stride, &thr, w, h, (h - 1), (w - 1));
xh = fabsf(xh) - thr;
xv = fabsf(xv) - thr;
xd = fabsf(xd) - thr;
xh = xh < 0.0f ? 0.0f : xh;
xv = xv < 0.0f ? 0.0f : xv;
xd = xd < 0.0f ? 0.0f : xd;
val = (xh * xh * xh);
accum_inner_h += val;
val = (xv * xv * xv);
accum_inner_v += val;
val = (xd * xd * xd);
accum_inner_d += val;
}
accum_h += accum_inner_h;
accum_v += accum_inner_v;
accum_d += accum_inner_d;
num_scale_h = powf(accum_h, 1.0f / 3.0f) + powf((bottom - top) * (right - left) / 32.0f, 1.0f / 3.0f);
num_scale_v = powf(accum_v, 1.0f / 3.0f) + powf((bottom - top) * (right - left) / 32.0f, 1.0f / 3.0f);
num_scale_d = powf(accum_d, 1.0f / 3.0f) + powf((bottom - top) * (right - left) / 32.0f, 1.0f / 3.0f);
return (num_scale_h + num_scale_v + num_scale_d);
}