首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

100 天构建 AI 视频编辑器原型

作者 | Kirk Kaiser       译者 | 明明如月

责编 | 夏萌

出品 | CSDN(ID:CSDNnews)

目前的生成式人工智能,尽管在很多方面为艺术家带来了便利和创新机会,但也存在争议,因为有观点认为它们更多是为了追求商业利益而设计。生成式人工智能的训练模型需要大量的资金、数据以及电力资源。

许多生成式人工智能模型是在庞大的艺术作品库上进行训练,但对于原创艺术家的补偿问题,不同的模型和使用条款有所不同。

然而,生成式人工智能完全有潜力增强艺术家的创作能力,并提升艺术作品的价值。

艺术家与颠覆性技术的关系

当流媒体技术兴起时,许多电视节目和音乐的创作者并未从流媒体交易中获益。例如,戴夫·查普尔(美国单口喜剧演员,编剧,制片人,演员)的节目在 Netflix 上播放时,他并未获得任何补偿,他不得不努力说服高管下架这个节目,以维护公平原则。泰勒·斯威夫特(一名美国创作歌手及音乐制作人)也曾通过艰苦谈判,为了确保公平的版税,她一度将自己的音乐从 Spotify 上撤下,直到 Spotify 同意调整她的版税费率。

在这种背景下,为创意工作者设计的生成工具必须有非常精准地定位。如果这些工具想要获得艺术家的认可,它们必须证明自己能够提升艺术作品的价值,并为独立艺术家开拓更广阔的市场。

资本力量倾向于利用新技术对艺术家施加财务压力,以增加对大资本持有者的回报,而这通常会损害艺术家的法律保护和经济利益。

讲故事、音乐和视觉艺术丰富了我们共同的人类体验。设计不佳的生成式人工智能可能会产生大量单调乏味的二次生成内容,这些内容可能会混淆我们的主要集体公共空间——互联网。

利用生成式人工智能为艺术家提供竞争优势

面对艺术家所面临的众多挑战,我们应该如何着手呢?如果生成式人工智能将改变创意过程,我们如何确保艺术家在这一变革中能够占有一席之地?

我尚无确切答案。

但我愿意去探索这个问题。

我发现,对一个领域感兴趣时,亲自动手构建东西能促进学习。而在创造新事物时,从最简单的想法开始往往是最佳选择。

与其开发一个复杂的系统来支持艺术家,不妨利用现有的模型来探索创新的创作方法。

我的专长主要在计算机视觉领域,因此我选择从这个领域入手。作为像  cyriak  这样艺术家的粉丝,我渴望建造一款工具,赋予世界 cyriak 式的风格。

开始,我找到了一个令人印象深刻的风格:

要实现此类效果,Facebook 的 Segment Anything 模型是理想选择。

原始艺术家在 After Effects 中的创作过程需要极大的耐心,以及大量手动遮罩的工作。当然,才华横溢的舞者像 Clay,他编排了自己的故事线以展现这种效果。但是,人物轮廓的操作和遮罩工作非常复杂。

一个能够帮助你创造性地探索视频片段,并提供更优化的遮罩工具,将是一个良好的起点。

因此,我开始了我的探索之旅...(大约 100 天)。

用 Python 构建开源人工智能视频编辑器?

随着机器学习模型的不断进步,使用 Python 开发一款辅助艺术家制作类似于 Clay 视频的软件,显得尤为合适。尽管我平时更多使用 Python 来开发后端基础架构而非桌面应用程序,但 Python 的使用领域实际上非常广泛。

因此,我开始探索使用 Python 构建视频编辑器的可能性,并搜索了相关工具包。

经过研究,我发现 ModernGL 结合 ModernGL-Window 能够提供一个在 Mac、Windows 和 Linux 上运行的高效 OpenGL 接口。此外,NVIDIA 提供了一个支持 NVIDIA 显卡进行视频硬件解码和编码的 Python 库。

当然,我还需要一个与正在编辑的视频交互的方法。为了实现这一点,我采用了 PyImgui ,在 OpenGL 窗口上构建用户界面。

使用 Imgui 构建原型界面

使用 moderngl-window,你能够明确定义并构建你的渲染循环:

import moderngl_windowfrom moderngl_window.text.bitmapped import TextWriter2D

class App(moderngl_window.WindowConfig): title = "Text" aspect_ratio = None

def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.writer = TextWriter2D() self.writer.text = "Hello ModernGL!"

def render(self, time, frame_time): self.writer.draw((240, 380), size=120)

App.run()

在 __init__ 方法中,可以设置窗口分辨率和其他所需配置。

Moderngl-window 也集成了 imgui,其添加过程非常简单:

import moderngl_windowimport imguifrom moderngl_window.integrations.imgui import ModernglWindowRendererfrom moderngl_window.text.bitmapped import TextWriter2D

class App(moderngl_window.WindowConfig): title = "Text" aspect_ratio = None

def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) imgui.create_context() self.imgui = ModernglWindowRenderer(self.wnd) self.writer = TextWriter2D() self.writer.text = "Hello ModernGL!"

def render(self, time, frame_time): self.writer.draw((240, 380), size=120) imgui.new_frame() imgui.begin("Custom window") imgui.text("hello world") imgui.end() imgui.render() self.imgui.render(imgui.get_draw_data())

def resize(self, width: int, height: int): self.imgui.resize(width, height)

def key_event(self, key, action, modifiers): self.imgui.key_event(key, action, modifiers)

def mouse_position_event(self, x, y, dx, dy): self.imgui.mouse_position_event(x, y, dx, dy)

def mouse_drag_event(self, x, y, dx, dy): self.imgui.mouse_drag_event(x, y, dx, dy)

def mouse_scroll_event(self, x_offset, y_offset): self.imgui.mouse_scroll_event(x_offset, y_offset)

def mouse_press_event(self, x, y, button): self.imgui.mouse_press_event(x, y, button)

def mouse_release_event(self, x: int, y: int, button: int): self.imgui.mouse_release_event(x, y, button)

def unicode_char_entered(self, char): self.imgui.unicode_char_entered(char)

App.run()

虽然代码量增加了,但大部分代码用于将事件传递给 imgui 实例,这样它就能识别我们的点击时间和位置。

Imgui 使用即时模式,允许在循环中直接定义 UI,极大地加快了原型构建的迭代速度。使用它,你可以迅速地构建和测试新想法。

在 OpenGL 中加载和处理视频

显然,只有当创意工具能够实时操作时,它们才真正发挥作用。

为了达到这一效果,我利用了大多数新型 NVIDIA 显卡内置的硬件加速解码器。

这允许我们使用 GPU 上的专用芯片解码每个视频帧。这样做可以加快搜索和播放速度,减少延迟,并且通常无需对加载的文件进行格式转换。

在 NVIDIA 硬件上,可以使用强大的 VideoProcessingFramework 。它甚至提供了示例代码,演示了如何将视频从输入色彩空间解码为 Pytorch 张量或 OpenGL 纹理:

# 定位到特定帧src_surface = nvDec.DecodeSingleSurface(nvc.SeekContext(frame_no))

# 使用管线转换为RGB色彩空间rgb_pln = to_rgb.run(src_surface)

# 转换为Pytorch张量src_tensor = surface_to_tensor(rgb_pln)

# 推送到CPU,作为numpy数组b = src_tensor.cpu().numpy()

这提供了可在 Pillow 或 PyTorch/Numpy 中操作的数据,方便在原型制作中保存为帧。

有了这些基础,我们就可以结合使用 Segment Anything,并通过 imgui 选择 OpenGL 帧中的目标点。但需注意,在实现这一点之前,虽然 ModernGL-Window 支持 MacOS,但 MacOS 并不支持任何 NVIDIA 硬件。

在 MacOS 中构建硬件视频解码和 Stable Diffusion XL

虽然我花了时间探索,但在 MacOS 上,包括 M1 和 M2 系列处理器,实现硬件解码依然困难。

因此,我尝试为 MacOS 编写一个 Python 硬件播放库,尽管苹果公司已用 Objective-C 开发了用于硬件解码的扩展,但这些 API 尚未有 Python 接口。

为了实现这一目标,我采用了 Cython,并参考了 OpenFramework 的视频播放器实现。这一方法使我得以将Objective-C 代码转换为 C++,进而转换为一个能够播放视频的 Python API 。

经过多次尝试和错误,我终于完成了一个可在 MacOS 机器上导入和运行的库。这个库拥有一个合理的 API ,与 NVIDIA 的 VideoProcessingFramework 大致相似:

import videoplayback

player = videoplayback.AVFPlayer()player.load("filename")

# 不幸的是,加载文件的操作还不是同步的time.sleep(.3)

numFrames = player.length_in_frames()w = player.width()h = player.height()

destination_frame = 1# 获取一帧player.seek(destination_frame)image = np.asarray(player.imageframe())image = image.view(np.uint8).reshape(image.shape + (-1,))# 形状 (1080, 1920, 4)image = image[:,:,0:3]b[:,:,[0,2]] = b[:,:,[2,0]]# 形状 (1080, 1920, 3)image = image.copy(order='C')

关于 Stable Diffusion XL,苹果发布了一个部分优化的库,使得在 M1 和 M2 硬件上能使用硬件加速生成图像。

然而,这些优化导致在我的 64GB 内存的 M1 MacBook Pro 上生成单张图片需约 2 分钟。对创意工作者而言,这并非理想的反馈周期。相比之下,在我配备 4090 显卡的台式电脑上,生成一个 Stable Diffusion XL 图像只需几秒。然而,通过使用像 Modal 这样的服务,我可以借助无服务器 GPU 实例将推理时间缩减至几秒。

早期反馈的获取

当我向一位朋友展示了视频编辑器原型时,他对视频中的实时物体分割功能表现出极大兴趣。

因此,我采用了 De-AOT 模型来实现这一功能,该模型能预测视频中接下来约 20 帧的内容,并几乎达到了预期效果。

在此过程中,我探索了使用 Stable Diffusion 的新方法,这些方法不仅可以模仿创意工作者的作品,还可以作为赋能工具。

构建用于资产生成的模型管道

通常,扩散模型并不是为融入现有框架或上下文而设计的。它们的主要目的是根据文本提示从头开始创造图像,从噪声中构想出图像的可能样貌,并逐步将其实现。

为在视频中生成透明资产(如 UFO 或箭头),我们需能自动从图像中分离和提取所需元素。

有了这些技术,我们现在可以生成并查看内容:

def generate_segmented_diffusion(object, prompt, negative_prompt="", auto=True, seed=None): if seed is not None: generator = torch.Generator(device="cuda").manual_seed(seed) pipeline_text2image = AutoPipelineForText2Image.from_pretrained( "stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True, cache_dir="/app/.cache", generator=generator ).to("cuda") else: pipeline_text2image = AutoPipelineForText2Image.from_pretrained( "stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True, cache_dir="/app/.cache" ).to("cuda")

img = pipeline_text2image(prompt=prompt,negative_prompt=negative_prompt).images[0]

if auto: # 仅使用 SAM 的第一个掩码 model = get_dino_model() img_ground = transform_pil_image_for_grounding(img) b, p = get_grounding_output(model=model, image=img_ground, caption=object, box_threshold=.35, text_threshold=.25) boxes = b * 1024 # 1024 x 1024 的 SDXL 图像 boxes = box_convert(boxes=boxes, in_fmt="cxcywh", out_fmt="xyxy").numpy() predictor.set_image(np.asarray(img)) masks, _, _ = predictor.predict(box=boxes[0]) # 仅使用第一个进行自动预测 masks = np.where(masks, 255, 0) masks = masks.copy(order='C') img_cutout = Image.new('RGBA', (1024, 1024), color=(0,0,0,0)) mask = Image.fromarray(masks[0].astype('uint8')) img_cutout.paste(img, (0,0), mask=mask) img_cutout = img_cutout.transpose(Image.Transpose.FLIP_TOP_BOTTOM) return img_cutout else: # 返回图像和掩码 model = get_dino_model() img_ground = transform_pil_image_for_grounding(img) b, p = get_grounding_output(model=model, image=img_ground, caption=object, box_threshold=.35, text_threshold=.25) boxes = b * 1024 #

1024 x 1024 的 SDXL 图像 boxes = box_convert(boxes=boxes, in_fmt="cxcywh", out_fmt="xyxy").numpy() predictor.set_image(np.asarray(img)) masks, _, _ = predictor.predict(box=boxes[0]) # 仅使用第一个进行自动预测 masks = np.where(masks, 255, 0) masks = masks.copy(order='C') return img, masks

现在,我们可以探索现有艺术愿景,而非完全从头创造图像。(顺便提一下,我之前对 Stable Diffusion 及其训练数据集持有怀疑。我觉得(可能我错了)结合反馈,而非完全自动生成,可能是更好的方法。但我仍不确定。)

使用 ControlNet 与图像协作

ControlNet 是一种用于引导和控制扩散过程的技术,通过使用自定义输入来训练模型,实现扩散模型生成中的精准控制。

例如,使用 OpenPose 这样的模型,可以精确控制图像中人物的姿势。ControlNet 则能准确设定图像中人物的数量和位置。

此外,要将物体转化为扩散图像时,可以用 Canny 边缘检测等方法获取物体轮廓,引导生成过程。

这些模型可用于调整视频中的主体,同时维持其原始比例。在上述视频示例中,我将一个橙色障碍物转换成了混凝土障碍物。

但仔细观察会发现一些问题。理想情况下,应该有一个能随着相机移动而变化的虚拟 3D 主体。

TokenFlow:视频扩散网络的应用

然而,仅使用 ControlNet 处理视频效果并不理想,如下方视频所示,扩散模型因输入噪声不同而产生多样结果,造成画面频繁闪烁。即使使用相同的初始种子图像保持帧间一致,由于扩散模型的工作原理,仍然会出现闪烁。

有技术如  AnimateDiff 可减少闪烁,通过在扩散器中加入时间层。但这些技术并非完美。

我所见最佳时间稳定性实现是 TokenFlow,它用名为 Plug and Play 的方法引导图像生成,同时保持空间连贯性。例如,视频中展示的片段,提示是“一个人在冲浪”。

Plug and Play 技术使用一个初始图像,通过 DDIM 反转为噪声,然后通过扩散过程提取生成图像的关键特征。这些特征随后被注入扩散模型的自我关注层,同时使用与原始图像相同的反转噪声。

结合此技术与帧间相关性,能生成时间上一致且相对无闪烁的视频,如上面的视频所示。然而,这两种技术看起来都带有一定的人工痕迹,与“人工智能视频”相关的特定人工制品。

构建 ebsynth 的模型导出器

Ebsynth 是一种基于非深度学习的方法,专门用于将视频的纹理替换为另一种艺术风格。它的工作原理是采用一系列视频帧,并结合一些已经绘制成目标视频风格的关键帧。

可以结合 ControlNet 和 Stable Diffusion 来处理视频,探索基于文本提示的各种纹理创意。

在这个例子中,我使用了“红热熔岩火山火焰”作为提示,目的是为了创造一个发光的效果。

对于 ControlNet,我首先检测图像中是否有人物,如果有,就结合使用针对 OpenPose 的加权 ControlNet 和 Canny 图像 ControlNet。

鉴于我们已经构建的其他工具,将 ebsynth 生成集成进来相对简单。我们需要选取一部分帧,并在这些帧上运行 Stable Diffusion。这样做可以确保它们都源自同一扩散模型生成路径。我还为视频添加了掩码模式,可专门为特定人物创作纹理,而非整个视频。

这样,我们就能够在视频中为单个主题生成特殊效果,确保效果的一致性。

完成这些之后,我们可以将生成的角色版本重新放入视频中。

为艺术家构建人工智能

在花费数月时间利用计算机视觉模型和生成性人工智能构建编辑器后,我的收获是什么?

视频本质上是多模态的,涵盖了图像、音频和叙述等多个方面。虽然一些机器学习模型能处理多模态输入,但视频创作的日常工作仍未完全适应单一模型。我发现,传统视频编辑与模型协作的结合产生了最有趣的结果。

但这些工具并未取代创造力!创造力的关键在于坚持不懈的日常工作。有时你会感觉工作进展顺利,而有时似乎一切都难以进行。

我们在生成式人工智能的探索之路上还处于初期阶段,我还无法确切预测未来的发展。我能看到工具逐渐成型,但具体哪些工具会胜出,或者事情将如何发展,目前还不得而知。

我们的目标是超过那些试图替代创意工作者的资本巨头,而是助力创意工作者获得成功。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/O-kzlvgv2dySiunYH3zL5rKg0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券