Unleashing Motion Magic: Python-Powered BVH Parsing

Unleashing the Power of Motion Capture Data with Python: A Beginner’s Guide to Parsing BVH Files

Riddhi Kumari Singh
5 min readApr 29, 2023

--

Have you ever had to work with motion capture data in BVH format, and found it difficult to extract the relevant information? If so, you’re not alone. Fortunately, with a little bit of Python, you can easily parse BVH files and extract the bone names and motion data.

In this blog post, we’ll walk through a Python script that reads an input file in BVH format, extracts the bone names and frame count, parses the data for each bone, and writes the data to a CSV file. We’ll explain each step of the code in detail, and provide tips for optimizing the execution.

This script is useful for anyone working with motion capture data, whether you’re an animator, game developer, or data analyst. With this script, you can quickly extract the data you need and use it for your own projects or analysis.

BVH stands for Biovision Hierarchy, which is a file format used for motion capture data. It was developed by Biovision, a motion capture technology company, and is widely used in the animation, gaming, and scientific research industries to capture and analyze human and animal movements. BVH files contain a hierarchical structure of joints and bones that represent the movement of a subject, along with positional and rotational data for each joint at each frame of the motion capture. This data can be used to animate digital characters or study the movements of living beings in various contexts.

Let’s Dive In

Step 1: Import Modules

The os module provides a way to work with file paths and system-specific functionality.

import os

Step 2: Initialize Variables

These variables are used to store the bone names and frame count from the input file.

bone_name = []
frame_count = 0

Step 3: Parse Input File

filename = "path_of_your_bvh_file"

with open(filename, "r") as f:
words = f.read().split()

add_next = False

for word in words:
if add_next:
bone_name += [f"{word}{suffix}" for suffix in ("Xpos", "Ypos", "Zpos", "Yrot", "Xrot", "Zrot")]
add_next = False
if word in ("ROOT", "JOINT"):
add_next = True
if word == "Frames:":
frame_count = int(words[words.index(word) + 1])
if word == "Time:":
words = words[words.index(word) + 2:]
break

This code reads the input file, splits it into a list of words, and iterates over the words to extract the bone names and frame count.

The add_next flag is used to indicate whether the next word should be added to the current bone name. When the code encounters a "ROOT" or "JOINT" keyword, it sets the flag to True. When the flag is True, it adds the current word with various suffixes to the bone_name list.

When the code encounters a “Frames:” keyword, it sets the frame_count variable to the number of frames specified in the input file.

When the code encounters a “Time:” keyword, it removes the unnecessary words from the words list and breaks out of the loop.

Step 4: Initialize Data List

data = [[] for _ in range(len(bone_name))]
size = len(bone_name)

This code initializes the data list with empty lists for each bone name, and sets the size variable to the number of bone names.

Step 5: Parse Data

for count, word in enumerate(words):
data[count % size].append(word)

This code iterates over the remaining words in the words list and adds each word to the data list for the corresponding bone name. The % operator is used to cycle through the bone names in a circular fashion.

Step 6: Write Output File

output_file = os.path.splitext(filename)[0] + ".csv"

with open(output_file, "w") as f:
f.write(f"Frames,{','.join(str(i) for i in range(1, frame_count + 1))}\n")

for name, values in zip(bone_name, data):
f.write(f"{name},{','.join(values)}\n")

This code generates the output file name based on the input file name, and opens the output file for writing. It writes the header row with the frame numbers, and then iterates over the bone names and their corresponding data lists and writes them to the file.

Step 6: Test the Work

To test the code from the above blog, you can follow these steps:

  1. Save the code to a file named bvh_parser.py.
  2. Download a sample BVH file, such as the one available at https://research.cs.wisc.edu/graphics/Courses/cs-838-1999/Jeff/BVH.html, and save it to your working directory as sample.bvh.
  3. Open bvh_parser.py in a text editor and replace "path_of_your_bvh_file" with "sample.bvh".
  4. Open a command prompt window in the same directory as bvh_parser.py and sample.bvh.
  5. Run the command python bvh_parser.py.
  6. If the script runs without errors, you should see a new CSV file called sample.csv in your working directory.

Conclusion

In conclusion, parsing BVH files using Python can greatly simplify the process of extracting bone names and motion data from motion capture data. The code we covered in this blog post demonstrates a simple yet effective way to parse BVH files and write the extracted data to a CSV file. With this script, animators, game developers, and data analysts can easily extract and analyze motion data for their own projects.

Although the code we discussed here is relatively simple, it can be a great starting point for more complex BVH parsing projects. By understanding the basics of how BVH files are structured and how to extract data from them, you can easily customize this script to fit your specific needs.

Overall, Python provides a powerful and flexible environment for working with motion capture data, and the code we’ve covered here is just one example of how it can be used. With a little bit of Python and some creativity, the possibilities for analyzing and visualizing motion capture data are endless.

github Link: https://github.com/wittygirl8/BVH-Parsing

Read my other articles:

--

--