【NUKE教程】Nuke Python 获取图像数据

10 九月, 2016
12
0

nukepyimg
通过python有两种方式读取图像的像素数据:

  • 创建分析图像的节点(比如,MinColor, CurveTool),执行,然后读取其结果的knob数值
  • sample方法可以直接抽样节点的像素。

使用CurveTool

创建CurveTool节点,执行后删除,并显示其分析结果:

noise = nuke.createNode('Noise')
noise['zoffset'].setExpression( 'frame*100 ' )
ct = nuke.createNode('CurveTool')
nuke.execute( ct, nuke.frame(), nuke.frame() )
dat = ct['intensitydata'].value()
nuke.delete(ct)
nuke.message( 'average luminance is %s' % dat )

使用sample方法

创建Noise节点,在x=500,y=600抽样红色通道,并输出:

noise = nuke.createNode('Noise')
print noise.sample('red', 500, 600)

下面代码结果一样:

	
print nuke.sample(noise, 'red', 500, 600)

例子

getMinMax

此工具可以抽取通道中的最大最小值。最近nuke的python api中没有现成的方法,一般利用MinColor的功能来实现。因此工作流中创建一
些临时节点,在当前帧上执行(为我们计算),然后删除。

刚开始,先创建一个测试方案:创建Ramp节点,将Grade节点挂到上面。确保Grade的black clamp knob禁止,然后可以用任意值来测试lift和gain knob。
Nuke Python 获取图像数据

创建MinColor节点,挂到Grade节点,MinColor的channels knob设置成默认rgba就行,调整其他knob。当目标knob被设置为0时,在当前
帧执行。输入节点的rgba层的delta knob保存了最小值。delta knob的值和你在Grade节点的lift knob的值很接近,但为负的。
Nuke Python 获取图像数据

想获取最大值,那么反转图像先,使用MinColor节点再走一边上面的流程。
Nuke Python 获取图像数据

反转图像意味着像素值从1到1-x,需要给delta knob加上1才能获得原始图像的最大值(方法很多)
现在知道怎么获取最大最小值。删除MinColor,反转节点,写一段脚本来干此事。
先从DAG图中抓取Grade1节点,然后添加MinColor节点,其target knob通过python设置为0:

srcNode = nuke.toNode('Grade1')
nuke.nodes.MinColor( target=0 )

其toNode()可以直接获取DAG中的节点。nuke.nodes可以替代nuke.createNode()方法。不同之处在于createNode()和从菜单创建是一样
的。这意味着:

  • 将选择的焦点切换到新节点
  • 尝试链接新节点
  • 自动给新节点定位
  • 挂起当前视图缓冲区
  • 打开默认panel控制面板

nuke.nodes就不是手工操作了,创建节点后,啥也不改变。我们要创建临时节点,后面还要删除,这样用户的节点图就不会因为临时节点
改变。麻烦就是需要手工链接新节点:

srcNode = nuke.toNode('Grade1')
nuke.nodes.MinColor( target=0, inputs=[srcNode])

inputs参数接收一个列表,因为会有多输入。这样,可以一次将其全部链接。
现在需要赋一个参数来定义不需要分析的通道,同时我们不想限制到rgba上。将新节点赋值给变量,随后可以在代码中使用:

srcNode = nuke.toNode('Grade1')
channel = 'rgba.red'
MinColor = nuke.nodes.Mincolor( channels=channel, target=0, inputs=[srcNode])

上面的代码仅分析red通道。
现在创建新MinColor,并反转图像,确保链接对应的输入,并在对应的通道上工作(或许想删除前面的临时节点):

srcNode = nuke.toNode('Grade1')
channel = 'rgba.red'
MinColor = nuke.nodes.MinColor( channels = channel, target=0, inputs=[srcNode] )
Inv = nuke.nodes.Invert( channels = channel, inputs=[srcNode])
MaxColor = nuke.nodes.MinColor( channels = channel, target=0, inputs[Inv] )

结果如下:
Nuke Python 获取图像数据

现在,节点树已有,执行MinColor节点来获取我们所需。nuke.execute()来办事:

curFrame = nuke.frame()
nuke.execute( MinColor, curFrame, curFrame)

可以看到,需要给节点提供起始帧作为参数,可以用FrameRanges对象替代。在pixeldelta knob中可以找到最小颜色。记得取反才是正确值。

	
minV = -MinColor['pixeldelta'].value()

现在第二个MinColor干一样的事情,连接到Invert节点(我们存在了MaxColor里面),记得给结果加上1来取得真正的最大值:

nuke.execute(MaxColor, curFrame, curFrame)
maxV = MaxColor['pixeldelta'].value() + 1

现在是清理时间,让我们删除这些节点:

for n in ( MinColor, MaxColor, Inv ):
    nuke.delete(n)

完成代码如下:

srcNode = nuke.toNode(' Grade1')
channel = 'rgba.red'
MinColor = nuke.nodes.MinColor( channels=channel, target=0, inputs=[srcNode] )
Inv = nuke.nodes.Invert( channels = channel, inputs= [srcNode])
MaxColor = nuke.nodes.MinColor( channels =channel, target=0, inputs=[Inv] )
curFrame = nuke.frame()
nuke.execute( MinColor, curFrame, curFrame)
minV = -MinColor['pixeldelta'].value()
nuke.execute( MaxColor, curFrame, curFrame)
maxV = MaxColor['pixeldelta'].value + 1
for n in ( MinColor, MaxColor, Inv):
    nuke.delete(n)

将代码封装成函数,参数为node和channel,默认分析深度通道:

import nuke
def getMinMax( srcNode, channel='depth.Z' ):
    '''
    Return the min and max values of a given node's image as a tuple
    args:
       srcNode  - node to analyse
       channels  - channels to analyse. This can either be a channel or layer name
    '''
    MinColor = nuke.nodes.MinColor( channels=channel, target=0, inputs=[srcNode] )
    Inv = nuke.nodes.Invert( channels=channel, inputs=[srcNode])
    MaxColor = nuke.nodes.MinColor( channels=channel, target=0, inputs=[Inv] )
    curFrame = nuke.frame()
    nuke.execute( MinColor, curFrame, curFrame )
    minV = -MinColor['pixeldelta'].value()
    nuke.execute( MaxColor, curFrame, curFrame )
    maxV = MaxColor['pixeldelta'].value() + 1
    for n in ( MinColor, MaxColor, Inv ):
        nuke.delete( n )
    return minV, maxV

将次模块放到插件路径下,用black 和white点创建Grade节点,并设置为深度通道的最大最小值,其会自动归一化:

minV, maxV = getMinMax(nuke.selectedNode())
grade =nuke.createNode('Grade')
grade['blackpoint'].setValue(minV)
grade['whitepoint'].setValue(maxV)

更加简洁的做法:

nuke.createNode('Grade', 'channels depth.Z blackpoint %s whitepoint %s' % examples.getMinMax(nuke.selectedNode()))
使用Sample

下面是一个LUT的例子:

import nuke
def getLUT( size=1024 ):
    '''
    Get the current viewer process node and generate a simple lut from it
    args:
       size  -  size of resulting lut (default=1024)
    '''
    vpNode = nuke.ViewerProcess.node()
    vp = eval( 'nuke.nodes.%s()' % vpNode.Class() )
    _copyKnobsFromScriptToScript( vpNode, vp )
    ramp = nuke.nodes.Ramp()
    ramp['p0'].setValue( (0, 0) )
    ramp['p1'].setValue( (size, 0) )
    vp.setInput(0, ramp )
    saturation = nuke.nodes.Saturation( saturation = 0 )
    saturation.setInput(0, vp )
    lut = [ saturation.sample("rgba.red", i+.5, 0.5) for i in xrange( 0, size )]
    nuke.delete( saturation )
    nuke.delete( ramp )
    nuke.delete( vp )
    return lut
def createLutNode( lut ):
    '''
    Create a ColorLookup node to hold lut. The values are normalised.
    args:
        lut  -  list of floating point numbers
    '''
    lutNode = nuke.createNode( 'ColorLookup' )
    lutKnob = lutNode['lut']
    for i, y in enumerate( lut ):
        x = float(i) / len(lut)
        lutKnob.setValueAt( y, x )
def _copyKnobsFromScriptToScript( srcNode, trgNode):
    '''
    Copy knobs between nodes.
    This function can also be found in the default menu.py
    args:
       srcNode  -  node to copy values from
       trgNode  -  node to copy values to
    '''
    srcKnobs = srcNode.knobs()
    trgKnobs = trgNode.knobs()
    excludedKnobs = ["name", "xpos", "ypos"]
    intersection = dict([ (item, srcKnobs[ item ]) for item in srcKnobs.keys() if item not in excludedKnobs and trgKnobs.has_key( item ) ])
    for k in intersection.keys():
                trgNode[ k ].fromScript( srcNode[ k ].toScript() )