in libvmaf/src/feature/adm_tools.c [97:229]
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)
{
#ifdef ADM_OPT_AVOID_ATAN
const float cos_1deg_sq = cos(1.0 * M_PI / 180.0) * cos(1.0 * M_PI / 180.0);
#endif
const float eps = 1e-30;
int ref_px_stride = ref_stride / sizeof(float);
int dis_px_stride = dis_stride / sizeof(float);
int r_px_stride = r_stride / sizeof(float);
int a_px_stride = a_stride / sizeof(float);
/* The computation of the score is not required for the regions which lie outside the frame borders */
int left = w * border_factor - 0.5 - 1; // -1 for filter tap
int top = h * border_factor - 0.5 - 1;
int right = w - left + 2; // +2 for filter tap
int bottom = h - top + 2;
if (left < 0) {
left = 0;
}
if (right > w) {
right = w;
}
if (top < 0) {
top = 0;
}
if (bottom > h) {
bottom = h;
}
float oh, ov, od, th, tv, td;
float kh, kv, kd, rst_h, rst_v, rst_d;
#ifdef ADM_OPT_AVOID_ATAN
float ot_dp, o_mag_sq, t_mag_sq;
#else
float oa, ta, diff;
#endif
int angle_flag;
int i, j;
for (i = top; i < bottom; ++i) {
for (j = left; j < right; ++j) {
oh = ref->band_h[i * ref_px_stride + j];
ov = ref->band_v[i * ref_px_stride + j];
od = ref->band_d[i * ref_px_stride + j];
th = dis->band_h[i * dis_px_stride + j];
tv = dis->band_v[i * dis_px_stride + j];
td = dis->band_d[i * dis_px_stride + j];
kh = DIVS(th, oh + eps);
kv = DIVS(tv, ov + eps);
kd = DIVS(td, od + eps);
kh = kh < 0.0f ? 0.0f : (kh > 1.0f ? 1.0f : kh);
kv = kv < 0.0f ? 0.0f : (kv > 1.0f ? 1.0f : kv);
kd = kd < 0.0f ? 0.0f : (kd > 1.0f ? 1.0f : kd);
rst_h = kh * oh;
rst_v = kv * ov;
rst_d = kd * od;
#ifdef ADM_OPT_AVOID_ATAN
/* Determine if angle between (oh,ov) and (th,tv) is less than 1 degree.
* Given that u is the angle (oh,ov) and v is the angle (th,tv), this can
* be done by testing the inequvality.
*
* { (u.v.) >= 0 } AND { (u.v)^2 >= cos(1deg)^2 * ||u||^2 * ||v||^2 }
*
* Proof:
*
* cos(theta) = (u.v) / (||u|| * ||v||)
*
* IF u.v >= 0 THEN
* cos(theta)^2 = (u.v)^2 / (||u||^2 * ||v||^2)
* (u.v)^2 = cos(theta)^2 * ||u||^2 * ||v||^2
*
* IF |theta| < 1deg THEN
* (u.v)^2 >= cos(1deg)^2 * ||u||^2 * ||v||^2
* END
* ELSE
* |theta| > 90deg
* END
*/
ot_dp = oh * th + ov * tv;
o_mag_sq = oh * oh + ov * ov;
t_mag_sq = th * th + tv * tv;
angle_flag = (ot_dp >= 0.0f) && (ot_dp * ot_dp >= cos_1deg_sq * o_mag_sq * t_mag_sq);
#else
oa = atanf(DIVS(ov, oh + eps));
ta = atanf(DIVS(tv, th + eps));
if (oh < 0.0f)
oa += (float)M_PI;
if (th < 0.0f)
ta += (float)M_PI;
diff = fabsf(oa - ta) * 180.0f / M_PI;
angle_flag = diff < 1.0f;
#endif
/* ==== original ==== */
// if (angle_flag) {
// rst_h = th;
// rst_v = tv;
// rst_d = td;
// }
/* ==== modification ==== */
if (angle_flag && (rst_h > 0.0)) rst_h = MIN(rst_h * adm_enhn_gain_limit, th);
if (angle_flag && (rst_h < 0.0)) rst_h = MAX(rst_h * adm_enhn_gain_limit, th);
if (angle_flag && (rst_v > 0.0)) rst_v = MIN(rst_v * adm_enhn_gain_limit, tv);
if (angle_flag && (rst_v < 0.0)) rst_v = MAX(rst_v * adm_enhn_gain_limit, tv);
if (angle_flag && (rst_d > 0.0)) rst_d = MIN(rst_d * adm_enhn_gain_limit, td);
if (angle_flag && (rst_d < 0.0)) rst_d = MAX(rst_d * adm_enhn_gain_limit, td);
/* == end of modification == */
r->band_h[i * r_px_stride + j] = rst_h;
r->band_v[i * r_px_stride + j] = rst_v;
r->band_d[i * r_px_stride + j] = rst_d;
a->band_h[i * a_px_stride + j] = th - rst_h;
a->band_v[i * a_px_stride + j] = tv - rst_v;
a->band_d[i * a_px_stride + j] = td - rst_d;
}
}
}