import numpy as np
import cv2
from skimage.measure import block_reduce
from linefiller.trappedball_fill import *
from linefiller.thinning import *
from linefiller.third_party import *


def from_png_to_jpg(map):
    if map.shape[2] ==3:
        return map
    color = map[:, :, 0:3].astype(np.float) / 255.0
    alpha = map[:, :, 3:4].astype(np.float) / 255.0
    reversed_color = 1 - color
    final_color = (255.0 - reversed_color * alpha * 255.0).clip(0,255).astype(np.uint8)
    return final_color


def mk_resize(x, k):
    if x.shape[0] < x.shape[1]:
        s0 = k
        s1 = int(x.shape[1] * (k / x.shape[0]))
        s1 = s1 - s1 % 128
        _s0 = 32 * s0
        _s1 = int(x.shape[1] * (_s0 / x.shape[0]))
        _s1 = (_s1 + 64) - (_s1 + 64) % 128
    else:
        s1 = k
        s0 = int(x.shape[0] * (k / x.shape[1]))
        s0 = s0 - s0 % 128
        _s1 = 32 * s1
        _s0 = int(x.shape[0] * (_s1 / x.shape[1]))
        _s0 = (_s0 + 64) - (_s0 + 64) % 128
    new_min = min(_s1, _s0)
    raw_min = min(x.shape[0], x.shape[1])
    if new_min < raw_min:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (_s1, _s0), interpolation=interpolation)
    return y


def k_resize(x, k):
    if x.shape[0] < x.shape[1]:
        s0 = k
        s1 = int(x.shape[1] * (k / x.shape[0]))
        s1 = s1 - s1 % 64
        _s0 = 16 * s0
        _s1 = int(x.shape[1] * (_s0 / x.shape[0]))
        _s1 = (_s1 + 32) - (_s1 + 32) % 64
    else:
        s1 = k
        s0 = int(x.shape[0] * (k / x.shape[1]))
        s0 = s0 - s0 % 64
        _s1 = 16 * s1
        _s0 = int(x.shape[0] * (_s1 / x.shape[1]))
        _s0 = (_s0 + 32) - (_s0 + 32) % 64
    new_min = min(_s1, _s0)
    raw_min = min(x.shape[0], x.shape[1])
    if new_min < raw_min:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (_s1, _s0), interpolation=interpolation)
    return y


def sk_resize(x, k):
    if x.shape[0] < x.shape[1]:
        s0 = k
        s1 = int(x.shape[1] * (k / x.shape[0]))
        s1 = s1 - s1 % 16
        _s0 = 4 * s0
        _s1 = int(x.shape[1] * (_s0 / x.shape[0]))
        _s1 = (_s1 + 8) - (_s1 + 8) % 16
    else:
        s1 = k
        s0 = int(x.shape[0] * (k / x.shape[1]))
        s0 = s0 - s0 % 16
        _s1 = 4 * s1
        _s0 = int(x.shape[0] * (_s1 / x.shape[1]))
        _s0 = (_s0 + 8) - (_s0 + 8) % 16
    new_min = min(_s1, _s0)
    raw_min = min(x.shape[0], x.shape[1])
    if new_min < raw_min:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (_s1, _s0), interpolation=interpolation)
    return y


def d_resize(x, d, fac=1.0):
    new_min = min(int(d[1] * fac), int(d[0] * fac))
    raw_min = min(x.shape[0], x.shape[1])
    if new_min < raw_min:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (int(d[1] * fac), int(d[0] * fac)), interpolation=interpolation)
    return y


def n_resize(x, d):
    y = cv2.resize(x, (d[1], d[0]), interpolation=cv2.INTER_NEAREST)
    return y


def s_resize(x, s):
    if x.shape[0] < x.shape[1]:
        s0 = x.shape[0]
        s1 = int(float(s0) / float(s[0]) * float(s[1]))
    else:
        s1 = x.shape[1]
        s0 = int(float(s1) / float(s[1]) * float(s[0]))
    new_max = max(s1, s0)
    raw_max = max(x.shape[0], x.shape[1])
    if new_max < raw_max:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (s1, s0), interpolation=interpolation)
    return y


def min_resize(x, m):
    if x.shape[0] < x.shape[1]:
        s0 = m
        s1 = int(float(m) / float(x.shape[0]) * float(x.shape[1]))
    else:
        s0 = int(float(m) / float(x.shape[1]) * float(x.shape[0]))
        s1 = m
    new_max = min(s1, s0)
    raw_max = min(x.shape[0], x.shape[1])
    if new_max < raw_max:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (s1, s0), interpolation=interpolation)
    return y


def max_resize(x, m):
    if x.shape[0] > x.shape[1]:
        s0 = m
        s1 = int(float(m) / float(x.shape[0]) * float(x.shape[1]))
    else:
        s0 = int(float(m) / float(x.shape[1]) * float(x.shape[0]))
        s1 = m
    new_max = max(s1, s0)
    raw_max = max(x.shape[0], x.shape[1])
    if new_max < raw_max:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (s1, s0), interpolation=interpolation)
    return y


def s_enhance(x, k=2.0):
    p = cv2.cvtColor(x, cv2.COLOR_RGB2HSV).astype(np.float)
    p[:, :, 1] *= k
    p = p.clip(0, 255).astype(np.uint8)
    return cv2.cvtColor(p, cv2.COLOR_HSV2RGB).clip(0, 255)


def sss_enhance(x, k=2.0):
    p = cv2.cvtColor(x, cv2.COLOR_RGB2HSV).astype(np.float)
    p[:, :, 1] *= k
    p[:, :, 2] = 255
    p = p.clip(0, 255).astype(np.uint8)
    return cv2.cvtColor(p, cv2.COLOR_HSV2RGB).clip(0, 255)


def ini_hint(x):
    r = np.zeros(shape=(x.shape[0], x.shape[1], 4), dtype=np.uint8)
    return r


def opreate_gird_hint(gird, points, type, length):
    h = gird.shape[0]
    w = gird.shape[1]
    for point in points:
        x, y, r, g, b, t = point
        if t == type:
            x = int(x * w)
            y = int(y * h)
            l_ = max(0, x - length)
            b_ = max(0, y - length)
            r_ = min(w, x + length + 1)
            t_ = min(h, y + length + 1)
            gird[b_:t_, l_:r_, 2] = 1 - r / 255.0
            gird[b_:t_, l_:r_, 1] = 1 - g / 255.0
            gird[b_:t_, l_:r_, 0] = 1 - b / 255.0
            gird[b_:t_, l_:r_, 3] = 1
    return gird


def opreate_normal_hint(gird, points, length, skip_sp):
    h = gird.shape[0]
    w = gird.shape[1]
    for point in points:
        x, y, r, g, b = point
        x = int(x * w)
        y = int(y * h)
        l_ = max(0, x - length)
        b_ = max(0, y - length)
        r_ = min(w, x + length + 1)
        t_ = min(h, y + length + 1)
        if skip_sp:
            if r == 1 and g == 233 and b == 0:
                continue
            elif r == 0 and g == 233 and b == 1:
                continue
            else:
                gird[b_:t_, l_:r_, 2] = r
                gird[b_:t_, l_:r_, 1] = g
                gird[b_:t_, l_:r_, 0] = b
                gird[b_:t_, l_:r_, 3] = 255.0
        else:
            if r == 1 and g == 233 and b == 0:
                gird[b_:t_, l_:r_, 2] = r
                gird[b_:t_, l_:r_, 1] = g
                gird[b_:t_, l_:r_, 0] = b
                gird[b_:t_, l_:r_, 3] = 255.0
            elif r == 0 and g == 233 and b == 1:
                gird[b_:t_, l_:r_, 2] = r
                gird[b_:t_, l_:r_, 1] = g
                gird[b_:t_, l_:r_, 0] = b
                gird[b_:t_, l_:r_, 3] = 255.0
            else:
                continue
    return gird


def opreate_non_paramic_hints(gird, points, type):
    points_r = []
    colors_r = []
    h = gird.shape[0]
    w = gird.shape[1]
    for point in points:
        x, y, r, g, b, t = point
        if t in type:
            x = int(x * w)
            y = int(y * h)
            points_r.append([y, x])
            colors_r.append([b, g, r])
    return points_r, colors_r


def go_cvline(img):
    x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
    y = cv2.Sobel(img, cv2.CV_16S, 0, 1)
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    r = 255 - cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    return np.tile(np.min(r, axis=2, keepdims=True).clip(0, 255).astype(np.uint8), [1, 1, 3])


def go_passline(img):
    o = img.astype(np.float32)
    b = cv2.GaussianBlur(img, (7, 7), 0).astype(np.float32)
    r = np.max(b - o, axis=2, keepdims=True)
    r /= np.max(cv2.resize(r.clip(0, 255).astype(np.uint8), (64, 64), cv2.INTER_AREA))
    r = (1 - r).clip(0, 1)
    return np.tile((r * 255.0).clip(0, 255).astype(np.uint8), [1, 1, 3])


def min_k_down(x, k):
    y = 255 - x.astype(np.float32)
    y = block_reduce(y, (k, k), np.max)
    y = 255 - y
    return y.clip(0, 255).astype(np.uint8)


def min_k_down_c(x, k):
    y = 255 - x.astype(np.float32)
    y = block_reduce(y, (k, k, 1), np.max)
    y = 255 - y
    return y.clip(0, 255).astype(np.uint8)


def mini_norm(x):
    y = x.astype(np.float32)
    y = 1 - y / 255.0
    y -= np.min(y)
    y /= np.max(y)
    return (255.0 - y * 80.0).astype(np.uint8)


def hard_norm(x):
    o = x.astype(np.float32)
    b = cv2.GaussianBlur(x, (3, 3), 0).astype(np.float32)
    y = (o - b + 255.0).clip(0, 255)
    y = 1 - y / 255.0
    y -= np.min(y)
    y /= np.max(y)
    y[y < np.mean(y)] = 0
    y[y > 0] = 1
    return (255.0 - y * 255.0).astype(np.uint8)


def sensitive(x, s=15.0):
    y = x.astype(np.float32)
    y -= s
    y /= 255.0 - s * 2.0
    y *= 255.0
    return y.clip(0, 255).astype(np.uint8)


def min_black(x):
    return np.tile(np.min(x, axis=2, keepdims=True), [1, 1, 3])


def eye_black(x):
    return cv2.cvtColor(cv2.cvtColor(x, cv2.COLOR_RGB2GRAY), cv2.COLOR_GRAY2RGB)


def cal_std(x):
    y = (cv2.resize(x, (128, 128), cv2.INTER_AREA)).astype(np.float32)
    return np.mean(np.var(y, axis=2))


def emph_line(x, y, c):
    a = x.astype(np.float32)
    b = y.astype(np.float32)[:, :, None] / 255.0
    c = np.tile(c[None, None, ::-1], [a.shape[0], a.shape[1], 1])
    return (a * b + c * (1 - b)).clip(0, 255).astype(np.uint8)


def de_line(x, y):
    a = x.astype(np.float32)
    b = y.astype(np.float32)[:, :, None] / 255.0
    c = np.tile(np.array([255, 255, 255])[None, None, ::-1], [a.shape[0], a.shape[1], 1])
    return (a * b + c * (1 - b)).clip(0, 255).astype(np.uint8)


def blur_line(x, y):
    o = x.astype(np.float32)
    b = cv2.GaussianBlur(x, (3, 3), 0).astype(np.float32)
    k = y.astype(np.float32)[:, :, None] / 255.0
    return (o * k + b * (1 - k)).clip(0, 255).astype(np.uint8)


def clip_15(x, s=15.0):
    return ((x - s) / (255.0 - s - s)).clip(0, 1) * 255.0


def cv_denoise(x):
    return cv2.fastNlMeansDenoisingColored(x, None, 3, 3, 7, 21)


def norm_sketch(x):
    tiny_image = cv2.resize(x, (256, 256), interpolation=cv2.INTER_AREA)
    min = np.min(tiny_image)
    max = np.max(tiny_image)
    y = x.astype(np.float)
    y -= min
    y /= max - min
    y *= 255.0
    return y.clip(0, 255).astype(np.uint8)


clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(16, 16))


def go_cal(x):
    r = clahe.apply(x[:, :, 0])
    g = clahe.apply(x[:, :, 1])
    b = clahe.apply(x[:, :, 2])
    img = np.stack([r, g, b], axis=2)
    return img


def shrink(x):
    a = cv2.resize(x, (x.shape[1] // 2, x.shape[0] // 2), cv2.INTER_AREA)
    b = a[:, ::-1]
    c = a[::-1, :]
    d = a[::-1, ::-1]
    e = np.concatenate([a, b], axis=1)
    f = np.concatenate([c, d], axis=1)
    g = np.concatenate([e, f], axis=0)
    return g


barriersss = np.zeros(shape=(1024, 1024), dtype=np.uint8)
for _x in range(1024):
    for _y in range(1024):
        if _x % 32 == 0 or _y % 32 == 0 or _x % 32 == 1 or _y % 32 == 1 or _x % 32 == 2 or _y % 32 == 2 or _x % 32 == 3 or _y % 32 == 3 or _x % 32 == 4 or _y % 32 == 4:
            barriersss[_x, _y] = 1


def check_filter(x):
    kbas = cv2.resize(barriersss, (x.shape[1], x.shape[0]), interpolation=cv2.INTER_NEAREST)
    result = np.zeros_like(x)
    result[kbas > 0] = x[kbas > 0]
    return result


def get_hue_direction(source, target):
    h1 = cv2.cvtColor(source, cv2.COLOR_RGB2HSV)[:, :, 0].astype(np.float32)
    h2 = cv2.cvtColor(target, cv2.COLOR_RGB2HSV)[:, :, 0].astype(np.float32)
    h3 = h2 + 256
    h4 = h2 - 256
    r1 = h2 - h1
    r2 = h3 - h1
    r3 = h4 - h1
    rs = r1.copy()
    rs[np.abs(r2) < np.abs(rs)] = r2[np.abs(r2) < np.abs(rs)]
    rs[np.abs(r3) < np.abs(rs)] = r3[np.abs(r3) < np.abs(rs)]
    rs[rs < 0] = 0
    rs[rs > 0] = 255
    return rs.clip(0, 255).astype(np.uint8)


def small_norm(x):
    x = cv2.resize(x, (256, 256), cv2.INTER_AREA)
    x = np_max_pool(x)
    x = np_max_pool(x)
    x = np_max_pool(x)
    x = cv2.GaussianBlur(x, (0, 0), 3.0)
    return x


def cli_norm(sketch):
    tiny_sketch = cv2.resize(sketch, (256, 256), interpolation=cv2.INTER_AREA).astype(np.float32)
    tiny_min = np.min(tiny_sketch)
    tiny_max = np.max(tiny_sketch)
    return ((sketch.astype(np.float32) - tiny_min) / (tiny_max - tiny_min) * 255.0).clip(0, 255).astype(np.uint8)


def image_colorfulness(image):
    R = image[:, :, 0].astype(np.float32)
    G = image[:, :, 1].astype(np.float32)
    B = image[:, :, 2].astype(np.float32)

    R -= np.mean(R)
    G -= np.mean(G)
    B -= np.mean(B)

    rg = np.absolute(R - G)

    yb = np.absolute(0.5 * (R + G) - B)

    (rbMean, rbStd) = (np.mean(rg), np.std(rg))
    (ybMean, ybStd) = (np.mean(yb), np.std(yb))

    stdRoot = np.sqrt((rbStd ** 2) + (ybStd ** 2))
    meanRoot = np.sqrt((rbMean ** 2) + (ybMean ** 2))

    return stdRoot + (0.3 * meanRoot)


def reason_blending(color, sketch):
    color = (color.astype(np.float32) / 255.0).clip(0, 1)
    sketch = (sketch.astype(np.float32) / 255.0).clip(0, 1)
    sketch_r = sketch.copy()
    sketch_r = sketch_r ** 5
    color_max = np.max(color, axis=2, keepdims=True)
    downs = color ** np.pi
    downs = (downs + 1e-10) / (np.max(downs, axis=2, keepdims=True) + 1e-10) * color_max
    bleeding = color * sketch_r + downs * (1 - sketch_r)
    result_YUV = cv2.cvtColor((bleeding * 255.0).clip(0, 255).astype(np.uint8), cv2.COLOR_RGB2YUV)
    sketch_YUV = cv2.cvtColor((sketch * 255.0).clip(0, 255).astype(np.uint8), cv2.COLOR_RGB2YUV)
    result_YUV[:, :, 0] = np.minimum(result_YUV[:, :, 0], sketch_YUV[:, :, 0])
    return cv2.cvtColor(result_YUV, cv2.COLOR_YUV2RGB)


def absmax(a, axis=None):
    amax = a.max(axis)
    amin = a.min(axis)
    return np.where(-amin > amax, amin, amax)



import numpy as np
import cv2
from skimage.measure import block_reduce
from linefiller.trappedball_fill import *
from linefiller.thinning import *
from linefiller.third_party import *


def from_png_to_jpg(map):
    if map.shape[2] ==3:
        return map
    color = map[:, :, 0:3].astype(np.float) / 255.0
    alpha = map[:, :, 3:4].astype(np.float) / 255.0
    reversed_color = 1 - color
    final_color = (255.0 - reversed_color * alpha * 255.0).clip(0,255).astype(np.uint8)
    return final_color


def mk_resize(x, k):
    if x.shape[0] < x.shape[1]:
        s0 = k
        s1 = int(x.shape[1] * (k / x.shape[0]))
        s1 = s1 - s1 % 128
        _s0 = 32 * s0
        _s1 = int(x.shape[1] * (_s0 / x.shape[0]))
        _s1 = (_s1 + 64) - (_s1 + 64) % 128
    else:
        s1 = k
        s0 = int(x.shape[0] * (k / x.shape[1]))
        s0 = s0 - s0 % 128
        _s1 = 32 * s1
        _s0 = int(x.shape[0] * (_s1 / x.shape[1]))
        _s0 = (_s0 + 64) - (_s0 + 64) % 128
    new_min = min(_s1, _s0)
    raw_min = min(x.shape[0], x.shape[1])
    if new_min < raw_min:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (_s1, _s0), interpolation=interpolation)
    return y


def k_resize(x, k):
    if x.shape[0] < x.shape[1]:
        s0 = k
        s1 = int(x.shape[1] * (k / x.shape[0]))
        s1 = s1 - s1 % 64
        _s0 = 16 * s0
        _s1 = int(x.shape[1] * (_s0 / x.shape[0]))
        _s1 = (_s1 + 32) - (_s1 + 32) % 64
    else:
        s1 = k
        s0 = int(x.shape[0] * (k / x.shape[1]))
        s0 = s0 - s0 % 64
        _s1 = 16 * s1
        _s0 = int(x.shape[0] * (_s1 / x.shape[1]))
        _s0 = (_s0 + 32) - (_s0 + 32) % 64
    new_min = min(_s1, _s0)
    raw_min = min(x.shape[0], x.shape[1])
    if new_min < raw_min:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (_s1, _s0), interpolation=interpolation)
    return y


def sk_resize(x, k):
    if x.shape[0] < x.shape[1]:
        s0 = k
        s1 = int(x.shape[1] * (k / x.shape[0]))
        s1 = s1 - s1 % 16
        _s0 = 4 * s0
        _s1 = int(x.shape[1] * (_s0 / x.shape[0]))
        _s1 = (_s1 + 8) - (_s1 + 8) % 16
    else:
        s1 = k
        s0 = int(x.shape[0] * (k / x.shape[1]))
        s0 = s0 - s0 % 16
        _s1 = 4 * s1
        _s0 = int(x.shape[0] * (_s1 / x.shape[1]))
        _s0 = (_s0 + 8) - (_s0 + 8) % 16
    new_min = min(_s1, _s0)
    raw_min = min(x.shape[0], x.shape[1])
    if new_min < raw_min:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (_s1, _s0), interpolation=interpolation)
    return y


def d_resize(x, d, fac=1.0):
    new_min = min(int(d[1] * fac), int(d[0] * fac))
    raw_min = min(x.shape[0], x.shape[1])
    if new_min < raw_min:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (int(d[1] * fac), int(d[0] * fac)), interpolation=interpolation)
    return y


def n_resize(x, d):
    y = cv2.resize(x, (d[1], d[0]), interpolation=cv2.INTER_NEAREST)
    return y


def s_resize(x, s):
    if x.shape[0] < x.shape[1]:
        s0 = x.shape[0]
        s1 = int(float(s0) / float(s[0]) * float(s[1]))
    else:
        s1 = x.shape[1]
        s0 = int(float(s1) / float(s[1]) * float(s[0]))
    new_max = max(s1, s0)
    raw_max = max(x.shape[0], x.shape[1])
    if new_max < raw_max:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (s1, s0), interpolation=interpolation)
    return y


def min_resize(x, m):
    if x.shape[0] < x.shape[1]:
        s0 = m
        s1 = int(float(m) / float(x.shape[0]) * float(x.shape[1]))
    else:
        s0 = int(float(m) / float(x.shape[1]) * float(x.shape[0]))
        s1 = m
    new_max = min(s1, s0)
    raw_max = min(x.shape[0], x.shape[1])
    if new_max < raw_max:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (s1, s0), interpolation=interpolation)
    return y


def max_resize(x, m):
    if x.shape[0] > x.shape[1]:
        s0 = m
        s1 = int(float(m) / float(x.shape[0]) * float(x.shape[1]))
    else:
        s0 = int(float(m) / float(x.shape[1]) * float(x.shape[0]))
        s1 = m
    new_max = max(s1, s0)
    raw_max = max(x.shape[0], x.shape[1])
    if new_max < raw_max:
        interpolation = cv2.INTER_AREA
    else:
        interpolation = cv2.INTER_LANCZOS4
    y = cv2.resize(x, (s1, s0), interpolation=interpolation)
    return y


def s_enhance(x, k=2.0):
    p = cv2.cvtColor(x, cv2.COLOR_RGB2HSV).astype(np.float)
    p[:, :, 1] *= k
    p = p.clip(0, 255).astype(np.uint8)
    return cv2.cvtColor(p, cv2.COLOR_HSV2RGB).clip(0, 255)


def sss_enhance(x, k=2.0):
    p = cv2.cvtColor(x, cv2.COLOR_RGB2HSV).astype(np.float)
    p[:, :, 1] *= k
    p[:, :, 2] = 255
    p = p.clip(0, 255).astype(np.uint8)
    return cv2.cvtColor(p, cv2.COLOR_HSV2RGB).clip(0, 255)


def ini_hint(x):
    r = np.zeros(shape=(x.shape[0], x.shape[1], 4), dtype=np.uint8)
    return r


def opreate_gird_hint(gird, points, type, length):
    h = gird.shape[0]
    w = gird.shape[1]
    for point in points:
        x, y, r, g, b, t = point
        if t == type:
            x = int(x * w)
            y = int(y * h)
            l_ = max(0, x - length)
            b_ = max(0, y - length)
            r_ = min(w, x + length + 1)
            t_ = min(h, y + length + 1)
            gird[b_:t_, l_:r_, 2] = 1 - r / 255.0
            gird[b_:t_, l_:r_, 1] = 1 - g / 255.0
            gird[b_:t_, l_:r_, 0] = 1 - b / 255.0
            gird[b_:t_, l_:r_, 3] = 1
    return gird


def opreate_normal_hint(gird, points, length, skip_sp):
    h = gird.shape[0]
    w = gird.shape[1]
    for point in points:
        x, y, r, g, b = point
        x = int(x * w)
        y = int(y * h)
        l_ = max(0, x - length)
        b_ = max(0, y - length)
        r_ = min(w, x + length + 1)
        t_ = min(h, y + length + 1)
        if skip_sp:
            if r == 1 and g == 233 and b == 0:
                continue
            elif r == 0 and g == 233 and b == 1:
                continue
            else:
                gird[b_:t_, l_:r_, 2] = r
                gird[b_:t_, l_:r_, 1] = g
                gird[b_:t_, l_:r_, 0] = b
                gird[b_:t_, l_:r_, 3] = 255.0
        else:
            if r == 1 and g == 233 and b == 0:
                gird[b_:t_, l_:r_, 2] = r
                gird[b_:t_, l_:r_, 1] = g
                gird[b_:t_, l_:r_, 0] = b
                gird[b_:t_, l_:r_, 3] = 255.0
            elif r == 0 and g == 233 and b == 1:
                gird[b_:t_, l_:r_, 2] = r
                gird[b_:t_, l_:r_, 1] = g
                gird[b_:t_, l_:r_, 0] = b
                gird[b_:t_, l_:r_, 3] = 255.0
            else:
                continue
    return gird


def opreate_non_paramic_hints(gird, points, type):
    points_r = []
    colors_r = []
    h = gird.shape[0]
    w = gird.shape[1]
    for point in points:
        x, y, r, g, b, t = point
        if t in type:
            x = int(x * w)
            y = int(y * h)
            points_r.append([y, x])
            colors_r.append([b, g, r])
    return points_r, colors_r


def go_cvline(img):
    x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
    y = cv2.Sobel(img, cv2.CV_16S, 0, 1)
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    r = 255 - cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    return np.tile(np.min(r, axis=2, keepdims=True).clip(0, 255).astype(np.uint8), [1, 1, 3])


def go_passline(img):
    o = img.astype(np.float32)
    b = cv2.GaussianBlur(img, (7, 7), 0).astype(np.float32)
    r = np.max(b - o, axis=2, keepdims=True)
    r /= np.max(cv2.resize(r.clip(0, 255).astype(np.uint8), (64, 64), cv2.INTER_AREA))
    r = (1 - r).clip(0, 1)
    return np.tile((r * 255.0).clip(0, 255).astype(np.uint8), [1, 1, 3])


def min_k_down(x, k):
    y = 255 - x.astype(np.float32)
    y = block_reduce(y, (k, k), np.max)
    y = 255 - y
    return y.clip(0, 255).astype(np.uint8)


def min_k_down_c(x, k):
    y = 255 - x.astype(np.float32)
    y = block_reduce(y, (k, k, 1), np.max)
    y = 255 - y
    return y.clip(0, 255).astype(np.uint8)


def mini_norm(x):
    y = x.astype(np.float32)
    y = 1 - y / 255.0
    y -= np.min(y)
    y /= np.max(y)
    return (255.0 - y * 80.0).astype(np.uint8)


def hard_norm(x):
    o = x.astype(np.float32)
    b = cv2.GaussianBlur(x, (3, 3), 0).astype(np.float32)
    y = (o - b + 255.0).clip(0, 255)
    y = 1 - y / 255.0
    y -= np.min(y)
    y /= np.max(y)
    y[y < np.mean(y)] = 0
    y[y > 0] = 1
    return (255.0 - y * 255.0).astype(np.uint8)


def sensitive(x, s=15.0):
    y = x.astype(np.float32)
    y -= s
    y /= 255.0 - s * 2.0
    y *= 255.0
    return y.clip(0, 255).astype(np.uint8)


def min_black(x):
    return np.tile(np.min(x, axis=2, keepdims=True), [1, 1, 3])


def eye_black(x):
    return cv2.cvtColor(cv2.cvtColor(x, cv2.COLOR_RGB2GRAY), cv2.COLOR_GRAY2RGB)


def cal_std(x):
    y = (cv2.resize(x, (128, 128), cv2.INTER_AREA)).astype(np.float32)
    return np.mean(np.var(y, axis=2))


def emph_line(x, y, c):
    a = x.astype(np.float32)
    b = y.astype(np.float32)[:, :, None] / 255.0
    c = np.tile(c[None, None, ::-1], [a.shape[0], a.shape[1], 1])
    return (a * b + c * (1 - b)).clip(0, 255).astype(np.uint8)


def de_line(x, y):
    a = x.astype(np.float32)
    b = y.astype(np.float32)[:, :, None] / 255.0
    c = np.tile(np.array([255, 255, 255])[None, None, ::-1], [a.shape[0], a.shape[1], 1])
    return (a * b + c * (1 - b)).clip(0, 255).astype(np.uint8)


def blur_line(x, y):
    o = x.astype(np.float32)
    b = cv2.GaussianBlur(x, (3, 3), 0).astype(np.float32)
    k = y.astype(np.float32)[:, :, None] / 255.0
    return (o * k + b * (1 - k)).clip(0, 255).astype(np.uint8)


def clip_15(x, s=15.0):
    return ((x - s) / (255.0 - s - s)).clip(0, 1) * 255.0


def cv_denoise(x):
    return cv2.fastNlMeansDenoisingColored(x, None, 3, 3, 7, 21)


def norm_sketch(x):
    tiny_image = cv2.resize(x, (256, 256), interpolation=cv2.INTER_AREA)
    min = np.min(tiny_image)
    max = np.max(tiny_image)
    y = x.astype(np.float)
    y -= min
    y /= max - min
    y *= 255.0
    return y.clip(0, 255).astype(np.uint8)


clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(16, 16))


def go_cal(x):
    r = clahe.apply(x[:, :, 0])
    g = clahe.apply(x[:, :, 1])
    b = clahe.apply(x[:, :, 2])
    img = np.stack([r, g, b], axis=2)
    return img


def shrink(x):
    a = cv2.resize(x, (x.shape[1] // 2, x.shape[0] // 2), cv2.INTER_AREA)
    b = a[:, ::-1]
    c = a[::-1, :]
    d = a[::-1, ::-1]
    e = np.concatenate([a, b], axis=1)
    f = np.concatenate([c, d], axis=1)
    g = np.concatenate([e, f], axis=0)
    return g


barriersss = np.zeros(shape=(1024, 1024), dtype=np.uint8)
for _x in range(1024):
    for _y in range(1024):
        if _x % 32 == 0 or _y % 32 == 0 or _x % 32 == 1 or _y % 32 == 1 or _x % 32 == 2 or _y % 32 == 2 or _x % 32 == 3 or _y % 32 == 3 or _x % 32 == 4 or _y % 32 == 4:
            barriersss[_x, _y] = 1


def check_filter(x):
    kbas = cv2.resize(barriersss, (x.shape[1], x.shape[0]), interpolation=cv2.INTER_NEAREST)
    result = np.zeros_like(x)
    result[kbas > 0] = x[kbas > 0]
    return result


def get_hue_direction(source, target):
    h1 = cv2.cvtColor(source, cv2.COLOR_RGB2HSV)[:, :, 0].astype(np.float32)
    h2 = cv2.cvtColor(target, cv2.COLOR_RGB2HSV)[:, :, 0].astype(np.float32)
    h3 = h2 + 256
    h4 = h2 - 256
    r1 = h2 - h1
    r2 = h3 - h1
    r3 = h4 - h1
    rs = r1.copy()
    rs[np.abs(r2) < np.abs(rs)] = r2[np.abs(r2) < np.abs(rs)]
    rs[np.abs(r3) < np.abs(rs)] = r3[np.abs(r3) < np.abs(rs)]
    rs[rs < 0] = 0
    rs[rs > 0] = 255
    return rs.clip(0, 255).astype(np.uint8)


def small_norm(x):
    x = cv2.resize(x, (256, 256), cv2.INTER_AREA)
    x = np_max_pool(x)
    x = np_max_pool(x)
    x = np_max_pool(x)
    x = cv2.GaussianBlur(x, (0, 0), 3.0)
    return x


def cli_norm(sketch):
    tiny_sketch = cv2.resize(sketch, (256, 256), interpolation=cv2.INTER_AREA).astype(np.float32)
    tiny_min = np.min(tiny_sketch)
    tiny_max = np.max(tiny_sketch)
    return ((sketch.astype(np.float32) - tiny_min) / (tiny_max - tiny_min) * 255.0).clip(0, 255).astype(np.uint8)


def image_colorfulness(image):
    R = image[:, :, 0].astype(np.float32)
    G = image[:, :, 1].astype(np.float32)
    B = image[:, :, 2].astype(np.float32)

    R -= np.mean(R)
    G -= np.mean(G)
    B -= np.mean(B)

    rg = np.absolute(R - G)

    yb = np.absolute(0.5 * (R + G) - B)

    (rbMean, rbStd) = (np.mean(rg), np.std(rg))
    (ybMean, ybStd) = (np.mean(yb), np.std(yb))

    stdRoot = np.sqrt((rbStd ** 2) + (ybStd ** 2))
    meanRoot = np.sqrt((rbMean ** 2) + (ybMean ** 2))

    return stdRoot + (0.3 * meanRoot)


def reason_blending(color, sketch):
    color = (color.astype(np.float32) / 255.0).clip(0, 1)
    sketch = (sketch.astype(np.float32) / 255.0).clip(0, 1)
    sketch_r = sketch.copy()
    sketch_r = sketch_r ** 5
    color_max = np.max(color, axis=2, keepdims=True)
    downs = color ** np.pi
    downs = (downs + 1e-10) / (np.max(downs, axis=2, keepdims=True) + 1e-10) * color_max
    bleeding = color * sketch_r + downs * (1 - sketch_r)
    result_YUV = cv2.cvtColor((bleeding * 255.0).clip(0, 255).astype(np.uint8), cv2.COLOR_RGB2YUV)
    sketch_YUV = cv2.cvtColor((sketch * 255.0).clip(0, 255).astype(np.uint8), cv2.COLOR_RGB2YUV)
    result_YUV[:, :, 0] = np.minimum(result_YUV[:, :, 0], sketch_YUV[:, :, 0])
    return cv2.cvtColor(result_YUV, cv2.COLOR_YUV2RGB)


def absmax(a, axis=None):
    amax = a.max(axis)
    amin = a.min(axis)
    return np.where(-amin > amax, amin, amax)


