You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python绘图中为特定填充对象单独添加模糊效果?

为独立填充的非规则图形添加个性化模糊效果(模拟景深)

背景与需求

  • 环境:Linux Mint 20.3 Una,Python 3.8.10
  • 任务:制作包含数千个鱼形的动画,每个鱼形通过指定2D轮廓点,用Matplotlib的fill函数生成填充区域
  • 核心需求:根据计算出的距离,为每个独立填充区域添加独特的模糊效果以模拟景深,且区域存在重叠情况
  • 痛点:手动在Inkscape等工具处理SVG不可行(数千鱼形+数百帧),尝试plt.fill句柄结合gaussian_filter无效,需代码化解决方案

最小复现代码

import matplotlib.pyplot as plt
import numpy as np

# 定义鱼形轮廓点
x_profile = [0.5,0.485951301332915,0.423371700761206,0.358237605529776,0.281609306290982,0.23180095266422,0.152618567550257,0.053001860296735,-0.005746611462221,-0.060663545623872,-0.05683323438022,-0.257343937095579,-0.317369329156755,-0.345466399463283,-0.469348762061393,-0.492337251833031,-0.5,-0.439974607938825,-0.418263242861681,-0.415709156986512,-0.461686095651334,-0.492337415346851,-0.483397419850022,-0.466794594429313,-0.363346513092306,-0.342912313588113,-0.31864669912198,-0.289272544999412,-0.236909860226751,-0.210090037250083,-0.183269887245775,-0.146233189348514,-0.078544599457363,0.086206203027589,0.210088361233424,0.310982111424531,0.418261893872663,0.478287408569203,0.493612741389321]
y_profile = [-0.019156461632871,0.002554903444271,0.031928934931474,0.051085805348896,0.065134504015981,0.07024308455087,0.071518492350251,0.067688181106599,0.158365179012477,0.068965632828735,0.049808353626761,0.028096988549618,0.025542085105346,0.03192770857782,0.10217038434414,0.104725287788412,0.091954040843463,0.00255449465972,-0.00255449465972,-0.017879827479838,-0.067688181106599,-0.148148017942698,-0.158365179012477,-0.151979555540003,-0.061302557634125,-0.047254267751592,-0.040868235494567,-0.042143643293948,-0.080457792913345,-0.084288104156997,-0.079179523622108,-0.097059759886497,-0.111108049769031,-0.127710834311284,-0.126435426511903,-0.107278556094481,-0.076627072885143,-0.045975589675805,-0.031927299793271]

n_objects = 2
n_points = len(y_profile)

x_points = np.zeros((n_objects, n_points))
y_points = np.zeros((n_objects, n_points))                  

for i in range(n_objects):
    for j in range(n_points):
        x_points[i,j] = x_profile[j]
        y_points[i,j] = y_profile[j] - i*0.5

# 创建画布
fig = plt.figure(frameon=False)
fig.set_size_inches(6.5, 6.5)
ax = plt.axes()
ax.set_facecolor((0,0,1.0))
ax.set_xlim(-1,+1)
ax.set_ylim(-1,+1)
ax.set_aspect('equal', adjustable='box')
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
for spine in ax.spines.values():
    spine.set_visible(False)

# 绘制两个鱼形填充区域
for i in range(n_objects):
    plt.fill(x_points[i,:], y_points[i,:], color = (0, 0, 0.5))

plt.show()

上述代码生成两个上下偏移的深蓝色鱼形,背景为纯蓝色。


可行解决方案

方案1:像素级分层渲染+模糊(Matplotlib+SciPy)

思路:将每个鱼形单独渲染到透明临时画布,应用高斯模糊后再合成到主画布,保留重叠区域的正确层级。

import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import gaussian_filter

# 鱼形轮廓点(同前文,省略重复代码)
x_profile = [...]
y_profile = [...]

n_objects = 2
n_points = len(y_profile)

x_points = np.zeros((n_objects, n_points))
y_points = np.zeros((n_objects, n_points))                  

for i in range(n_objects):
    for j in range(n_points):
        x_points[i,j] = x_profile[j]
        y_points[i,j] = y_profile[j] - i*0.5

# 自定义每个鱼形的模糊sigma值(可根据距离动态计算)
sigmas = [1, 3]

# 创建主画布
fig = plt.figure(frameon=False)
fig.set_size_inches(6.5, 6.5)
ax = plt.axes()
ax.set_facecolor((0,0,1.0))
ax.set_xlim(-1,+1)
ax.set_ylim(-1,+1)
ax.set_aspect('equal', adjustable='box')
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
for spine in ax.spines.values():
    spine.set_visible(False)

# 逐个渲染鱼形并模糊
for i in range(n_objects):
    # 创建临时透明画布
    temp_fig = plt.figure(frameon=False)
    temp_fig.set_size_inches(6.5, 6.5)
    temp_ax = temp_fig.add_axes([0,0,1,1])
    temp_ax.set_xlim(-1,+1)
    temp_ax.set_ylim(-1,+1)
    temp_ax.set_aspect('equal', adjustable='box')
    temp_ax.set_facecolor('none')
    temp_ax.get_xaxis().set_visible(False)
    temp_ax.get_yaxis().set_visible(False)
    for spine in temp_ax.spines.values():
        spine.set_visible(False)
    
    # 在临时画布绘制单个鱼形
    temp_ax.fill(x_points[i,:], y_points[i,:], color=(0,0,0.5))
    
    # 将画布转为像素数组
    temp_fig.canvas.draw()
    buf = temp_fig.canvas.buffer_rgba()
    temp_img = np.asarray(buf)
    
    # 分离RGB和Alpha通道,仅模糊RGB部分
    rgb = temp_img[:, :, :3]
    alpha = temp_img[:, :, 3:]
    blurred_rgb = gaussian_filter(rgb, sigma=sigmas[i])
    blurred_img = np.concatenate([blurred_rgb, alpha], axis=2)
    
    # 将模糊后的图像合成到主画布
    ax.imshow(blurred_img, extent=[-1,1,-1,1], origin='lower')
    
    # 关闭临时画布释放资源
    plt.close(temp_fig)

plt.show()

方案2:矢量级SVG批量修改

思路:利用Matplotlib导出的SVG中每个填充区域是独立<path>元素的特性,通过XML解析工具为每个路径添加高斯模糊滤镜。

import matplotlib.pyplot as plt
import numpy as np
from xml.etree import ElementTree as ET

# 鱼形轮廓点(同前文,省略重复代码)
x_profile = [...]
y_profile = [...]

n_objects = 2
# 对应每个鱼形的模糊程度
sigmas = [1, 3]

# 生成原始SVG
fig = plt.figure(frameon=False)
fig.set_size_inches(6.5, 6.5)
ax = plt.axes()
ax.set_facecolor((0,0,1.0))
ax.set_xlim(-1,+1)
ax.set_ylim(-1,+1)
ax.set_aspect('equal', adjustable='box')
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
for spine in ax.spines.values():
    spine.set_visible(False)

# 绘制鱼形
for i in range(n_objects):
    x = x_profile
    y = [y - i*0.5 for y in y_profile]
    ax.fill(x, y, color=(0,0,0.5))

# 导出SVG
svg_path = 'fish_frame.svg'
plt.savefig(svg_path, format='svg', transparent=True)
plt.close()

# 解析并修改SVG
ET.register_namespace('', "http://www.w3.org/2000/svg")
tree = ET.parse(svg_path)
root = tree.getroot()

# 添加滤镜定义
defs = ET.SubElement(root, '{http://www.w3.org/2000/svg}defs')
for idx, sigma in enumerate(sigmas):
    filter_id = f'blur-filter-{idx}'
    filter_elem = ET.SubElement(defs, '{http://www.w3.org/2000/svg}filter', id=filter_id)
    ET.SubElement(filter_elem, '{http://www.w3.org/2000/svg}feGaussianBlur', 
                  stdDeviation=str(sigma))
    
    # 为对应路径添加滤镜引用(跳过第一个path,为背景)
    path_elem = root.findall('.//{http://www.w3.org/2000/svg}path')[idx+1]
    path_elem.set('filter', f'url(#{filter_id})')

# 保存修改后的SVG
tree.write('fish_frame_blurred.svg', encoding='utf-8', xml_declaration=True)

方案3:使用专业动画库(如Manim)

如果需要制作复杂动画,Manim等专业动画库支持直接为矢量对象添加模糊滤镜,适合批量处理大量元素。示例片段:

from manim import *

class FishBlurAnimation(Scene):
    def construct(self):
        # 定义鱼形路径
        fish_path = VMobject()
        fish_path.set_points_as_corners([
            (0.5, -0.019, 0), (0.485, 0.002, 0), ...  # 完整轮廓点
        ])
        fish_path.set_fill(BLUE_D, opacity=1)
        
        # 复制并偏移鱼形,添加不同模糊
        fish1 = fish_path.copy().shift(UP*0.5)
        fish1.set_blur(1)
        
        fish2 = fish_path.copy().shift(DOWN*0.5)
        fish2.set_blur(3)
        
        self.add(fish1, fish2)
        self.wait()

内容的提问来源于stack exchange,提问作者user20787420

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 08:15:46