void adm_decouple_s()

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;
		}
	}
}