Hi everyone,
I have a sequence in 3D Slicer that reproduces the movement of some 3D models by modifying their associated transforms. The sequence was originally recorded using a tracking system that navigated 4 different tools (so I have 4 transforms).
Whenever I click the Play button, the transforms change based on the recorded pattern.
I would like to play the sequence and export the successive transforms to an external file, such as a CSV file. The ultimate goal is to have a file that contains all the positions and rotations associated with the transform matrices over time.
I would like to obtain this to replicate the animation in another software that doesn’t support “seq” files (such as Unity).
Could anybody provide me with a Python code to extract and save this information?
Thank you very much in advance for your assistance.
Operating system: Windows 11
Slicer version: 5.2.2
I don’t think you can do this without some programming either in Slicer or in Unity. The transform sequences are saved in mrml with your scene, so it should be straightforward to parse the XML either in C# or some other language to put them in a form for your Unity program. You’ll need to reverse engineer the mrml format but that shouldn’t be too hard.
Hello Steve,
Thank you for your prompt response.
I was thinking of a piece of Python code that plays the sequence frame by frame in a loop and extracts the transform matrix information at each point using something like transformNode.GetTransformToParentInfo().
While I am able to start the sequence with sequenceNode.PlaybackActiveOn() and stop it with sequenceNode.PlaybackActiveOff(), I am unsure if there is a way to skip to the next frame with Python commands (similar to pressing ctrl+shift+right on my keyboard).
Thank you again for your assistance.
I’m not sure if CSV files would be much easier to parse than seq.nrrd files (both are just simple text files) and introducing yet another file custom format would be a significant overhead in the long-term. Text files are also really slow to read when we record a few sensors for a few ten minutes at dozens of frames per second.
Are you aware of a standard file format for storing transform sequences? (When we looked 10 years ago we did not find one, that’s why we used custom fields in image sequence files - but things might have changed since then.)
If there are commonly used standard file formats for transform sequences then we can add reader/writer for those in Slicer.
Thank you, Steve and Andras.
The piece of code provided by Steve is exactly what I wanted.
Just in case anybody is interested in the final code, it is something like:
Code:
# Iterate over the sequence frames
for offsetIndex in range(int(numberOfImages / stepSize)):
sequenceNode.SetSelectedItemNumber(int(sequenceStartIndex + offsetIndex * stepSize)) # Set sequence frame
transform = transformNode.GetTransformToParentInfo() # Get the transform at this pint
listOfTransforms.append([transform.split("\n")[1], transform.split("\n")[2], transform.split("\n")[3], transform.split("\n")[4]]) # Append each row of the transform matrix
# Open the CSV file for writing
with open(myPath, 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile) # Create a CSV writer object
for i in range(len(listOfTransforms)):
csvwriter.writerow([listOfTimestamps[i], listOfTransforms[i]])
The CSV file contains as many rows as analyzed frames (numberOfImages/stepSize). Each row is something like:
[’ -0.257538 -0.966068 -0.0162887 384.981’, ’ 0.660495 -0.163762 -0.732819 -37.6163’, ’ 0.705438 -0.199489 0.680316 -221.679’, ’ 0 0 0 1’]
Where ’ -0.257538 -0.966068 -0.0162887 384.981’ is the first row of the transform matrix and so on.
This is an interesting idea. It is a quote widely use standard, if it’s very efficient, and can store animations.
However, it is an export format for 3D rendering and fully optimized for that purpose and it is hard to use it for anything else. For example, extending with custom metadata in a standard way (e.g., so that the extra data survives when it is read into some software and saves from there) is not practically possible. For example, we may be able to read transform sequence into Blender but if we store the transform status in some custom way (or associated image data, etc) then Blender just discards all that data.
Probably all we could use from glTF is some high-level concepts and low-level glTF reader/writer libraries.