float adm_cm_s()

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