首先NDK文档中的Op.h头文件中已经有了相关概念的解释,摘录翻译如下:

      /*! \fn const OutputContext& Op::outputContext() const;
The current context that this Op is supposed to produce a picture
for. This includes the frame number, the view, etc.
*/
const OutputContext& outputContext() const { return outputContext_; }

即当前Op进行图像处理的一个实时环境,这个环境包括了帧数,视角(包括main视角,left视角,right视角,等)。

Op会对当前帧的画面进行处理,通过_validate()方法去确认图像相关信息,通过Knobs机制去读取工程文件中的属性参数并存储到knobs中,通过_requenst()去逐行请求图像信息,继而通过engine()方法综合现有数据进行图像处理。这是Op的一个简单的机制,一个Op实例只能处理一幅画面。那么Op该处理哪一帧图像呢?处理这一帧图像的哪一个视角呢(exr图像的header表中会记录视角信息)?这一切都由OutputContext机制决定。该机制会更早于Op属性实例化。OutputContext()机制启动后确定处理环境后才会实例化Op来进行下一步工作。

下面分析几个案例来解释这个机制:

默认的split_input()和OutputContext()方法是这样的:

virtual int split_input(int inputNo) const
{
return 1;
} virtual const OutputContext& inputContext(int n, int offset, OutputContext& oc) const
{
return outputContext();
}

一:

如果你希望input arrow在时间轴上的任何帧上都只进入第一帧(例如FrameHold),那么你需要这样重定义:

virtual const OutputContext& inputContext(int n, int offset, OutputContext& oc) const {
oc = outputContext();
oc.frame(1);
return oc;
}

第二行表示oc指向当前已经存在outputContext(),inputContext()方法中这样指认实际上表示inputContext()与outputContext()一致,即:输入哪一帧,处理哪一帧。第三行显式的为oc赋值1,表示无论何时只输入第一帧。第四行返回修改后的oc对象。

通过这种方式即可实现framehold的效果,无论时间轴怎样拖动,只显示指定的某一帧。

二:

如果你有一个Op想使用两个以上的输入帧来进行操作(比如FrameBlend),那你就需要重新定义split_input()。

virtual int split_input(int inputNo) const
{
if (inputNo == 0)
return 2;
return 1;
} virtual const OutputContext& inputContext(int n, int offset, OutputContext& oc) const
{
oc = outputContext();
if (inputNo == 0 && offset == 1)
oc.frame(oc.frame() + 1);
return oc;
}

第一个方法表示将第一个input arrow分出两个子input,每个input对应一个独立Op;第二个方法表示在第二个子input上输入下一帧的内容。即input(0,1)对应的Op处理input(0,0)应对Op处理帧的下一帧。这样就是在input(0)上同时处理生成两个Op来进行串帧处理了。inputContext(int n,int offset,OutputContext&oc)中n代表当前帧,offset代表当前input下的子input,oc表示当前outputContext()对象。

三:

virtual int split_input(int inputNo) const
{
return 11;
} virtual const OutputContext& inputContext(int n, int offset, OutputContext& oc) const
{
oc = outputContext();
oc.frame(oc.frame() - 5 + offset);
return oc;
}

在这个案例中通过split_input()方法为每个input定义了11个子inputs,目的是为每一个input都生成11个op,在每一帧都调用附近的11帧来生成图像。之后又定义了inputContext()方法,该方法继承了outputContext()方法,之后将当前帧向前偏移5帧,以oc.frame()-5为基准来添加offset,offset范围为0-10,这样就会生成oc.frame()-5到oc.frame()+5这个范围的input。每一帧的计算都会调用这个范围的input数据。通过这种结构,engine机制能够很容易的生成多帧混合图像。

但是这个机制有个缺陷,我们的原素材范围framerange假设为[1-100],经过这个机制之后framerange就变成[-4,105]了,这样会造成不必要的读写,于是nuke引入一个新的机制inputUIcontext().该机制同样继承自outputContext(),目的是在修复inputContext产生的帧数范围错误。我们只需要重新定义一下该函数即可:

virtual const OutputContext* inputUIContext(int n, OutputContext&) const
{
return &outputContext();
}

这样就可以将错误的范围重新指认回原来的应该的帧数范围了。

通过这OutputContext机制的这三个方法可以很轻松的解决时间线上多帧操作的问题,nuke的程序思路非常明确:

一个input对应一个op,多帧运算就实例化多个op,在engine方法中构建对应于多个input的row即可。

例如:

void TemporalMedian::engine ( int y, int x, int r,
ChannelMask channels, Row& row )
{
row.get(input0(), y, x, r, channels);
Row prevrow(x, r);
Row nextrow(x, r);
prevrow.get(input1(), y, x, r, channels);
nextrow.get(*input(2), y, x, r, channels);

该例子中就实例化了三个input,即:input0(),input1(),*input(2),每一个input的读写row实例即:row,preview,nextrow。

总结一下:

学习到这里Nuke的读写运算机制就很清晰了,剩下的就是算法移植了。希望自己的数学底子不要拖后腿。勤能补拙,再接再厉。

NDK学习笔记(四):OutputContext机制的更多相关文章

  1. NDK学习笔记(五)Reader机制

    针对每一种后缀名Nuke都提供了对应的模块.为了决定用哪个版本的reader或writer模块,Nuke会先解析文件后缀名再以此为依据调用相关模块. 以JPG为例: 该文件格式有两种后缀名:.jpg和 ...

  2. muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制

    目录 muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制 eventfd的使用 eventfd系统函数 使用示例 EventLoop对eventfd的封装 工作时序 runInLoo ...

  3. java学习笔记09--反射机制

    java学习笔记09--反射机制 什么是反射: 反射是java语言的一个特性,它允许程序在运行时来进行自我检查并且对内部的成员进行操作.例如它允许一个java的类获取他所有的成员变量和方法并且显示出来 ...

  4. 零拷贝详解 Java NIO学习笔记四(零拷贝详解)

    转 https://blog.csdn.net/u013096088/article/details/79122671 Java NIO学习笔记四(零拷贝详解) 2018年01月21日 20:20:5 ...

  5. MySql学习笔记四

    MySql学习笔记四 5.3.数据类型 数值型 整型 小数 定点数 浮点数 字符型 较短的文本:char, varchar 较长的文本:text, blob(较长的二进制数据) 日期型 原则:所选择类 ...

  6. ZooKeeper学习笔记四:使用ZooKeeper实现一个简单的分布式锁

    作者:Grey 原文地址: ZooKeeper学习笔记四:使用ZooKeeper实现一个简单的分布式锁 前置知识 完成ZooKeeper集群搭建以及熟悉ZooKeeperAPI基本使用 需求 当多个进 ...

  7. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  8. IOS学习笔记(四)之UITextField和UITextView控件学习

    IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...

  9. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

  10. Learning ROS for Robotics Programming Second Edition学习笔记(四) indigo devices

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

随机推荐

  1. 如何利用Power BI 制作动态搜索界面

    最近Power BI有了最新更新,想着利用 Power BI 工具制造一个动态的搜索界面,比如动态切换搜索引擎,分别从百度.360.搜狗等搜索苹果最新新闻.通过一番测试,最终实现了相关功能. 数据加载 ...

  2. 一些Go操作Kafka的问题

    1)包的选择 confluent-kafka-go使用了rdkafka的c库,破坏了go代码的收敛,不使用: sarama不支持groud id 的功能,写consumer需要自己管理消费的parti ...

  3. MySQL(1) 基本操作(MySQL的启动,表的创建,查询表的结构和表的字段的修改)

    MySQL启动流程 1 启动服务器 2 用户名登录到MySQL数据库中 3  查看有哪些数据库 4 使用其中的数据库 5 查看该数据库中已有哪些表,没有就新建 mysql> CREATE TAB ...

  4. 【Java】将字节转换成十六进制、BCD码输出

    public class HexUtils { public static void main(String[] args) { byte []out = { 0, 1, 2, 3, 4, 5, 6, ...

  5. 怎样用CMD命令强行删除文件?

    如果你要删除的整个文件夹以及文件夹里面的所有内容的话rd/s/q 盘符:\某个文件夹   (这样整个文件夹所有的文件和文件夹都删除了)比如我想删除D盘的123文件夹以及123文件夹里面所有的内容rd/ ...

  6. this和super用法详解

    这几天看到类在继承时会用到this和super,这里就做了一点总结,与各位共同交流,有错误请各位指正~ this this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针. this ...

  7. MAC使用pycharm上传代码到Github上

    本人的电脑已经在GitHub中添加成功了SSH keys! 以下为在pycharm中上传代码到Github的步骤. Step1:打开pycharm,preferences---plugins(插件)选 ...

  8. 矩阵快速幂(以HDU1757为例)

    对于数据量大的求余运算,在有递推式的情况下,可以构造矩阵求解. A - A Simple Math Problem Lele now is thinking about a simple functi ...

  9. Python学习-终端字体高亮显示1

    Python学习-终端字体高亮显示   1.采用原生转义字符序列,对Windows有的版本不支持(比如win7),完美支持Linux 实现过程: 终端的字符颜色是用转义序列控制的,是文本模式下的系统显 ...

  10. 可变,不可变类型和hash

    可变与不可变类型 截止到目前为止我们已经学过很多数据类型:数字类型.字符串类型.列表类型.元祖类型. 在python中,我们对数据类型还有另外一种分类方式,我们给数据类型分为可变数据类型和不可变数据类 ...