forked from mttu-developers/konabot
最新最热模糊
This commit is contained in:
@ -19,8 +19,6 @@ fx [滤镜名称] <参数1> <参数2> ...
|
||||
## 可用滤镜列表
|
||||
|
||||
### 基础滤镜
|
||||
* ```fx 模糊 <半径=10>```
|
||||
* ```fx 马赛克 <像素大小=10>```
|
||||
* ```fx 轮廓```
|
||||
* ```fx 锐化```
|
||||
* ```fx 边缘增强```
|
||||
@ -33,6 +31,15 @@ fx [滤镜名称] <参数1> <参数2> ...
|
||||
* ```fx 素描```
|
||||
* ```fx 阴影 <x偏移量=10> <y偏移量=10> <模糊量=10> <不透明度=0.5> <阴影颜色=black>```
|
||||
|
||||
### 模糊滤镜
|
||||
* ```fx 模糊 <半径=10>```
|
||||
* ```fx 马赛克 <像素大小=10>```
|
||||
* ```fx 径向模糊 <强度=3.0> <采样量=6>```
|
||||
* ```fx 旋转模糊 <强度=30.0> <采样量=6>```
|
||||
* ```fx 方向模糊 <角度=0.0> <距离=20> <采样量=6>```
|
||||
* ```fx 缩放模糊 <强度=0.1> <采样量=6>```
|
||||
* ```fx 边缘模糊 <半径=10.0>```
|
||||
|
||||
### 色彩处理滤镜
|
||||
* ```fx 反色```
|
||||
* ```fx 黑白```
|
||||
|
||||
@ -566,4 +566,325 @@ class ImageFilterImplement:
|
||||
result.paste(image, image_position, image)
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def apply_radial_blur(image: Image.Image, strength: float = 3.0, samples: int = 6) -> Image.Image:
|
||||
"""
|
||||
快速径向模糊 - 使用预计算网格和向量化
|
||||
"""
|
||||
if image.mode != 'RGBA':
|
||||
image = image.convert('RGBA')
|
||||
|
||||
width, height = image.size
|
||||
arr = np.array(image, dtype=np.uint8)
|
||||
|
||||
# 转换为float32并归一化
|
||||
arr_float = arr.astype(np.float32) / 255.0
|
||||
|
||||
# 计算中心点
|
||||
center_x = width / 2
|
||||
center_y = height / 2
|
||||
|
||||
# 预计算坐标网格(只计算一次)
|
||||
x_indices = np.arange(width, dtype=np.float32)
|
||||
y_indices = np.arange(height, dtype=np.float32)
|
||||
x_grid, y_grid = np.meshgrid(x_indices, y_indices)
|
||||
|
||||
# 预计算相对坐标和距离
|
||||
dx = x_grid - center_x
|
||||
dy = y_grid - center_y
|
||||
distance = np.sqrt(dx*dx + dy*dy + 1e-6) # 避免除零
|
||||
max_dist = np.max(distance)
|
||||
|
||||
# 生成采样强度
|
||||
if samples > 1:
|
||||
strengths = np.linspace(-strength/2, strength/2, samples) / 100
|
||||
else:
|
||||
strengths = np.array([0])
|
||||
|
||||
# 初始化结果
|
||||
result = np.zeros_like(arr_float)
|
||||
|
||||
for s in strengths:
|
||||
# 计算缩放因子
|
||||
scale = 1.0 + s * distance / max_dist
|
||||
|
||||
# 计算变形坐标
|
||||
new_x = np.clip(center_x + dx * scale, 0, width - 1)
|
||||
new_y = np.clip(center_y + dy * scale, 0, height - 1)
|
||||
|
||||
# 快速双线性插值
|
||||
x0 = np.floor(new_x).astype(np.int32)
|
||||
x1 = np.minimum(x0 + 1, width - 1)
|
||||
y0 = np.floor(new_y).astype(np.int32)
|
||||
y1 = np.minimum(y0 + 1, height - 1)
|
||||
|
||||
# 计算权重
|
||||
wx = new_x - x0
|
||||
wy = new_y - y0
|
||||
w00 = (1 - wx) * (1 - wy)
|
||||
w01 = wx * (1 - wy)
|
||||
w10 = (1 - wx) * wy
|
||||
w11 = wx * wy
|
||||
|
||||
# 向量化插值所有通道
|
||||
for c in range(4):
|
||||
result[:, :, c] += (
|
||||
arr_float[y0, x0, c] * w00 +
|
||||
arr_float[y0, x1, c] * w01 +
|
||||
arr_float[y1, x0, c] * w10 +
|
||||
arr_float[y1, x1, c] * w11
|
||||
)
|
||||
|
||||
# 平均并转换
|
||||
result /= len(strengths)
|
||||
result = np.clip(result * 255, 0, 255).astype(np.uint8)
|
||||
|
||||
return Image.fromarray(result, 'RGBA')
|
||||
|
||||
@staticmethod
|
||||
def apply_spin_blur(image: Image.Image, strength: float = 30.0, samples: int = 6) -> Image.Image:
|
||||
"""
|
||||
快速旋转模糊
|
||||
"""
|
||||
if image.mode != 'RGBA':
|
||||
image = image.convert('RGBA')
|
||||
|
||||
width, height = image.size
|
||||
arr = np.array(image, dtype=np.uint8)
|
||||
arr_float = arr.astype(np.float32) / 255.0
|
||||
|
||||
# 计算中心点
|
||||
center_x = width / 2
|
||||
center_y = height / 2
|
||||
|
||||
# 预计算坐标网格
|
||||
x_indices = np.arange(width, dtype=np.float32)
|
||||
y_indices = np.arange(height, dtype=np.float32)
|
||||
x_grid, y_grid = np.meshgrid(x_indices, y_indices)
|
||||
|
||||
# 预计算相对坐标
|
||||
dx = x_grid - center_x
|
||||
dy = y_grid - center_y
|
||||
|
||||
# 生成角度采样
|
||||
if samples > 1:
|
||||
angles = np.linspace(-strength/2, strength/2, samples) * np.pi / 180
|
||||
else:
|
||||
angles = np.array([0])
|
||||
|
||||
result = np.zeros_like(arr_float)
|
||||
|
||||
for angle in angles:
|
||||
# 预计算三角函数值
|
||||
cos_a = math.cos(angle)
|
||||
sin_a = math.sin(angle)
|
||||
|
||||
# 计算旋转坐标
|
||||
new_x = center_x + dx * cos_a - dy * sin_a
|
||||
new_y = center_y + dx * sin_a + dy * cos_a
|
||||
|
||||
# 边界裁剪
|
||||
new_x = np.clip(new_x, 0, width - 1)
|
||||
new_y = np.clip(new_y, 0, height - 1)
|
||||
|
||||
# 快速双线性插值
|
||||
x0 = np.floor(new_x).astype(np.int32)
|
||||
x1 = np.minimum(x0 + 1, width - 1)
|
||||
y0 = np.floor(new_y).astype(np.int32)
|
||||
y1 = np.minimum(y0 + 1, height - 1)
|
||||
|
||||
wx = new_x - x0
|
||||
wy = new_y - y0
|
||||
w00 = (1 - wx) * (1 - wy)
|
||||
w01 = wx * (1 - wy)
|
||||
w10 = (1 - wx) * wy
|
||||
w11 = wx * wy
|
||||
|
||||
# 向量化插值
|
||||
for c in range(4):
|
||||
result[:, :, c] += (
|
||||
arr_float[y0, x0, c] * w00 +
|
||||
arr_float[y0, x1, c] * w01 +
|
||||
arr_float[y1, x0, c] * w10 +
|
||||
arr_float[y1, x1, c] * w11
|
||||
)
|
||||
|
||||
result /= len(angles)
|
||||
result = np.clip(result * 255, 0, 255).astype(np.uint8)
|
||||
|
||||
return Image.fromarray(result, 'RGBA')
|
||||
|
||||
@staticmethod
|
||||
def apply_directional_blur(image: Image.Image, angle: float = 0.0,
|
||||
distance: int = 20, samples: int = 6) -> Image.Image:
|
||||
"""
|
||||
快速方向模糊 - 使用累积缓冲区技术
|
||||
"""
|
||||
if image.mode != 'RGBA':
|
||||
image = image.convert('RGBA')
|
||||
|
||||
width, height = image.size
|
||||
arr = np.array(image, dtype=np.uint8)
|
||||
arr_float = arr.astype(np.float32) / 255.0
|
||||
|
||||
# 计算角度和步长
|
||||
rad = math.radians(angle)
|
||||
cos_a = math.cos(rad)
|
||||
sin_a = math.sin(rad)
|
||||
|
||||
# 生成偏移位置
|
||||
if samples > 1:
|
||||
offsets = np.linspace(-distance/2, distance/2, samples)
|
||||
else:
|
||||
offsets = np.array([0])
|
||||
|
||||
result = np.zeros_like(arr_float)
|
||||
|
||||
for offset in offsets:
|
||||
# 计算偏移量
|
||||
shift_x = offset * cos_a
|
||||
shift_y = offset * sin_a
|
||||
|
||||
# 预计算变形坐标
|
||||
x_indices = np.arange(width, dtype=np.float32)
|
||||
y_indices = np.arange(height, dtype=np.float32)
|
||||
x_grid, y_grid = np.meshgrid(x_indices, y_indices)
|
||||
|
||||
new_x = x_grid - shift_x
|
||||
new_y = y_grid - shift_y
|
||||
|
||||
# 边界裁剪
|
||||
new_x = np.clip(new_x, 0, width - 1)
|
||||
new_y = np.clip(new_y, 0, height - 1)
|
||||
|
||||
# 快速双线性插值
|
||||
x0 = np.floor(new_x).astype(np.int32)
|
||||
x1 = np.minimum(x0 + 1, width - 1)
|
||||
y0 = np.floor(new_y).astype(np.int32)
|
||||
y1 = np.minimum(y0 + 1, height - 1)
|
||||
|
||||
wx = new_x - x0
|
||||
wy = new_y - y0
|
||||
w00 = (1 - wx) * (1 - wy)
|
||||
w01 = wx * (1 - wy)
|
||||
w10 = (1 - wx) * wy
|
||||
w11 = wx * wy
|
||||
|
||||
# 向量化插值
|
||||
for c in range(4):
|
||||
result[:, :, c] += (
|
||||
arr_float[y0, x0, c] * w00 +
|
||||
arr_float[y0, x1, c] * w01 +
|
||||
arr_float[y1, x0, c] * w10 +
|
||||
arr_float[y1, x1, c] * w11
|
||||
)
|
||||
|
||||
result /= len(offsets)
|
||||
result = np.clip(result * 255, 0, 255).astype(np.uint8)
|
||||
|
||||
return Image.fromarray(result, 'RGBA')
|
||||
|
||||
@staticmethod
|
||||
def apply_zoom_blur(image: Image.Image, strength: float = 0.1, samples: int = 6) -> Image.Image:
|
||||
"""
|
||||
快速缩放模糊
|
||||
"""
|
||||
if image.mode != 'RGBA':
|
||||
image = image.convert('RGBA')
|
||||
|
||||
width, height = image.size
|
||||
arr = np.array(image, dtype=np.uint8)
|
||||
arr_float = arr.astype(np.float32) / 255.0
|
||||
|
||||
# 计算中心点
|
||||
center_x = width / 2
|
||||
center_y = height / 2
|
||||
|
||||
# 预计算坐标网格
|
||||
x_indices = np.arange(width, dtype=np.float32)
|
||||
y_indices = np.arange(height, dtype=np.float32)
|
||||
x_grid, y_grid = np.meshgrid(x_indices, y_indices)
|
||||
|
||||
# 预计算相对坐标
|
||||
dx = x_grid - center_x
|
||||
dy = y_grid - center_y
|
||||
|
||||
# 生成缩放因子
|
||||
if samples > 1:
|
||||
scales = np.linspace(1 - strength, 1 + strength, samples)
|
||||
else:
|
||||
scales = np.array([1.0])
|
||||
|
||||
result = np.zeros_like(arr_float)
|
||||
|
||||
for scale in scales:
|
||||
# 计算缩放坐标
|
||||
new_x = center_x + dx / scale
|
||||
new_y = center_y + dy / scale
|
||||
|
||||
# 边界裁剪
|
||||
new_x = np.clip(new_x, 0, width - 1)
|
||||
new_y = np.clip(new_y, 0, height - 1)
|
||||
|
||||
# 快速双线性插值
|
||||
x0 = np.floor(new_x).astype(np.int32)
|
||||
x1 = np.minimum(x0 + 1, width - 1)
|
||||
y0 = np.floor(new_y).astype(np.int32)
|
||||
y1 = np.minimum(y0 + 1, height - 1)
|
||||
|
||||
wx = new_x - x0
|
||||
wy = new_y - y0
|
||||
w00 = (1 - wx) * (1 - wy)
|
||||
w01 = wx * (1 - wy)
|
||||
w10 = (1 - wx) * wy
|
||||
w11 = wx * wy
|
||||
|
||||
# 向量化插值
|
||||
for c in range(4):
|
||||
result[:, :, c] += (
|
||||
arr_float[y0, x0, c] * w00 +
|
||||
arr_float[y0, x1, c] * w01 +
|
||||
arr_float[y1, x0, c] * w10 +
|
||||
arr_float[y1, x1, c] * w11
|
||||
)
|
||||
|
||||
result /= len(scales)
|
||||
result = np.clip(result * 255, 0, 255).astype(np.uint8)
|
||||
|
||||
return Image.fromarray(result, 'RGBA')
|
||||
|
||||
# 中心清晰,边缘模糊
|
||||
@staticmethod
|
||||
def apply_focus_blur(image: Image.Image, radius: float = 10.0) -> Image.Image:
|
||||
if image.mode != 'RGBA':
|
||||
image = image.convert('RGBA')
|
||||
|
||||
width, height = image.size
|
||||
arr = np.array(image)
|
||||
|
||||
# 创建坐标网格
|
||||
y_coords, x_coords = np.mgrid[0:height, 0:width]
|
||||
|
||||
# 计算中心点
|
||||
center_x = width / 2
|
||||
center_y = height / 2
|
||||
|
||||
# 计算归一化坐标
|
||||
norm_x = (x_coords - center_x) / (width / 2)
|
||||
norm_y = (y_coords - center_y) / (height / 2)
|
||||
distance = np.sqrt(norm_x**2 + norm_y**2)
|
||||
|
||||
# 创建模糊图像
|
||||
blurred_image = image.filter(ImageFilter.GaussianBlur(radius))
|
||||
blurred_arr = np.array(blurred_image)
|
||||
|
||||
# 创建结果图像(向量化)
|
||||
result = np.zeros_like(arr, dtype=np.float32)
|
||||
|
||||
# 根据距离混合原图和模糊图
|
||||
for c in range(4): # 对每个通道
|
||||
result[:, :, c] = arr[:, :, c] * (1 - distance) + blurred_arr[:, :, c] * distance
|
||||
|
||||
return Image.fromarray(np.clip(result, 0, 255).astype(np.uint8), 'RGBA')
|
||||
|
||||
|
||||
@ -35,6 +35,11 @@ class ImageFilterManager:
|
||||
"素描": ImageFilterImplement.apply_sketch,
|
||||
"叠加颜色": ImageFilterImplement.apply_gradient_overlay,
|
||||
"阴影": ImageFilterImplement.apply_shadow,
|
||||
"径向模糊": ImageFilterImplement.apply_radial_blur,
|
||||
"旋转模糊": ImageFilterImplement.apply_spin_blur,
|
||||
"方向模糊": ImageFilterImplement.apply_directional_blur,
|
||||
"边缘模糊": ImageFilterImplement.apply_focus_blur,
|
||||
"缩放模糊": ImageFilterImplement.apply_zoom_blur,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
|
||||
Reference in New Issue
Block a user