Source code for pyiqa.matlab_utils.nss_feature
import torch
from typing import Tuple
[docs]
def estimate_aggd_param(
block: torch.Tensor, return_sigma=False
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
"""Estimate AGGD (Asymmetric Generalized Gaussian Distribution) parameters.
Args:
block (Tensor): Image block with shape (b, 1, h, w).
Returns:
Tensor: alpha, beta_l and beta_r for the AGGD distribution
(Estimating the parames in Equation 7 in the paper).
"""
gam = torch.arange(0.2, 10 + 0.001, 0.001).to(block)
r_gam = (
2 * torch.lgamma(2.0 / gam)
- (torch.lgamma(1.0 / gam) + torch.lgamma(3.0 / gam))
).exp()
r_gam = r_gam.repeat(block.shape[0], 1)
mask_left = block < 0
mask_right = block > 0
count_left = mask_left.sum(dim=(-1, -2), dtype=torch.float32)
count_right = mask_right.sum(dim=(-1, -2), dtype=torch.float32)
left_std = torch.sqrt((block * mask_left).pow(2).sum(dim=(-1, -2)) / (count_left))
right_std = torch.sqrt(
(block * mask_right).pow(2).sum(dim=(-1, -2)) / (count_right)
)
gammahat = left_std / right_std
rhat = block.abs().mean(dim=(-1, -2)).pow(2) / block.pow(2).mean(dim=(-1, -2))
rhatnorm = (rhat * (gammahat.pow(3) + 1) * (gammahat + 1)) / (
gammahat.pow(2) + 1
).pow(2)
array_position = (r_gam - rhatnorm).abs().argmin(dim=-1)
alpha = gam[array_position]
beta_l = (
left_std.squeeze(-1)
* (torch.lgamma(1 / alpha) - torch.lgamma(3 / alpha)).exp().sqrt()
)
beta_r = (
right_std.squeeze(-1)
* (torch.lgamma(1 / alpha) - torch.lgamma(3 / alpha)).exp().sqrt()
)
if return_sigma:
return alpha, left_std.squeeze(-1), right_std.squeeze(-1)
else:
return alpha, beta_l, beta_r
[docs]
def compute_nss_features(luma_nrmlzd: torch.Tensor) -> torch.Tensor:
alpha, betal, betar = estimate_aggd_param(luma_nrmlzd, return_sigma=False)
features = [alpha, (betal + betar) / 2]
shifts = [(0, 1), (1, 0), (1, 1), (-1, 1)]
for shift in shifts:
shifted_luma_nrmlzd = torch.roll(luma_nrmlzd, shifts=shift, dims=(-2, -1))
alpha, betal, betar = estimate_aggd_param(
luma_nrmlzd * shifted_luma_nrmlzd, return_sigma=False
)
distmean = (betar - betal) * torch.exp(
torch.lgamma(2 / alpha) - torch.lgamma(1 / alpha)
)
features.extend((alpha, distmean, betal, betar))
return torch.stack(features, dim=-1)