MitchellKehn
12/1/2019 - 5:15 AM

Exporter for nuke 2D tracks into PFTrack-importable format. Exporter not quite working, but has some attribute access stuff that could prove

[nuke track exporter] Exporter for nuke 2D tracks into PFTrack-importable format. Exporter not quite working, but has some attribute access stuff that could prove useful #nuke #pftrack

"""
Export a nuke tracker node to an ACII file that can be read by PFTrack
"""
from math import sqrt

HEADER = """\
# "Name"
# clipNumber
# frameCount
# frame, xpos, ypos, similarity
"""

ATTRS = [
    "e", "name", "track_x", "track_y", "offset_x", "offset_y", "T", "R", "S",
    "error", "error_min", "error_max",
    "pattern_x", "pattern_y", "pattern_r", "pattern_t",
    "search_x", "search_y", "search_r", "search_t",
    "key_track", "key_search_x", "key_search_y", "key_search_r", "key_search_t",
    "key_track_x", "key_track_y", "key_track_r", "key_track_t",
    "key_centre_offset_x", "key_centre_offset_y"
]
COL_COUNT = 31

RESIZE = 1520.0 / 4448.0


def attrIndex(attribute, row):
    """
    Get the index of an attribute of the Tracker node
    @param attribute: the name of the attribute
    @param row: the row of the table you're accessing
    """
    col = ATTRS.index(attribute)
    return row * COL_COUNT + col

def trackCount(tracker):
    """@return the number of trackers on the selected node"""
    tracks = 0
    while node.knob('tracks').isAnimated(31 * tracks + 2):
        tracks += 1
    return tracks

def trackRange(tracker, row, first, last):
    """@return: frame range where there are keyframes for the given row. None, None if there are none"""
    tracks = tracker["tracks"]

    # work out first frame by stepping forwards
    firstKey = first
    while firstKey < last:
        if tracks.isKeyAt(firstKey, attrIndex("track_x", row)) or \
            tracks.isKeyAt(firstKey, attrIndex("track_y", row)):
            break
        firstKey += 1
    else:
        return None, None

    # work out last frame by stepping backwards
    lastKey = last
    while lastKey > first:
        if tracks.isKeyAt(lastKey, attrIndex("track_x", row)) or \
            tracks.isKeyAt(lastKey, attrIndex("track_y", row)):
            break
        lastKey -= 1

    return firstKey, lastKey

def getTrackNames(tracker4Node):
    k = tracker4Node['tracks']
    s = tracker4Node['tracks'].toScript().split(' \n} \n{ \n ')
    s.pop(0)
    ss = str(s)[2:].split('\\n')
    if ss:
        ss.pop(-1)
    if ss:
        ss.pop(-1)
    outList = []
    for i in ss:
        outList.append(i.split('"')[1])
    return outList


def exportTracker(tracker):
    frange, views = nuke.getFramesAndViews("frame range", "{}-{}".format(nuke.root().firstFrame(), nuke.root().lastFrame()))
    frange = frange.split("-")
    firstFrame, lastFrame = int(frange[0]), int(frange[-1])
    tracks = tracker["tracks"]

    fp = nuke.getFilename("Path to ASCII file", "*.txt")
    with open(fp, "w") as file:
        file.write(HEADER)

        for row in range(trackCount(tracker)):
            firstKey, lastKey = trackRange(tracker, row, firstFrame, lastFrame)

            if any([firstKey == lastKey, firstKey is None, lastKey is None]):
                print "no keys in row", row
                continue  # there are no keyframes on this track

            file.write("\n")
            # print tracks.getValue(attrIndex("name", row))  # can't get strings from values key_search_t
            file.write('"NukeTrack{:04d}"\n'.format(row+1))
            file.write("1\n")
            file.write("{}\n".format(lastKey - firstKey + 1))

            for frame in range(firstKey, lastKey + 1):
                xpos = tracks.getValueAt(frame, attrIndex("track_x", row))
                ypos = tracks.getValueAt(frame, attrIndex("track_y", row))
                simi = 1 - sqrt(tracks.getValueAt(frame, attrIndex("error", row)))

                file.write("{} {} {} {}\n".format(frame, xpos * RESIZE, ypos * RESIZE, simi))

            file.write("\n")
    with open(fp, "r") as file:
        print file.read()


if __name__ == "__main__":
    node = nuke.selectedNode()
    exportTracker(node)