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

Gizeh+Moviepy透明背景渲染伪影问题技术求助

问题描述

使用Gizeh绘制带圆盘的Surface帧,通过Moviepy合成视频时,将Surface的bg_color从(0.2,0.5,0.2,1.0)改为(0.2,0.5,0.2,0.0)设置透明背景后,移动的圆盘在运动方向前方出现异常伪影,圆盘重叠时还会出现颜色渗色问题,尝试多种Alpha值后问题仍存在。


核心绘制函数代码

def make_frame(t):
    
    surface = gizeh.Surface(1080,1080,bg_color=(0.2,0.5,0.2,1.0))
    #draw border
    border_width= 40.00
    Border=gizeh.rectangle(1080, 1080, xy=((1080//2,1080//2)), stroke = (1.0,1.0,1.0), stroke_width = border_width)
    Border.draw(surface)
    for disc in discs:
        Ball_w=gizeh.circle(r=(disc.size), xy=[disc.position[0] ,disc.position[1]], fill= (disc.color))
        Ball_w.draw(surface)
        disc.collide_with_wall(table_width, table_height, border_width)
        #disc.collide_with_disc(discs)
        disc.move()
    return surface.get_npimage(transparent=True)

背景修改点

bg_color=(0.2,0.5,0.2,1.0)  # 修改前
bg_color=(0.2,0.5,0.2,0.0)  # 修改后

Disc类实现代码

class Disc:
    def __init__(self, size, density, position, velocity, color):
        self.size = size
        self.density = density
        self.mass = size*size*density
        self.position = position
        self.velocity = velocity
        self.color = color
    def move(self):
        # Update the position of the disc based on its velocity
        self.position[0] = (self.position[0] + self.velocity[0])
        self.position[1] = (self.position[1] + self.velocity[1])
    def update_position(self, new_position):
        self.position = new_position
    def update_velocity(self, new_velocity):
        self.velocity = new_velocity
    def collide_with_wall(self, width, height, border_width):
        # Check for collisions with the walls of the pool table
        if self.position[0] <=0+self.size+border_width/2:
            self.velocity[0] =abs(self.velocity[0])  # Reverse the x-direction velocity
    
        if self.position[0] >= width-self.size-border_width/2:
            self.velocity[0] =-abs(self.velocity[0])  # Reverse the x-direction velocity
        
        if self.position[1] <=0+self.size+border_width/2:
            self.velocity[1] =abs(self.velocity[1])  # Reverse the y-direction velocity

        if self.position[1] >= height-self.size-border_width/2:
            self.velocity[1] =-abs(self.velocity[1])  # Reverse the y-direction velocity

帧合成代码

for frame_no in range (0, int(num_frames)):
    clip=get_array_clip(discs,frame_no)
    palette_clip.append(clip)
final_vid=concatenate_videoclips(palette_clip, method="chain" )
final_vid.set_start(palette_start_time)
clip=[]
clip.append(final_vid.set_start(palette_start_time).set_position((0,420)))
return clip

解决建议
  • 强制每帧全透明初始化:替换原半透明背景为纯透明,避免Gizeh混合逻辑导致的帧残留。创建Surface后手动填充全透明画布:

    surface = gizeh.Surface(1080,1080,bg_color=(0,0,0,0))
    # 确保画布完全清空
    gizeh.rectangle(1080,1080, xy=(540,540), fill=(0,0,0,0)).draw(surface)
    
  • 调整抗锯齿设置:伪影和渗色多来自透明背景下的抗锯齿边缘混合。绘制元素时显式关闭抗锯齿:

    Border=gizeh.rectangle(1080, 1080, xy=(540,540), stroke=(1.0,1.0,1.0), stroke_width=border_width, anti_alias=False)
    Ball_w=gizeh.circle(r=disc.size, xy=[disc.position[0],disc.position[1]], fill=disc.color, anti_alias=False)
    

    若需要抗锯齿,可使用高分辨率渲染后缩小:

    surface = gizeh.Surface(1080,1080,bg_color=(0,0,0,0), pxratio=2)
    # 绘制完成后缩至原尺寸
    frame = surface.get_npimage(transparent=True)[::2,::2]
    return frame
    
  • 修改Moviepy合成模式:用compose替代chain,确保每帧完全覆盖,避免帧间残留:

    final_vid=concatenate_videoclips(palette_clip, method="compose")
    

    同时确认每个clip的帧数组为RGBA 4通道格式,创建clip时明确is_mask=False。

  • 隔离帧间状态:原代码直接修改全局discs对象会导致帧间状态污染,每帧生成时使用对象副本:

    from copy import deepcopy
    def make_frame(t):
        frame_discs = deepcopy(discs)
        surface = gizeh.Surface(1080,1080,bg_color=(0,0,0,0))
        # 后续绘制逻辑使用frame_discs副本
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 20:42:48