import torch


def noise(rgb, a, b):
    """
    Applies additional Poissonian-Gaussian noise

    :param rgb: 3xHxW input RGB image, float [0-1]
    :param a: variance factor of the signal-dependant noise (var = a*y(x))
    :param b: standard deviation of the signal-independant noise
    :return: modified image

    See Foi, Alessandro, et al. (2008):
    `Practical Poissonian-Gaussian noise modeling and fitting for single-image
    raw-data`,
    `PDF <http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.164.1943&rep=rep1&type=pdf>`_
    """

    if a > 0.0:
        chi = 1.0 / a
        poisson_part = torch.poisson(chi * rgb) / chi
    else:
        poisson_part = rgb

    if b > 0.0:
        gaussian_part = torch.empty_like(rgb).normal_(std=b)
    else:
        gaussian_part = torch.zeros_like(rgb)

    return (poisson_part + gaussian_part).clamp_(0.0, 1.0)