Files

64 lines
2.2 KiB
Python

import numpy as np
import cv2
try:
from numba import jit
HAS_NUMBA = True
except ImportError:
HAS_NUMBA = False
print("Warning: Numba not found. Dithering processing will be significantly slower.")
def fast_jit(func):
if HAS_NUMBA:
return jit(nopython=True)(func)
return func
@fast_jit
def apply_atkinson_core(img_float, threshold):
h, w = img_float.shape
out = np.zeros((h, w), dtype=np.uint8)
for y in range(h):
for x in range(w):
old_val = img_float[y, x]
new_val = 255.0 if old_val >= threshold else 0.0
out[y, x] = int(new_val)
err = (old_val - new_val) / 8.0
if x + 1 < w: img_float[y, x + 1] += err
if x + 2 < w: img_float[y, x + 2] += err
if y + 1 < h and x - 1 >= 0: img_float[y + 1, x - 1] += err
if y + 1 < h: img_float[y + 1, x] += err
if y + 1 < h and x + 1 < w: img_float[y + 1, x + 1] += err
if y + 2 < h: img_float[y + 2, x] += err
return out
def apply_halftone(img, dot_size, threshold):
h, w = img.shape
y, x = np.ogrid[:h, :w]
cy = (y // dot_size) * dot_size + dot_size // 2
cx = (x // dot_size) * dot_size + dot_size // 2
dist_sq = (y - cy)**2 + (x - cx)**2
max_dist_sq = (dot_size / 2.0)**2
threshold_map = dist_sq / max_dist_sq
darkness = 1.0 - (img / 255.0)
sensitivity = 1.0 + (threshold / 128.0)
darkness = np.clip(darkness * sensitivity, 0, 1)
out = np.ones((h, w), dtype=np.uint8) * 255
out[darkness > threshold_map] = 0
return out
def apply_adjustments(img, brightness, contrast, gamma, grain):
img = img * (brightness / 100.0)
factor = (259 * (contrast + 255)) / (255 * (259 - contrast))
img = factor * (img - 128) + 128
if gamma != 1.0 and gamma > 0:
img = np.power(np.maximum(img, 0) / 255.0, 1.0 / gamma) * 255.0
if grain > 0:
noise = (np.random.rand(*img.shape) - 0.5) * grain * 2.55
img += noise
return np.clip(img, 0, 255)
def hex_to_rgb(hex_str):
hex_str = hex_str.lstrip('#')
if len(hex_str) == 3: hex_str = ''.join([c*2 for c in hex_str])
return tuple(int(hex_str[i:i+2], 16) for i in (0, 2, 4))