从Nuke的节点图中提取矢量图像或高分辨率图像

2024-05-15 11:43:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我是一名VFX教师,目前,当我想要抓取节点图的图像用于课堂幻灯片时,我必须使节点图全屏并进行屏幕捕获,但正如您可以想象的那样,对于较大的脚本,我必须缩小到有时无法识别的程度

在我看来,当你放大和缩小时,Nuke的节点图会调整大小,这可能是引擎盖下的某种向量图像。我正在寻找一种方法,要么导出此图像,这样我就可以获得整个节点图的更高分辨率版本。要么作为矢量,要么只是更高分辨率的光栅化图像

有人知道有没有一种方法可以用Python实现这一点吗?或者有一些外部脚本可以做到这一点


Tags: 方法图像脚本节点屏幕教师高分辨率幻灯片
1条回答
网友
1楼 · 发布于 2024-05-15 11:43:20

我想要这个已经有很长一段时间了,但是你的问题让我更深入地研究它

我不相信有一个真正的矢量图像可用的引擎盖下(它是openGL引擎盖下),但我也不明白为什么没有一种方法来自动化一个完整的分辨率屏幕截图

我已经写了一个脚本,将检查您的节点图的大小,设置缩放到100%,并截图DAG的每一块,然后自动缝合它。这需要几秒钟,因为如果我试图做得太快,事情会因为线程而变得混乱,所以我不得不在每个屏幕截图之间引入人工暂停

您应该能够运行下面的代码。别忘了在倒数第二行设置路径

from PySide2 import QtWidgets, QtOpenGL, QtGui
from math import ceil
import time

 
def get_dag():
    stack = QtWidgets.QApplication.topLevelWidgets()
    while stack:
        widget = stack.pop()
        if widget.objectName() == 'DAG.1':
            for c in widget.children():
                if isinstance(c, QtOpenGL.QGLWidget):
                    return c
        stack.extend(c for c in widget.children() if c.isWidgetType())

def grab_dag(dag, path):
    dag.updateGL()  # This does some funky back and forth but function grabs the wrong thing without it
    pix = dag.grabFrameBuffer()
    pix.save(path)
    
class DagCapture(threading.Thread):
    def __init__(self, path, margins=20, ignore_right=200):
        self.path = path
        threading.Thread.__init__(self)
        self.margins = margins
        self.ignore_right = ignore_right

    def run(self):
        # Store the current dag size and zoom
        original_zoom = nuke.zoom()
        original_center = nuke.center()
        # Calculate the total size of the DAG
        min_x = min([node.xpos() for node in nuke.allNodes()]) - self.margins
        min_y = min([node.ypos() for node in nuke.allNodes()]) - self.margins
        max_x = max([node.xpos() + node.screenWidth() for node in nuke.allNodes()]) + self.margins
        max_y = max([node.ypos() + node.screenHeight() for node in nuke.allNodes()]) + self.margins

        # Get the Dag Widget
        dag = get_dag()
        if not dag:
            raise RuntimeError("Couldn't get DAG widget")

        # Check the size of the current widget, excluding the right side (because of minimap)
        capture_width = dag.width() - self.ignore_right
        capture_height = dag.height()

        # Calculate the number of tiles required to coveral all
        image_width = max_x - min_x
        image_height = max_y - min_y
        horizontal_tiles = int(ceil(image_width / float(capture_width)))
        vertical_tiles = int(ceil(image_height / float(capture_height)))
        # Create a pixmap to store the results
        pixmap = QtGui.QPixmap(image_width, image_height)
        painter = QtGui.QPainter(pixmap)
        painter.setCompositionMode(painter.CompositionMode_SourceOver)
        # Move the dag so that the top left corner is in the top left corner, screenshot, paste in the pixmap, repeat
        for xtile in range(horizontal_tiles):
            left = min_x + capture_width * xtile
            for ytile in range(vertical_tiles):
                top = min_y + capture_height * ytile
                nuke.executeInMainThread(nuke.zoom, (1, (left + (capture_width + self.ignore_right) / 2, top + capture_height / 2)))
                time.sleep(.5)
                nuke.executeInMainThread(grab_dag, (dag, self.path))
                time.sleep(.5)
                screengrab = QtGui.QImage(self.path)
                painter.drawImage(capture_width * xtile, capture_height * ytile, screengrab)
        painter.end()
        pixmap.save(self.path)
        nuke.executeInMainThread(nuke.zoom, (original_zoom, original_center))
        print "Capture Complete"

t = DagCapture("C:\\Users\\erwan\\Downloads\\test.png")
t.start()

我相信这是可以改进的,但希望它能为您节省时间

编辑:我现在对这段代码做了一些改进:https://github.com/herronelou/nuke_dag_capture

相关问题 更多 >