- 音视频
- 视频处理
- 图形学
- 桌面应用
【免费下载链接】Natron
Open-source video compositing software. Node-graph based. Similar in functionalities to Adobe After Effects and Nuke by The Foundry.
导读
ItemBase 是 Natron 引擎中 Roto(rotoscoping/roto 节点)内部所有形状与层级对象的公共基类,它为 Layer(分组层)和 BezierCurve(贝塞尔曲线形状)统一提供了标签、脚本名、锁定状态、可见性、父层与参数访问等基础能力。本文以官方 Python API 参考文档 ItemBase.rst 为核心骨架,逐一对每个成员函数进行签名、语义、源码实现与实战脚本的深度讲解,帮助你在编写 Natron Python 插件或自动化 Roto 工作流时,准确、安全地操作任何 roto 项目。
类概览:ItemBase 在 Roto 对象体系中的位置
ItemBase 是一个抽象类,它本身不会直接实例化,而是作为Layer与BezierCurve两个具体子类的公共基类存在。官方文档将其定位为"gathers all common functions to both layers and beziers",即所有既适用于图层、也适用于曲线的通用操作都被集中在这里。
在 Natron 的 roto 节点中,形状层级结构大致如下:
Roto:封装整个 roto 节点内容的入口对象(见 Roto.rst),负责创建Layer、BezierCurve等对象,并提供getBaseLayer()、getItemByName()等访问接口;Layer:用于分组多个形状并控制渲染顺序,继承自 ItemBase;BezierCurve:单个贝塞尔形状(含椭圆、矩形等便捷构造),继承自 ItemBase。
从源码看,这一继承关系在 PyRoto.h 中定义得十分清晰:class ItemBase持有一个RotoItemPtr _item(指向引擎层 RotoItem.h 中的 RotoItem 对象),随后class Layer : public ItemBase与class BezierCurve : public ItemBase分别对其扩展。也就是说,ItemBase 的每个 Python 方法最终都转发到引擎层的RotoItem或RotoDrawableItem上,Python 绑定层(Shiboken)仅负责类型转换与所有权管理。
注意:ItemBase 文档中所有方法的实现转发都位于 PyRoto.cpp,后续每个小节都会给出对应的实现依据。
核心概念:script-name 与 label 的区别
理解 ItemBase 之前,必须先分清 roto 中每个 item 的两重标识:
| 标识 | 含义 | 唯一性 |
|---|---|---|
| script-name | 脚本名,用于在 Python 脚本中唯一寻址该 item | 在同一个 roto 节点内唯一 |
| label | 显示标签,即设置面板表格中看到的名称 | 可以有多个 item 同名 |
官方文档原文明确:"Thescript-nameuniquely identifies an item within a roto node, while several items can have the samelabel."(ItemBase.rst)。这组概念与节点系统中的脚本名/标签语义一致:脚本名是编程寻址的句柄,标签则是给人看的名字。
Roto 文档还展示了 script-name 的自动声明访问方式(auto-declared variables),例如:
app1.Roto1.roto.Layer1.Bezier1等价于调用getItemByName:
app1.Roto1.roto.Layer1.Bezier1 = app1.Roto1.roto.getItemByName("Bezier1")(见 Roto.rst)。由于 script-name 唯一,这种"按名寻址"才是可依赖的,label 则不具备寻址能力。
成员函数详解
以下 11 个成员函数全部继承自 ItemBase,对 Layer 和 BezierCurve 通用。按"读取/查询类"与"修改/写入类"分组讲解。
查询类函数
getLabel()
- 签名:
def getLabel() - 返回类型:
str - 语义:返回该 item 的标签,即设置面板表格中显示的那个名字。
源码实现位于 PyRoto.cpp,最终调用引擎层的_item->getLabel()(定义于 RotoItem.h)。注意返回的是std::string,绑定层用QString::fromUtf8转成 Pythonstr,因此含非 ASCII 字符的标签也能正确往返。
getScriptName()
- 签名:
def getScriptName() - 返回类型:
str - 语义:返回 item 的脚本名。该名字在同一 roto 节点内对每个 item 唯一,是脚本寻址的基础。
对应实现 PyRoto.cpp。引擎层 RotoItem.h 中getScriptName()与getFullyQualifiedName()并存,后者可给出完整层级路径,而前者只给出当前 item 自身的脚本名。
getParentLayer()
- 签名:
def getParentLayer() - 返回类型:
Layer(若无父层返回None) - 语义:返回该 item 的父层。官方文档强调:除基础层(base layer)外,所有 item 都必须有一个父层。
实现见 PyRoto.cpp:底层取_item->getParentLayer(),若存在则包装成一个新的 PythonLayer对象返回,否则返回0(即 Python 的None)。正因为存在这种"可能无父层"的例外,脚本中调用getParentLayer()后应习惯性地判空。Shiboken 绑定中,该函数的返回值被声明为target所有权(见 typesystem_engine.xml),确保返回的 Layer 对象由 Python 侧管理,可安全长期持有。
getParam(name)
- 签名:
def getParam(name) - 参数:
name(str,参数的脚本名) - 返回类型:
Param或None - 语义:按脚本名返回该 item 的某个参数;若不存在则返回
None。
实现 PyRoto.cpp 值得注意:它先通过dynamic_cast<RotoDrawableItem*>判断 item 是否可绘制——只有RotoDrawableItem(即 Bezier 这类形状)才携带参数,纯粹的 Layer 会直接返回空;随后通过drawable->getKnobByName(name)查找旋钮,找不到同样返回空;最终用Effect::createParamWrapperForKnob(knob)把引擎层 Knob 包装成 Python 侧Param对象返回。
因此,实际使用中:
- 对
BezierCurve对象,可通过getParam拿到诸如激活、不透明度、羽化距离、羽化衰减、颜色、合成算子等参数(这些参数的便捷访问器在 PyRoto.h 中另有一组专门的getActivatedParam()、getOpacityParam()等,返回类型更精确); - 对
Layer对象调用getParam通常会得到None。
getLocked()
- 签名:
def getLocked() - 返回类型:
bool - 语义:返回该 item 是否被锁定。锁定后,用户在界面上不能再编辑该 item。
实现 PyRoto.cpp 直接转发到_item->getLocked()。注意它只查询 item 自身的锁定标志。
getLockedRecursive()
- 签名:
def getLockedRecursive() - 返回类型:
bool - 语义:返回该 item 是否处于锁定状态,但与
getLocked()不同,它会递归向上检查所有父层,只要任意一层被锁定,就认为该 item 被锁定。
这是与getLocked()最容易混淆的方法。二者的差异可归纳为:
| 方法 | 检查范围 | 典型用途 |
|---|---|---|
getLocked() | 仅该 item 自身的锁定标志 | 判断"这一项"是否被单独锁定 |
getLockedRecursive() | 该 item 及其所有祖先层 | 判断"整个子树"是否实际不可编辑 |
实现中它调用的是 RotoItem.h 的isLockedRecursive(),引擎层同样存在递归设置版本的setLocked_recursive(RotoItem.h),与递归查询相互对应。在编写自动化脚本时,若要判断"我能否安全修改这个形状",应优先使用getLockedRecursive()。
getVisible()
- 签名:
def getVisible() - 返回类型:
bool - 语义:返回该 item 是否可见。在用户界面中,这对应设置面板里的小"眼睛"图标。
官方文档给出了一个非常关键的行为说明(ItemBase.rst):
当隐藏时,item 的 overlay(覆盖层)将不再在查看器中绘制,但它仍然会渲染到图像中。
也就是说,可见性开关只影响交互式 overlay 的显示,不影响最终渲染结果。这对自动化的意义重大:批量"隐藏"形状只用于清理界面显示,不会改变输出图像。
实现 PyRoto.cpp 调用_item->isGloballyActivated(),引擎层 RotoItem.h 将其声明为 MT-safe(多线程安全),可放心在渲染相关脚本中读取。
修改类函数
setLabel(name)
- 签名:
def setLabel(name) - 参数:
name(str) - 返回类型:无(
None) - 语义:设置该 item 的标签。
实现 PyRoto.cpp 调用_item->setLabel(...)(RotoItem.h)。在 Shiboken 绑定里该函数通过inject-code直接调用而不保留返回值(typesystem_engine.xml)。由于 label 不要求唯一,你可以放心为多个形状设置同样的标签用于视觉归类。
setScriptName(name)
- 签名:
def setScriptName(name) - 参数:
name(str) - 返回类型:
bool(是否设置成功) - 语义:设置该 item 的脚本名。
官方文档对此方法给出了强烈警告(ItemBase.rst):
你绝不应该自己调用它,因为 Natron 会自动为每个 item 选择唯一的脚本名。该函数仅为内部技术需要而开放,而且要知道:更改 item 的脚本名可能破坏其他依赖它的脚本。
结合引擎实现可以理解这个警告的由来:setScriptName在 RotoItem.h 中标注为"仅可在主线程调用",且必须保证 roto 节点内唯一性;PyRoto.cpp 直接透传返回值,Shiboken 绑定层也专门注入代码处理其bool返回值(typesystem_engine.xml)。如果确有重命名需求,务必:
- 确认新名字在当前 roto 节点内没有冲突;
- 同步更新所有引用旧脚本名的其他脚本与表达式;
- 用返回值判断是否成功,失败时回滚逻辑。
setLocked(locked)
- 签名:
def setLocked(locked) - 参数:
locked(bool) - 返回类型:无
- 语义:设置该 item 是否锁定,语义与
getLocked()对应。
实现 PyRoto.cpp 很有意思:它调用的是_item->setLocked(locked, true, RotoItem::eSelectionReasonOther)——第二个参数true表示同时锁定/解锁所有子项。也就是说,Python 层的setLocked行为是递归的:锁定一个 Layer 会连带锁定其下所有形状。这在批量保护内容时非常高效,但也意味着你要小心别误锁整棵子树。若只想锁定单个形状而不影响其父层或子项,应在引擎层行为之上自行设计(例如先记录子项状态)。
setVisible(activated)
- 签名:
def setVisible(activated) - 参数:
activated(bool) - 返回类型:无
- 语义:设置该 item 是否在查看器中可见,语义与
getVisible()对应(仅影响 overlay 显示,不影响渲染)。
实现 PyRoto.cpp 调用_item->setGloballyActivated(activated, true),同样带有true的递归子项参数,说明对 Layer 设置可见性也会级联到其全部子形状。引擎层 RotoItem.h 同样标注该操作仅允许在主线程调用,脚本中应避免在渲染线程内直接切换可见性。
方法与源码实现映射表
为便于快速对照,将 ItemBase 的 Python API 与引擎层实现整理如下:
| Python 方法 | 引擎实现(PyRoto.cpp) | 底层核心(RotoItem.h) |
|---|---|---|
getLabel() | L59-L63 | getLabel()(L105) |
setLabel(name) | L53-L57 | setLabel()(L107) |
getScriptName() | L71-L75 | getScriptName()(L103) |
setScriptName(name) | L65-L69 | setScriptName()(L101,仅主线程) |
getLocked() | L83-L87 | getLocked()(L124) |
getLockedRecursive() | L89-L93 | isLockedRecursive()(L126) |
setLocked(locked) | L77-L81 | setLocked(locked, true, ...)(L123,递归子项) |
getVisible() | L101-L105 | isGloballyActivated()(L119,MT-safe) |
setVisible(activated) | L96-L99 | setGloballyActivated(a, true)(L116,递归子项) |
getParentLayer() | L107-L117 | getParentLayer()(L113,MT-safe) |
getParam(name) | L119-L134 | RotoDrawableItem::getKnobByName()包装 |
Python 绑定层的所有权与返回值处理细节可参见 typesystem_engine.xml。
实战:用 ItemBase API 编写 Roto 自动化脚本
下面给出可直接在 Natron Python 脚本编辑器(或 PyPlug)中运行的综合示例,演示 ItemBase 各方法的典型组合用法。
# 获取当前工程中名为 Roto1 的 roto 节点 rotoNode = app1.Roto1 roto = rotoNode.roto # Roto 对象 # 1) 访问基础层并创建自己的子层 baseLayer = roto.getBaseLayer() myLayer = roto.createLayer() baseLayer.addItem(myLayer) # 2) 在子层内创建椭圆并设置脚本名 ellipse = roto.createEllipse(0, 0, 200, True, app1.frame) myLayer.addItem(ellipse) ellipse.setScriptName("EllipseMain") # 虽然官方不建议主动改名,这里展示用法 print("script name:", ellipse.getScriptName()) # -> EllipseMain print("label:", ellipse.getLabel()) # -> 默认标签 ellipse.setLabel("主遮罩") # 标签可以是非 ASCII 中文 print("new label:", ellipse.getLabel()) # 3) 可见性与锁定控制 ellipse.setVisible(False) # 隐藏 overlay,但仍会渲染 print("visible:", ellipse.getVisible()) # -> False myLayer.setLocked(True) # 递归锁定整个子层 print("locked:", ellipse.getLocked()) # -> 子项自身标志,可能是 False print("locked recursive:", ellipse.getLockedRecursive()) # -> True(父层已锁) # 4) 层级关系与按名寻址 print("parent is base:", ellipse.getParentLayer() is baseLayer) # -> False(父层是 myLayer) sameItem = roto.getItemByName("EllipseMain") # 按唯一脚本名找回同一对象 print("same item:", sameItem is ellipse) # 5) 参数访问(Bezier 形状才有参数) opacityParam = ellipse.getParam("opacity") if opacityParam is not None: print("opacity at current frame:", opacityParam.getValue())几点实战提醒:
- 先判空再取父层:基础层
getParentLayer()返回None,遍历层级时务必判断。 - 递归语义:
setLocked/setVisible都会递归影响子项,配合getLockedRecursive()判断实际编辑权限。 - 可见性 ≠ 渲染开关:
setVisible(False)只隐藏 viewer overlay,图像渲染结果不变,适合做"界面收纳"而不会破坏输出。 - 慎用 setScriptName:重命名会破坏依赖旧脚本名的脚本与表达式;批量处理时先收集所有引用再统一改名。
- getParam 返回 None 属正常情况:对 Layer 调用
getParam一般返回None,只有可绘制形状(BezierCurve)才有参数集合。
关联 API 与进一步阅读
ItemBase 是 roto 对象体系的地基,与以下 API 文档配合阅读可形成完整认知:
- Layer.rst:ItemBase 的派生类之一,负责分组、排序与渲染顺序(从下到上绘制);
- BezierCurve.rst:另一个派生类,提供控制点、羽化、颜色等形状专属操作;
- Roto.rst:roto 节点入口对象,提供
createBezier/createEllipse/createRectangle/createLayer/getBaseLayer/getItemByName; - Param.rst:
getParam(name)返回的通用参数对象; - 源码层参考:PyRoto.cpp、PyRoto.h、RotoItem.h、typesystem_engine.xml。
掌握 ItemBase 这套统一的标签/脚本名/锁定/可见性/层级/参数接口,就等于掌握了操作 Natron roto 节点内任意形状与图层的通用入口——无论是批量整理 Roto 层级、做脚本化 Mask 管理,还是构建复杂的自动化抠像工作流,都能以一致的 API 风格完成。
- 音视频
- 视频处理
- 图形学
- 桌面应用
【免费下载链接】Natron
Open-source video compositing software. Node-graph based. Similar in functionalities to Adobe After Effects and Nuke by The Foundry.
相关推荐
Natron Python 脚本开发:Group 抽象基类与节点图遍历(getChildren / getNode)完全指南
Natron Python 脚本开发:Group 抽象基类与节点图遍历(getChildren / getNode)完全指南 导读 Group 是 Natron
音视频视频处理图形学桌面应用Natron 引擎中的 BezierCurve:用 Python 脚本化控制 Roto 形状的完整指南
Natron 引擎中的 BezierCurve:用 Python 脚本化控制 Roto 形状的完整指南 导读 BezierCurve 是 Natron 引擎(N
音视频视频处理图形学桌面应用Natron 的 App 对象:Python 脚本 API 中的项目实例核心
Natron 的 App 对象:Python 脚本 API 中的项目实例核心 App 是 Natron Python API( NatronEngine 模块)
音视频视频处理图形学桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考