def ergas(GT, P, r=4, ws=8):
    """calculates erreur relative globale adimensionnelle de synthese (ergas).

	:param GT: first (original) input image.
	:param P: second (deformed) input image.
	:param r: ratio of high resolution to low resolution (default=4).
	:param ws: sliding window size (default = 8).

	:returns:  float -- ergas value.
	"""
    GT, P = _initial_check(GT, P)

    rmse_map = None
    nb = 1

    _, rmse_map = rmse_sw(GT, P, ws)

    means_map = uniform_filter(GT, ws) / ws**2

    # Avoid division by zero
    idx = means_map == 0
    means_map[idx] = 1
    rmse_map[idx] = 0

    ergasroot = np.sqrt(np.sum(((rmse_map**2) / (means_map**2)), axis=2) / nb)
    ergas_map = 100 * r * ergasroot

    s = int(np.round(ws / 2))
    return np.mean(ergas_map[s:-s, s:-s])
def mse(GT, P):
    """Calculates mean squared error (mse).

	:param GT: first (original) input image
	:paran P: second (deformed) input image

	:returns: float -- mse value
	"""
    GT, P = _initial_check(GT, P)
    return np.mean((GT.astype(np.float64) - P.astype(np.float64))**2)
def rmse(GT, P):
    """Calculates root mean squared error (rmse).

	:param GT: first (original) input image
	:paran P: second (deformed) input image

	:returns: float -- rmse value
	"""
    GT, P = _initial_check(GT, P)
    return np.sqrt(mse(Gt, P))
def uqi(GT, P, ws=8):
    """calculates universal image quality index (uqi).

	:param GT: first (original) input image.
	:param P: second (deformed) input image.
	:param ws: sliding window size (default = 8).

	:returns:  float -- uqi value.
	"""
    GT, P = _initial_check(GT, P)
    return np.mean(
        [_uqi_single(GT[:, :, i], P[:, :, i], ws) for i in range(GT.shape[2])])
def msssim(GT,
           P,
           weights=[0.0448, 0.2856, 0.3001, 0.2363, 0.1333],
           ws=11,
           K1=0.01,
           K2=0.03,
           MAX=None):
    """calculates multi-scale structural similarity index (ms-ssim).

	:param GT: first (original) input image.
	:param P: second (deformed) input image.
	:param weights: weights for each scale (default = [0.0448, 0.2856, 0.3001, 0.2363, 0.1333]).
	:param ws: sliding window size (default = 11).
	:param K1: First constant for SSIM (default = 0.01).
	:param K2: Second constant for SSIM (default = 0.03).
	:param MAX: Maximum value of datarange (if None, MAX is calculated using image dtype).

	:returns:  float -- ms-ssim value.
	"""
    if MAX is None:
        MAX = np.iinfo(GT.dtype).max

    GT, P = _initial_check(GT, P)

    scales = len(weights)

    fltr_specs = dict(fltr=Filter.GAUSSIAN, sigma=1.5, ws=11)

    if isinstance(weights, list):
        weights = np.array(weights)

    mssim = []
    mcs = []
    for _ in range(scales):
        _ssim, _cs = ssim(GT,
                          P,
                          ws=ws,
                          K1=K1,
                          K2=K2,
                          MAX=MAX,
                          fltr_specs=fltr_specs)
        mssim.append(_ssim)
        mcs.append(_cs)

        filtered = [uniform_filter(im, 2) for im in [GT, P]]
        GT, P = [x[::2, ::2, :] for x in filtered]
    mssim = np.array(mssim, dtype=np.float64)
    mcs = np.array(mcs, dtype=np.float64)
    return np.prod(_power_complex(mcs[:scales - 1],
                                  weights[:scales - 1])) * _power_complex(
                                      mssim[scales - 1], weights[scales - 1])
def vifp(GT, P, sigma_nsq=2):
    """calculates Pixel Based Visual Information Fidelity (vif-p).

	:param GT: first (original) input image.
	:param P: second (deformed) input image.
	:param sigma_nsq: variance of the visual noise (default = 2)

	:returns:  float -- vif-p value.
	"""
    GT, P = _initial_check(GT, P)
    # GT,P = GT[:,:,np.newaxis],P[:,:,np.newaxis]
    return np.mean([
        _vifp_single(GT[:, :, i], P[:, :, i], sigma_nsq)
        for i in range(GT.shape[2])
    ])
def scc(GT, P, win=[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], ws=8):
    """calculates spatial correlation coefficient (scc).

	:param GT: first (original) input image.
	:param P: second (deformed) input image.
	:param fltr: high pass filter for spatial processing (default=[[-1,-1,-1],[-1,8,-1],[-1,-1,-1]]).
	:param ws: sliding window size (default = 8).

	:returns:  float -- scc value.
	"""
    GT, P = _initial_check(GT, P)

    coefs = np.zeros(GT.shape)
    for i in range(GT.shape[2]):
        coefs[:, :, i] = _scc_single(GT[:, :, i], P[:, :, i], win, ws)
    return np.mean(coefs)
def psnr(GT, P, MAX=None):
    """Calculates peak signal-to-noise ratio (psnr)

	:param GT: frist (orginal) input image.
	:param P: second (deformed) input image.
	:param MAX: maximum value of datarange (if None, MAX is calculated using image dtype)

	return: float -- psnr value in dB.
	"""
    if MAX is None:
        MAX = np.iinfo(GT.dtype).max
    GT, P = _initial_check(GT, P)
    mse_value = mse(GT, P)
    if mse_value == 0:
        return np.inf
    return 10 * np.log10(MAX**2 / mse_value)
def rmse_sw(GT, P, ws=8):
    """calculates root mean squared error (rmse) using sliding window.

	:param GT: first (original) input image.
	:param P: second (deformed) input image.
	:param ws: sliding window size (default = 8).

	:returns:  tuple -- rmse value,rmse map.	
	"""
    GT, P = _initial_check(GT, P)

    rmse_map = np.zeros(GT.shape)
    vals = np.zeros(GT.shape[2])
    for i in range(GT.shape[2]):
        vals[i], rmse_map[:, :, i] = _rmse_sw_single(GT[:, :, i], P[:, :, i],
                                                     ws)
    return np.mean(vals), rmse_map
def rase(GT, P, ws=8):
    """calculates relative average spectral error (rase).

	:param GT: first (original) input image.
	:param P: second (deformed) input image.
	:param ws: sliding window size (default = 8).

	:returns:  float -- rase value.
	"""
    GT, P = _initial_check(GT, P)
    _, rmse_map = rmse_sw(GT, P, ws)
    GT_means = uniform_filter(GT, ws) / ws**2

    N = GT.shape[2]
    M = np.sum(GT_means, axis=2) / N
    rase_map = (100. / M) * np.sqrt(np.sum(rmse_map**2, axis=2) / N)

    s = int(np.round(ws / 2))
    return np.mean(rase_map[s:-s, s:-s])
def sam(GT, P):
    """calculates spectral angle mapper (sam).

	:param GT: first (original) input image.
	:param P: second (deformed) input image.

	:returns:  float -- sam value.
	"""
    GT, P = _initial_check(GT, P)

    GT = GT.reshape((GT.shape[0] * GT.shape[1], GT.shape[2]))
    P = P.reshape((P.shape[0] * P.shape[1], P.shape[2]))

    N = GT.shape[1]
    sam_angles = np.zeros(N)
    for i in range(GT.shape[1]):
        val = np.clip(
            np.dot(GT[:, i], P[:, i]) /
            (np.linalg.norm(GT[:, i]) * np.linalg.norm(P[:, i])), -1, 1)
        sam_angles[i] = np.arccos(val)
    return np.mean(sam_angles)
def vif(Org, Dis, sigma_n=2):
    """calculates Pixel Based Visual Information Fidelity (vif).

	Org: first (original) input image.
	Dis: second (deformed) input image.
	sigma_n: variance of the visual noise (default = 2)
	"""
    Org, Dis = _initial_check(Org, Dis)
    #checking whther we are getting correct index within 0 and 1 or not
    #print(Org.shape[2])
    """print(Org[:,:,0])
	print(GT[:,:,1])
	print(GT[:,:,2])
	print(GT[:,:,3])
	"""
    #print(_vifp_single(GT[:,:,1],P[:,:,1],sigma_n))
    # GT,P = GT[:,:,np.newaxis],P[:,:,np.newaxis]
    #3 times because of r, g, b separate calculations
    return np.mean([
        _vif_single(Org[:, :, i], Dis[:, :, i], sigma_n)
        for i in range(Org.shape[2])
    ])
def ssim(GT,
         P,
         ws=11,
         K1=0.03,
         K2=0.03,
         MAX=None,
         fltr_specs=None,
         mode='valid'):
    """Calculates structural similarity index (ssim).

	:param GT: first (original) input image
	:param P: second (deformed) input image
	:param ws: sliding window size (default = 11)
	:param K1: first constant for SSIM (default = 0.01)
	:param K2: second constant for SSIM (default = 0.03)
	:param MAX: Maximum value of datarange (if None, MAX is calculated using image dtype).

	:returns:  tuple -- ssim value, cs value.
	"""
    if MAX is None:
        MAX = np.iinfo(GT.dtype).max

    GT, P = _initial_check(GT, P)

    if fltr_specs is None:
        fltr_specs = dict(fltr=Filter.UNIFORM, ws=ws)
    C1 = (K1 * MAX)**2
    C2 = (K2 * MAX)**2

    ssims = []
    css = []
    for i in range(GT.shape[2]):
        ssim, cs = _ssim_single(GT[:, :, i], P[:, :, i], ws, C1, C2,
                                fltr_specs, mode)
        ssims.append(ssim)
        css.append(cs)
    return np.mean(ssims), np.mean(css)