File size: 1,841 Bytes
c19ca42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import cv2
import numpy as np

from ..utils.utils import get_h_w_c
from .image_utils import as_2d_grayscale


def _luminance(img: np.ndarray) -> np.ndarray:
    """Returns the luminance of an image."""
    _, _, c = get_h_w_c(img)
    if c == 1:
        return as_2d_grayscale(img)
    if c == 2:
        return img[..., 0]
    return np.dot(img[..., :3], [0.2126, 0.7152, 0.0722])


def create_cas_mask(img: np.ndarray, kernel, bias: float = 2) -> np.ndarray:
    """
    Uses contrast adaptive sharpening's method to create a mask to interpolate between the original
    and sharpened image.

    `kernel` is an element create by `cv2.getStructuringElement`. It determines the shape and size
    of each pixel's neighborhood.

    `bias` is used to bias the mask towards the more sharpening. A value of 1 means no bias, a
    value greater than 1 biases the mask towards the sharpened image, a value less than 1 biases
    the mask towards the original image.

    Reference:
    Lou Kramer, FidelityFX CAS, AMD Developer Day 2019, https://gpuopen.com/wp-content/uploads/2019/07/FidelityFX-CAS.pptx
    https://www.shadertoy.com/view/wtlSWB#
    """
    assert bias > 0, "Bias must be greater than or equal to 0."

    l = _luminance(img)
    min_l = cv2.erode(l, kernel)
    max_l = cv2.dilate(l, kernel)
    min_d = np.minimum(1.0 - max_l, min_l, out=min_l)  # type: ignore
    max_l += 1e-8  # type: ignore
    min_d /= max_l
    mask = min_d
    if bias != 1:
        mask = np.power(mask, 1 / bias, out=mask)
    return mask


def cas_mix(
    img: np.ndarray,
    sharpened: np.ndarray,
    kernel,
    bias: float = 2,
) -> np.ndarray:
    mask = create_cas_mask(img, kernel, bias)
    _, _, c = get_h_w_c(sharpened)
    if c > 1:
        mask = np.dstack((mask,) * c)
    return img * (1 - mask) + sharpened * mask  # type: ignore