Serializing Tracking Data

The Frame class provides methods for serializing the data in a frame as a sequence of bytes. You can pass this sequence of bytes to the deserializer to create a new copy of the original frame.

Serializing a Frame

To serialize a Frame instance, use Frame.serialize.

The following example serializes a frame and saves it to a file.

import ctypes

frame = controller.frame()

serialized_tuple = frame.serialize
serialized_data = serialized_tuple[0]
serialized_length = serialized_tuple[1]
data_address = serialized_data.cast().__long__()
buffer = (ctypes.c_ubyte * serialized_length).from_address(data_address)
with open(os.path.realpath('frame.data'), 'wb') as data_file:
    data_file.write(buffer)

Deserializing a Frame

Before you can deserialize Frame data, you must create a Controller object. If you want to access any Gesture data in the restored frame, you must enable the gesture using the Controller.enable_gesture() function. Accessing images stored in the frame data is not supported at this time. Deserializing data serialized by a different version of the Leap Motion SDK is not officially supported; it may work if there are no data model differences between the two versions.

To deserialize frame data:

  1. Create a Controller instance if one doesn’t already exist.
  2. Acquire the data and, if necessary, convert it into the proper data type.
  3. Create a Frame object.
  4. Call the new frame’s deserialize() function.

Note that the reconstructed data replaces the existing data in the frame. If you use an existing, valid Frame instance, its existing data is replaced; however, any child objects, like hands or fingers, remain valid as long as you maintain a separate reference to them.

The following example loads data from a file and deserializes it to create a Frame object.

When you load the data from disk, you get a Python str object. However, the deserialize() function takes a tuple containing a Leap.byte_array object, which is a simple, limited array. You can construct such a byte_array object using the length of the data and then copy the data byte-by-byte or you can use the ctypes.memmove() function. Put the byte array in the first position of the tuple and the length of the data in the second position before passing it to the deserialize() function.

import ctypes, numpy

frame = Leap.Frame()
filename = "frame.data"
with open(os.path.realpath(filename), 'rb') as data_file:
    data = data_file.read()

leap_byte_array = Leap.byte_array(len(data))
address = leap_byte_array.cast().__long__()
ctypes.memmove(address, data, len(data))

frame.deserialize((leap_byte_array, len(data)))

Saving and Loading Multiple Frames

If you wish to save several frames to the same file, you will have to devise a way to tell where one frame ends and the next begins. The size of the data can vary from frame-to-frame. The following example illustrates one way to do this, which is to store a 4 byte integer containing the size of the data immediately before the data itself.

with open("frames.data", "wb") as data_file:
    for f in range(0, 10):
        frame_to_save = controller.frame(9 - f)
        serialized_tuple = frame_to_save.serialize
        data = serialized_tuple[0]
        size = serialized_tuple[1]
        data_file.write(struct.pack("i", size))

        data_address = data.cast().__long__()
        buffer = (ctypes.c_ubyte * size).from_address(data_address)
        data_file.write(buffer)

To read the frame data from the saved file, you can then read the first 4 bytes of the file to determine how much data to read to get an entire frame. Simply repeat the process until you reach the end of the file.

with open("frames.data", "rb") as data_file:
    next_block_size = data_file.read(4)
    while next_block_size:
        size = struct.unpack('i', next_block_size)[0]
        data = data_file.read(size)
        leap_byte_array = Leap.byte_array(size)
        address = leap_byte_array.cast().__long__()
        ctypes.memmove(address, data, size)

        frame = Leap.Frame()
        frame.deserialize((leap_byte_array, size))
        next_block_size = data_file.read(4)