new fx
This commit is contained in:
@ -51,6 +51,8 @@ fx [滤镜名称] <参数1> <参数2> ...
|
||||
* ```fx RGB分离 <偏移量=5>```
|
||||
* ```fx 叠加颜色 <颜色列表=[rgb(255,0,0)|(0,0)+rgb(0,255,0)|(0,100)+rgb(0,0,255)|(50,100)]> <叠加模式=overlay>```
|
||||
* ```fx 像素抖动 <最大偏移量=2>```
|
||||
* ```fx 半调 <半径=5>```
|
||||
* ```fx 描边 <半径=5> <颜色=black>```
|
||||
|
||||
### 几何变换滤镜
|
||||
* ```fx 平移 <x偏移量=10> <y偏移量=10>```
|
||||
@ -1,5 +1,5 @@
|
||||
import random
|
||||
from PIL import Image, ImageFilter
|
||||
from PIL import Image, ImageFilter, ImageDraw, ImageStat
|
||||
from PIL import ImageEnhance
|
||||
from PIL import ImageChops
|
||||
from PIL import ImageOps
|
||||
@ -412,6 +412,13 @@ class ImageFilterImplement:
|
||||
if valid_mask.any():
|
||||
# 使用花式索引复制像素
|
||||
result[valid_mask] = arr[new_y[valid_mask], new_x[valid_mask]]
|
||||
|
||||
# 计算裁剪边界
|
||||
ys, xs = np.where(valid_mask)
|
||||
min_y, max_y = ys.min(), ys.max() + 1
|
||||
min_x, max_x = xs.min(), xs.max() + 1
|
||||
# 裁剪结果图像
|
||||
result = result[min_y:max_y, min_x:max_x]
|
||||
|
||||
return Image.fromarray(result, 'RGBA')
|
||||
|
||||
@ -1103,6 +1110,86 @@ class ImageFilterImplement:
|
||||
|
||||
return Image.fromarray(result, 'RGBA')
|
||||
|
||||
# 描边
|
||||
@staticmethod
|
||||
def apply_stroke(image: Image.Image, stroke_width: int = 5, stroke_color: str = 'black') -> Image.Image:
|
||||
if image.mode != 'RGBA':
|
||||
image = image.convert('RGBA')
|
||||
|
||||
# 基于图像的 alpha 通道创建描边
|
||||
alpha = image.split()[3]
|
||||
# 创建描边图像
|
||||
stroke_image = Image.new('RGBA', image.size, (0, 0, 0, 0))
|
||||
# 根据 alpha 通道的值,以每个像素为中心,扩大描边区域
|
||||
expanded_alpha = alpha.filter(ImageFilter.MaxFilter(size=stroke_width*2+1))
|
||||
draw = Image.new('RGBA', image.size, ColorHandle.parse_color(stroke_color) + (255,))
|
||||
stroke_image.paste(draw, (0, 0), expanded_alpha)
|
||||
# 将描边和原图合并
|
||||
result = Image.alpha_composite(stroke_image, image)
|
||||
return result
|
||||
|
||||
# 半调
|
||||
@staticmethod
|
||||
def apply_halftone(image: Image.Image, dot_size: int = 5) -> Image.Image:
|
||||
if image.mode != 'L':
|
||||
grayscale = image.convert('L')
|
||||
else:
|
||||
grayscale = image.copy()
|
||||
|
||||
# 获取图像尺寸
|
||||
width, height = grayscale.size
|
||||
|
||||
# 计算网格数量
|
||||
grid_width = math.ceil(width / dot_size)
|
||||
grid_height = math.ceil(height / dot_size)
|
||||
|
||||
# 创建输出图像(白色背景)
|
||||
output = Image.new('RGB', (width, height), 'white')
|
||||
draw = ImageDraw.Draw(output)
|
||||
|
||||
# 遍历每个网格单元
|
||||
for gy in range(grid_height):
|
||||
for gx in range(grid_width):
|
||||
# 计算当前网格的边界
|
||||
left = gx * dot_size
|
||||
top = gy * dot_size
|
||||
right = min(left + dot_size, width)
|
||||
bottom = min(top + dot_size, height)
|
||||
|
||||
# 获取当前网格的区域
|
||||
grid_region = grayscale.crop((left, top, right, bottom))
|
||||
|
||||
# 计算网格内像素的平均亮度(0-255)
|
||||
stat = ImageStat.Stat(grid_region)
|
||||
avg_brightness = stat.mean[0]
|
||||
|
||||
# 将亮度转换为网点半径
|
||||
# 亮度越高(越白),网点越小;亮度越低(越黑),网点越大
|
||||
max_radius = dot_size / 2
|
||||
radius = max_radius * (1 - avg_brightness / 255)
|
||||
|
||||
# 如果半径太小,则不绘制网点
|
||||
if radius > 0.5:
|
||||
# 计算网点中心坐标
|
||||
center_x = left + (right - left) / 2
|
||||
center_y = top + (bottom - top) / 2
|
||||
|
||||
# 绘制黑色网点
|
||||
draw.ellipse([
|
||||
center_x - radius + 0.5,
|
||||
center_y - radius + 0.5,
|
||||
center_x + radius + 0.5,
|
||||
center_y + radius + 0.5
|
||||
], fill='black')
|
||||
|
||||
# 叠加 alpha 通道
|
||||
if image.mode == 'RGBA':
|
||||
alpha = image.split()[3]
|
||||
output.putalpha(alpha)
|
||||
|
||||
return output
|
||||
|
||||
|
||||
class ImageFilterEmpty:
|
||||
# 空滤镜,不做任何处理,形式化参数用
|
||||
@staticmethod
|
||||
|
||||
@ -47,6 +47,8 @@ class ImageFilterManager:
|
||||
"晃动": ImageFilterImplement.apply_random_wiggle,
|
||||
"动图": ImageFilterEmpty.empty_filter_param,
|
||||
"像素抖动": ImageFilterImplement.apply_pixel_jitter,
|
||||
"描边": ImageFilterImplement.apply_stroke,
|
||||
"半调": ImageFilterImplement.apply_halftone,
|
||||
# 图像处理
|
||||
"存入图像": ImageFilterStorage.store_image,
|
||||
"读取图像": ImageFilterStorage.load_image,
|
||||
|
||||
Reference in New Issue
Block a user