> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.stereolabs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.stereolabs.com/_mcp/server.

# Tutorial - Using Human Body Tracking

This tutorial shows how to enable the Body Tracking module to detect and track 3D human body skeletons, with a confidence threshold you can tune for the scene (lower for outdoor/long-range use, higher for indoor/close-range use to avoid false positives). This module requires a stereo camera with an integrated IMU (ZED 2/2i, ZED Mini, or ZED X family); the original ZED is **not** supported.

## Getting Started

* First, download the latest version of the [ZED SDK](https://www.stereolabs.com/developers/).
* Download the [Body Tracking](https://github.com/stereolabs/zed-sdk/tree/master/tutorials/tutorial%208%20-%20body%20tracking) sample code in C, C++, Python or C#.

## Code Overview

### Open the camera

In this tutorial, we will use the Body Tracking AI module of the ZED SDK.
As in previous tutorials, we create, configure and open the camera.

**`C++`**

```cpp C++
// Create ZED objects
Camera zed;
InitParameters initParameters;
initParameters.camera_resolution = RESOLUTION::HD720;
initParameters.depth_mode = DEPTH_MODE::NEURAL;

// Open the camera
ERROR_CODE zed_error = zed.open(initParameters);
if (zed_error != ERROR_CODE::SUCCESS) {
	std::cout << "Error " << zed_error << ", exit program.\n";
	return 1; // Quit if an error occurred
}
```

**`Python`**

```python Python
# Create ZED objects
zed = sl.Camera()
init_params = sl.InitParameters()
init_params.camera_resolution = sl.RESOLUTION.HD720
init_params.depth_mode = sl.DEPTH_MODE.NEURAL

# Open the camera
err = zed.open(init_params)
if err != sl.ERROR_CODE.SUCCESS:
    # Quit if an error occurred
    exit()
```

**`C#`**

```csharp C#
// Create a ZED camera object
Camera zed = new Camera(0);
// Set configuration parameters
InitParameters init_params = new InitParameters();
init_params.resolution = RESOLUTION.HD720; 
init_params.depthMode = DEPTH_MODE.NEURAL;

// Open the camera
ERROR_CODE err = zed.Open(ref init_params);
if (err != ERROR_CODE.SUCCESS)
    Environment.Exit(-1);
```

### Enable Body Tracking

Before enabling body tracking, we specify the `BodyTrackingParameters` of the module.

> **Note**
>
> Body tracking needs positional tracking to be able to track the bodies in the world reference frame.

**`C++`**

```cpp C++
// Define the Body Tracking module parameters
BodyTrackingParameters detection_parameters;
// Different models can be chosen, optimizing the runtime or the accuracy
detection_parameters.detection_model = BODY_TRACKING_MODEL::HUMAN_BODY_FAST;
// Enable tracking to detect bodies across time and space
detection_parameters.enable_tracking = true;
// Optimize the person joints position, requires more computations
detection_parameters.enable_body_fitting = true;

// If you want to track bodies you need to enable positional tracking first
if (detection_parameters.enable_tracking)
    zed.enablePositionalTracking();
```

**`Python`**

```python Python
# Define the Body Tracking module parameters
body_param = sl.BodyTrackingParameters()
# Different model can be chosen, optimizing the runtime or the accuracy
body_param.detection_model = sl.BODY_TRACKING_MODEL.HUMAN_BODY_FAST
# Enable tracking to detect bodies across time and space
body_param.enable_tracking = True
# Optimize the person joints position, requires more computations
body_param.enable_body_fitting = True

# If you want to track bodies you need to enable positional tracking first
if body_param.enable_tracking:
    positional_tracking_param = sl.PositionalTrackingParameters()
    zed.enable_positional_tracking(positional_tracking_param)
```

**`C#`**

```csharp C#
// Define the Body Tracking module parameters
BodyTrackingParameters bodyTrackingParameters = new BodyTrackingParameters();
// Different models can be chosen, optimizing the runtime or the accuracy
bodyTrackingParameters.detectionModel = sl.BODY_TRACKING_MODEL.HUMAN_BODY_FAST;
// Enable tracking to detect bodies across time and space
bodyTrackingParameters.enableObjectTracking = true;

// Body tracking requires the positional tracking module
// Enable positional tracking
PositionalTrackingParameters trackingParams = new PositionalTrackingParameters();
// If you want to track bodies you need to enable positional tracking first
err = zed.EnablePositionalTracking(ref trackingParams);
```

Then we can start the module, which loads the AI model. This operation can take a few seconds. The first time the module is used, the model will be optimized for the hardware and will take more time. This operation is done only once.

**`C++`**

```cpp C++
cout << "Body Tracking: Loading Module..." << endl;
zed_error = zed.enableBodyTracking(detection_parameters);
if (zed_error != ERROR_CODE::SUCCESS) {
    cout << "Error " << zed_error << ", exit program.\n";
    zed.close();
    return EXIT_FAILURE;
}
```

**`Python`**

```python Python
print("Body Tracking: Loading Module...")
err = zed.enable_body_tracking(body_param)
if err != sl.ERROR_CODE.SUCCESS:
    print(repr(err))
    zed.close()
    exit(1)
```

**`C#`**

```csharp C#
Console.WriteLine("Body Tracking: Loading Module...");
err = zed.EnableBodyTracking(ref bodyTrackingParameters);
if (err != ERROR_CODE.SUCCESS)
    Environment.Exit(-1);
```

### Capture Data

The detection confidence threshold can be adjusted at runtime to select only the relevant skeletons depending on the scene complexity. For each `grab` call, the image is fed into the AI module, which outputs the bodies detected in that frame.

**`C++`**

```cpp C++
// Set runtime parameter confidence to 40
BodyTrackingRuntimeParameters body_parameters_rt;
body_parameters_rt.detection_confidence_threshold = 40;

Bodies bodies;

// Grab new frames and detect bodies
while (zed.grab() == ERROR_CODE::SUCCESS) {
	zed.retrieveBodies(bodies, body_parameters_rt);
	if (bodies.is_new) {
		// Count the number of bodies detected
		cout << bodies.body_list.size() << " Person(s) detected\n";
		if (!bodies.body_list.empty()) {
			auto first_body = bodies.body_list.front();
			// Display the 3D keypoint coordinates of the first detected person    
			cout << " Keypoints 3D \n";
			for (int i = 0; i < first_body.keypoint.size(); i++) {
				auto &kp = first_body.keypoint[i];
				cout << "    " << kp.x << ", " << kp.y << ", " << kp.z << "\n";
			}
		}
	}
}
```

**`Python`**

```python Python
# Set runtime parameter confidence to 40
body_runtime_param = sl.BodyTrackingRuntimeParameters()
body_runtime_param.detection_confidence_threshold = 40

bodies = sl.Bodies()

# Grab new frames and detect bodies
while zed.grab() == sl.ERROR_CODE.SUCCESS:
    err = zed.retrieve_bodies(bodies, body_runtime_param)

    if bodies.is_new:
        # Count the number of bodies detected
        body_array = bodies.body_list
        print(str(len(body_array)) + " Person(s) detected\n")

        if len(body_array) > 0:
            first_body = bodies.body_list[0]
            # Display the 3D keypoint coordinates of the first detected person
            print("\n Keypoint 3D ")
            keypoint = first_body.keypoint
            for it in keypoint:
                print("    " + str(it))
```

**`C#`**

```csharp C#
// Set runtime parameter confidence to 40
BodyTrackingRuntimeParameters bt_runtime_parameters = new BodyTrackingRuntimeParameters();
bt_runtime_parameters.detectionConfidenceThreshold = 40;

Bodies bodies = new Bodies();

// Grab new frames and detect bodies
RuntimeParameters runtimeParameters = new RuntimeParameters();
while (zed.Grab(ref runtimeParameters) == ERROR_CODE.SUCCESS) {
	err = zed.RetrieveBodies(ref bodies, ref bt_runtime_parameters);

	if (bodies.isNew != 0) {
		// Count the number of bodies detected
		Console.WriteLine(bodies.bodiesList.Length + " Person(s) detected");
		if (bodies.bodiesList.Length > 0)
		{
			BodyData firstBody = bodies.bodiesList[0];
			// Display the 3D keypoint coordinates of the first detected person
			Console.WriteLine(" Keypoints 3D ");
			for (int i = 0; i < firstBody.keypoints.Length; i++)
			{
				var kp = firstBody.keypoints[i];
				Console.WriteLine(" " + kp.X + ", " + kp.Y + ", " + kp.Z);
			}
		}
	}
}
```

### Disable modules and exit

Once the program is over, the modules can be disabled and the camera closed. This step is optional since the `zed.close()` will take care of disabling all the modules. This function is also called automatically by the destructor if necessary.

**`C++`**

```cpp C++
// Disable body tracking and close the camera
zed.disableBodyTracking();
zed.close();
```

**`Python`**

```python Python
# Disable body tracking and close the camera
zed.disable_body_tracking()
zed.close()
```

**`C#`**

```csharp C#
// Disable body tracking and close the camera
zed.DisableBodyTracking();
zed.Close();
```

And this is it!