How to detect if people climb/jump above the floor plan? Thx

Hi,

For my application, I want to check if anyone climb/jump from the floor
I am new to Zedi. I have tried the body tracking, object detection, And I see the center point of that person.
For the floor detection, I am playing with it. I can see the green mesh floor

Right now, I can see the center point of the person and the green mesh floor. But how can I know the floor point right below that person center point? I guess if the height is longer than certain length, I consider that person is climbing or jumping.

Thx

Hi,

First, I would recommend you to set the PositionalTrackingParameters::set_floor_as_origin to true (https://www.stereolabs.com/docs/api/structsl_1_1PositionalTrackingParameters.html#abccf07b1fa02cbbaabf55858a1ec8c59), that way, all the tracking and object detection data will be relative to the floor plane position.
For example, the camera position won’t be (0,0,0) anymore but (0,0, Z) with Z the height of the camera relative to the floor (if Z is the Up axis).

One solution to detect if the person is not on the floor is to compare his position (https://www.stereolabs.com/docs/api/classsl_1_1ObjectData.html#a73ad5e3f5c238f322437399b54d8ec5e) with the half height of his bounding box.

For that, you can use sl::ObjectData::dimension.y (half of this value of course).

Therefore, assuming the Up axis is Z, you need to verify if object_data.position.z - (object_data.dimension.y / 2) > threshold. If true, then the person is above the ground.

The threshold is important because the detection data is not perfect. You may need some testing to find the correct value in your configuration.

Best,
Benjamin Vallon

Stereolabs Support

Hi,

I got the z be negative…
Person ID = 9 [ 0.54632825 -0.25366327 -2.94440794]
Person ID = 9 [ 0.53793859 -0.25392723 -2.94371223]

Based on the object detection sample,
I’ve added
positional_tracking_parameters.set_as_static = True
positional_tracking_parameters.set_floor_as_origin = True

And then print out the object x y z. (May be I print it wrong?? The object is 3m away…)

        for object in objects.object_list:
            print("Person ID  = {} {}".format(object.id, object.position))

How can I know if the floor is detected? Note: when I use the plane_detection example, I can see the green mesh when I click the space bar. So, even my lab is messy, the floor can be detected I guess.
How to modify the object detection code so that I can see the green floor? I have a hard time reading the OpenGL python code in plane detection. Is there any link of the cloud window display? Thx

And when I comment out “positional_tracking_parameters.set_floor_as_origin = True”
The x y z is more or less the same…
Person ID = 0 [ 0.52168459 -0.25106254 -2.98486495]
Person ID = 0 [ 0.5406729 -0.2512401 -2.98334646]

Btw, my ZED is pointing a little downward, it shouldn’t matter right? As soon as it can detect the floor…
Thx

And When I put the object on the floor
Person ID = 6 [ 0.4964152 -0.7681551 -2.62042546]
Person ID = 6 [ 0.49598047 -0.7681368 -2.61898327]
Person ID = 6 [ 0.49580163 -0.76822615 -2.6143527 ]
So, the the middle value is the height? And the last value is the distance to the camera? I am a little confuse with the coordinate. is there any link about it?
If I put it on the floor, why the middle value is more negative…?
Note: Before, the object is on a chair.

Thx

Below is the full code.

########################################################################
#
# Copyright (c) 2022, STEREOLABS.
#
# All rights reserved.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
########################################################################

"""
    This sample demonstrates how to capture 3D point cloud and detected objects
    with the ZED SDK and display the result in an OpenGL window.
"""

import sys
import numpy as np
import cv2
import pyzed.sl as sl

import ogl_viewer.viewer as gl
import cv_viewer.tracking_viewer as cv_viewer
from batch_system_handler import *


##
# Variable to enable/disable the batch option in Object Detection module
# Batching system allows to reconstruct trajectories from the object detection module by adding Re-Identification / Appareance matching.
# For example, if an object is not seen during some time, it can be re-ID to a previous ID if the matching score is high enough
# Use with caution if image retention is activated (See batch_system_handler.py) :
#   --> Images will only appear if an object is detected since the batching system is based on OD detection.
USE_BATCHING = False

if __name__ == "__main__":
    print("Running object detection ... Press 'Esc' to quit")
    zed = sl.Camera()
    
    # Create a InitParameters object and set configuration parameters
    init_params = sl.InitParameters()
    init_params.camera_resolution = sl.RESOLUTION.HD1080
    init_params.coordinate_units = sl.UNIT.METER
    init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP  
    init_params.depth_mode = sl.DEPTH_MODE.ULTRA
    init_params.depth_maximum_distance = 20
    is_playback = False                             # Defines if an SVO is used
        
    # If applicable, use the SVO given as parameter
    # Otherwise use ZED live stream
    if len(sys.argv) == 2:
        filepath = sys.argv[1]
        print("Using SVO file: {0}".format(filepath))
        init_params.svo_real_time_mode = True
        init_params.set_from_svo_file(filepath)
        is_playback = True

    status = zed.open(init_params)
    if status != sl.ERROR_CODE.SUCCESS:
        print(repr(status))
        exit()


    # Enable positional tracking module
    positional_tracking_parameters = sl.PositionalTrackingParameters()
    # If the camera is static in space, enabling this setting below provides better depth quality and faster computation
    positional_tracking_parameters.set_as_static = True
    positional_tracking_parameters.set_floor_as_origin = True
    zed.enable_positional_tracking(positional_tracking_parameters)

    # Enable object detection module
    batch_parameters = sl.BatchParameters()
    if USE_BATCHING:
        batch_parameters.enable = True
        batch_parameters.latency = 2.0
        batch_handler = BatchSystemHandler(batch_parameters.latency*2)
    else:
        batch_parameters.enable = False
    obj_param = sl.ObjectDetectionParameters(batch_trajectories_parameters=batch_parameters)
        
    obj_param.detection_model = sl.DETECTION_MODEL.MULTI_CLASS_BOX
    # Defines if the object detection will track objects across images flow.
    obj_param.enable_tracking = True
    zed.enable_object_detection(obj_param)

    camera_infos = zed.get_camera_information()
    # Create OpenGL viewer
    viewer = gl.GLViewer()
    point_cloud_res = sl.Resolution(min(camera_infos.camera_resolution.width, 720), min(camera_infos.camera_resolution.height, 404)) 
    point_cloud_render = sl.Mat()
    viewer.init(camera_infos.camera_model, point_cloud_res, obj_param.enable_tracking)
    
    # Configure object detection runtime parameters
    obj_runtime_param = sl.ObjectDetectionRuntimeParameters()
    detection_confidence = 10#60
    obj_runtime_param.detection_confidence_threshold = detection_confidence
    # To select a set of specific object classes
    obj_runtime_param.object_class_filter = [sl.OBJECT_CLASS.PERSON]
    # To set a specific threshold
    obj_runtime_param.object_class_detection_confidence_threshold = {sl.OBJECT_CLASS.PERSON: detection_confidence} 

    # Runtime parameters
    runtime_params = sl.RuntimeParameters()
    runtime_params.confidence_threshold = 10#50

    # Create objects that will store SDK outputs
    point_cloud = sl.Mat(point_cloud_res.width, point_cloud_res.height, sl.MAT_TYPE.F32_C4, sl.MEM.CPU)
    objects = sl.Objects()
    image_left = sl.Mat()

    # Utilities for 2D display
    display_resolution = sl.Resolution(min(camera_infos.camera_resolution.width, 1280), min(camera_infos.camera_resolution.height, 720))
    image_scale = [display_resolution.width / camera_infos.camera_resolution.width
                 , display_resolution.height / camera_infos.camera_resolution.height]
    image_left_ocv = np.full((display_resolution.height, display_resolution.width, 4), [245, 239, 239,255], np.uint8)

    # Utilities for tracks view
    camera_config = zed.get_camera_information().camera_configuration
    tracks_resolution = sl.Resolution(400, display_resolution.height)
    track_view_generator = cv_viewer.TrackingViewer(tracks_resolution, camera_config.camera_fps, init_params.depth_maximum_distance)
    track_view_generator.set_camera_calibration(camera_config.calibration_parameters)
    image_track_ocv = np.zeros((tracks_resolution.height, tracks_resolution.width, 4), np.uint8)

    # Will store the 2D image and tracklet views 
    global_image = np.full((display_resolution.height, display_resolution.width+tracks_resolution.width, 4), [245, 239, 239,255], np.uint8)

    # Camera pose
    cam_w_pose = sl.Pose()
    cam_c_pose = sl.Pose()

    quit_app = False

    while(viewer.is_available() and (quit_app == False)):
        if zed.grab(runtime_params) == sl.ERROR_CODE.SUCCESS:
            # Retrieve objects
            returned_state = zed.retrieve_objects(objects, obj_runtime_param)
            
            if (returned_state == sl.ERROR_CODE.SUCCESS and objects.is_new):
                # Retrieve point cloud
                zed.retrieve_measure(point_cloud, sl.MEASURE.XYZRGBA,sl.MEM.CPU, point_cloud_res)
                point_cloud.copy_to(point_cloud_render)
                # Retrieve image
                zed.retrieve_image(image_left, sl.VIEW.LEFT, sl.MEM.CPU, display_resolution)
                image_render_left = image_left.get_data()
                # Get camera pose
                zed.get_position(cam_w_pose, sl.REFERENCE_FRAME.WORLD)

                update_render_view = True
                update_3d_view = True
                update_tracking_view = True

                if USE_BATCHING:
                    zed.get_position(cam_c_pose, sl.REFERENCE_FRAME.CAMERA)
                    objects_batch = []
                    zed.get_objects_batch(objects_batch)
                    batch_handler.push(cam_c_pose,cam_w_pose,image_left,point_cloud,objects_batch)
                    cam_c_pose, cam_w_pose, image_left, point_cloud_render, objects = batch_handler.pop(cam_c_pose,cam_w_pose,image_left,point_cloud,objects)
                    
                    image_render_left = image_left.get_data()
                    
                    update_tracking_view = objects.is_new

                    if WITH_IMAGE_RETENTION:
                        update_render_view = objects.is_new
                        update_3d_view = objects.is_new
                    else:
                        update_render_view = True
                        update_3d_view = True

#####################
            for object in objects.object_list:
                print("Person ID  = {} {}".format(object.id, object.position))


#######################
                # 3D rendering
                if update_3d_view:
                    viewer.updateData(point_cloud_render, objects)

                # 2D rendering
                if update_render_view:
                    np.copyto(image_left_ocv,image_render_left)
                    cv_viewer.render_2D(image_left_ocv,image_scale,objects, obj_param.enable_tracking)
                    global_image = cv2.hconcat([image_left_ocv,image_track_ocv])

                # Tracking view
                if update_tracking_view:
                    track_view_generator.generate_view(objects, cam_w_pose, image_track_ocv, objects.is_tracked)
                    
            cv2.imshow("ZED | 2D View and Birds View",global_image)
            cv2.waitKey(10)

        if (is_playback and (zed.get_svo_position() == zed.get_svo_number_of_frames()-1)):
            print("End of SVO")
            quit_app = True


    cv2.destroyAllWindows()
    viewer.exit()
    image_left.free(sl.MEM.CPU)
    point_cloud.free(sl.MEM.CPU)
    point_cloud_render.free(sl.MEM.CPU)

    if USE_BATCHING:
        batch_handler.clear()

    # Disable modules and close camera
    zed.disable_object_detection()
    zed.disable_positional_tracking()

    zed.close()

Hi,

In your sample, you are using : init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP which means you have to use the Y axis in your case.

I forgot to mention it in my previous message, but you also need to set runtime_params.measure3D_reference_frame = REFERENCE_FRAME.WORLD (default is camera).
This way, the object detection position is directly in the right coordinate system. If you can’t change this param because of the OGL display, for example, you can convert the position you receive from the OD module from the Camera Coordinate system to the World Coordinate system, using the pose of the Camera (cam_w_pose in your sample code).

Best,
Benjamin Vallon

Stereolabs Support

Hi,

Here is my result with updated code.
I think the middle value is the height, correct?
Less negative means closer to the floor?
But if I move further away from the ZED camera, the middle value change…
How can I know the floor is actually detected?

Thx

On the Chair
Person ID = 0 [ 1.1501559 -0.62542784 2.50490832]
Person ID = 0 [ 1.15023017 -0.62573695 2.50752926]

On the floor
Person ID = 21 [ 0.91341418 -0.17756172 2.52376056]
Person ID = 21 [ 0.91349429 -0.17753631 2.52401114]

########################################################################
#
# Copyright (c) 2022, STEREOLABS.
#
# All rights reserved.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
########################################################################

"""
    This sample demonstrates how to capture 3D point cloud and detected objects
    with the ZED SDK and display the result in an OpenGL window.
"""

import sys
import numpy as np
import cv2
import pyzed.sl as sl

import ogl_viewer.viewer as gl
import cv_viewer.tracking_viewer as cv_viewer
from batch_system_handler import *


##
# Variable to enable/disable the batch option in Object Detection module
# Batching system allows to reconstruct trajectories from the object detection module by adding Re-Identification / Appareance matching.
# For example, if an object is not seen during some time, it can be re-ID to a previous ID if the matching score is high enough
# Use with caution if image retention is activated (See batch_system_handler.py) :
#   --> Images will only appear if an object is detected since the batching system is based on OD detection.
USE_BATCHING = False

if __name__ == "__main__":
    print("Running object detection ... Press 'Esc' to quit")
    zed = sl.Camera()
    
    # Create a InitParameters object and set configuration parameters
    init_params = sl.InitParameters()
    init_params.camera_resolution = sl.RESOLUTION.HD1080
    init_params.coordinate_units = sl.UNIT.METER
#    init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP  
    init_params.depth_mode = sl.DEPTH_MODE.ULTRA
    init_params.depth_maximum_distance = 20
    is_playback = False                             # Defines if an SVO is used
        
    # If applicable, use the SVO given as parameter
    # Otherwise use ZED live stream
    if len(sys.argv) == 2:
        filepath = sys.argv[1]
        print("Using SVO file: {0}".format(filepath))
        init_params.svo_real_time_mode = True
        init_params.set_from_svo_file(filepath)
        is_playback = True

    status = zed.open(init_params)
    if status != sl.ERROR_CODE.SUCCESS:
        print(repr(status))
        exit()


    # Enable positional tracking module
    positional_tracking_parameters = sl.PositionalTrackingParameters()
    # If the camera is static in space, enabling this setting below provides better depth quality and faster computation
    positional_tracking_parameters.set_as_static = True
    positional_tracking_parameters.set_floor_as_origin = True
    zed.enable_positional_tracking(positional_tracking_parameters)

    # Enable object detection module
    batch_parameters = sl.BatchParameters()
    if USE_BATCHING:
        batch_parameters.enable = True
        batch_parameters.latency = 2.0
        batch_handler = BatchSystemHandler(batch_parameters.latency*2)
    else:
        batch_parameters.enable = False
    obj_param = sl.ObjectDetectionParameters(batch_trajectories_parameters=batch_parameters)
        
    obj_param.detection_model = sl.DETECTION_MODEL.MULTI_CLASS_BOX
    # Defines if the object detection will track objects across images flow.
    obj_param.enable_tracking = True
    zed.enable_object_detection(obj_param)

    camera_infos = zed.get_camera_information()
    # Create OpenGL viewer
    viewer = gl.GLViewer()
    point_cloud_res = sl.Resolution(min(camera_infos.camera_resolution.width, 720), min(camera_infos.camera_resolution.height, 404)) 
    point_cloud_render = sl.Mat()
    viewer.init(camera_infos.camera_model, point_cloud_res, obj_param.enable_tracking)
    
    # Configure object detection runtime parameters
    obj_runtime_param = sl.ObjectDetectionRuntimeParameters()
    detection_confidence = 10#60
    obj_runtime_param.detection_confidence_threshold = detection_confidence
    # To select a set of specific object classes
    obj_runtime_param.object_class_filter = [sl.OBJECT_CLASS.PERSON]
    # To set a specific threshold
    obj_runtime_param.object_class_detection_confidence_threshold = {sl.OBJECT_CLASS.PERSON: detection_confidence} 

    # Runtime parameters
    runtime_params = sl.RuntimeParameters()
    runtime_params.confidence_threshold = 10#50
#######################
    runtime_params.measure3D_reference_frame = sl.REFERENCE_FRAME.WORLD
########################
    # Create objects that will store SDK outputs
    point_cloud = sl.Mat(point_cloud_res.width, point_cloud_res.height, sl.MAT_TYPE.F32_C4, sl.MEM.CPU)
    objects = sl.Objects()
    image_left = sl.Mat()

    # Utilities for 2D display
    display_resolution = sl.Resolution(min(camera_infos.camera_resolution.width, 1280), min(camera_infos.camera_resolution.height, 720))
    image_scale = [display_resolution.width / camera_infos.camera_resolution.width
                 , display_resolution.height / camera_infos.camera_resolution.height]
    image_left_ocv = np.full((display_resolution.height, display_resolution.width, 4), [245, 239, 239,255], np.uint8)

    # Utilities for tracks view
    camera_config = zed.get_camera_information().camera_configuration
    tracks_resolution = sl.Resolution(400, display_resolution.height)
    track_view_generator = cv_viewer.TrackingViewer(tracks_resolution, camera_config.camera_fps, init_params.depth_maximum_distance)
    track_view_generator.set_camera_calibration(camera_config.calibration_parameters)
    image_track_ocv = np.zeros((tracks_resolution.height, tracks_resolution.width, 4), np.uint8)

    # Will store the 2D image and tracklet views 
    global_image = np.full((display_resolution.height, display_resolution.width+tracks_resolution.width, 4), [245, 239, 239,255], np.uint8)

    # Camera pose
    cam_w_pose = sl.Pose()
    cam_c_pose = sl.Pose()

    quit_app = False

    while(viewer.is_available() and (quit_app == False)):
        if zed.grab(runtime_params) == sl.ERROR_CODE.SUCCESS:
            # Retrieve objects
            returned_state = zed.retrieve_objects(objects, obj_runtime_param)
            
            if (returned_state == sl.ERROR_CODE.SUCCESS and objects.is_new):
                # Retrieve point cloud
                zed.retrieve_measure(point_cloud, sl.MEASURE.XYZRGBA,sl.MEM.CPU, point_cloud_res)
                point_cloud.copy_to(point_cloud_render)
                # Retrieve image
                zed.retrieve_image(image_left, sl.VIEW.LEFT, sl.MEM.CPU, display_resolution)
                image_render_left = image_left.get_data()
                # Get camera pose
                zed.get_position(cam_w_pose, sl.REFERENCE_FRAME.WORLD)

                update_render_view = True
                update_3d_view = True
                update_tracking_view = True

                if USE_BATCHING:
                    zed.get_position(cam_c_pose, sl.REFERENCE_FRAME.CAMERA)
                    objects_batch = []
                    zed.get_objects_batch(objects_batch)
                    batch_handler.push(cam_c_pose,cam_w_pose,image_left,point_cloud,objects_batch)
                    cam_c_pose, cam_w_pose, image_left, point_cloud_render, objects = batch_handler.pop(cam_c_pose,cam_w_pose,image_left,point_cloud,objects)
                    
                    image_render_left = image_left.get_data()
                    
                    update_tracking_view = objects.is_new

                    if WITH_IMAGE_RETENTION:
                        update_render_view = objects.is_new
                        update_3d_view = objects.is_new
                    else:
                        update_render_view = True
                        update_3d_view = True

#####################
            for object in objects.object_list:
                print("Person ID  = {} {}".format(object.id, object.position))


#######################
                # 3D rendering
                if update_3d_view:
                    viewer.updateData(point_cloud_render, objects)

                # 2D rendering
                if update_render_view:
                    np.copyto(image_left_ocv,image_render_left)
                    cv_viewer.render_2D(image_left_ocv,image_scale,objects, obj_param.enable_tracking)
                    global_image = cv2.hconcat([image_left_ocv,image_track_ocv])

                # Tracking view
                if update_tracking_view:
                    track_view_generator.generate_view(objects, cam_w_pose, image_track_ocv, objects.is_tracked)
                    
            cv2.imshow("ZED | 2D View and Birds View",global_image)
            cv2.waitKey(10)

        if (is_playback and (zed.get_svo_position() == zed.get_svo_number_of_frames()-1)):
            print("End of SVO")
            quit_app = True


    cv2.destroyAllWindows()
    viewer.exit()
    image_left.free(sl.MEM.CPU)
    point_cloud.free(sl.MEM.CPU)
    point_cloud_render.free(sl.MEM.CPU)

    if USE_BATCHING:
        batch_handler.clear()

    # Disable modules and close camera
    zed.disable_object_detection()
    zed.disable_positional_tracking()

    zed.close()

Hi,

You commented the line init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP which means you are using the default coordinate system “IMAGE” which has Y down axis (see here ; Core Module | API Reference | Stereolabs).

Hi,

My question is that I would like to check height between the centre of a person from the floor. Say x distance
In my code, if the distance between the person and the camera change, the x change also… I don’t understand. Thx

Hi,

Here is my test video.
The middle value changes a lot… (which is y, the height of that person)
Let me explain what I want to do. I would like to set the floor as reference. So, when a person move around, the height (y) is the same in this test.
The next step, if the person jump or lay on the floor, I will know from the y value.

y range is from -1.35 to -0.84. So, the zed cannot see the floor?? Or some parameter setting issue?

And the y is not consistence at the beginning of the video and the end of the video when the person is at the same distance from the camera…
Time at 0:03 y is -1.34
Time at 0:32 y is -0.90
But the person is at the similar distance from the camera. I don’t understand…

Thx

Here is the same code for reference. Thx

########################################################################
#
# Copyright (c) 2022, STEREOLABS.
#
# All rights reserved.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
########################################################################

"""
    This sample demonstrates how to capture 3D point cloud and detected objects
    with the ZED SDK and display the result in an OpenGL window.
"""

import sys
import numpy as np
import cv2
import pyzed.sl as sl

import ogl_viewer.viewer as gl
import cv_viewer.tracking_viewer as cv_viewer
from batch_system_handler import *


##
# Variable to enable/disable the batch option in Object Detection module
# Batching system allows to reconstruct trajectories from the object detection module by adding Re-Identification / Appareance matching.
# For example, if an object is not seen during some time, it can be re-ID to a previous ID if the matching score is high enough
# Use with caution if image retention is activated (See batch_system_handler.py) :
#   --> Images will only appear if an object is detected since the batching system is based on OD detection.
USE_BATCHING = False

if __name__ == "__main__":
    print("Running object detection ... Press 'Esc' to quit")
    zed = sl.Camera()
    
    # Create a InitParameters object and set configuration parameters
    init_params = sl.InitParameters()
    init_params.camera_resolution = sl.RESOLUTION.HD1080
    init_params.coordinate_units = sl.UNIT.METER
#    init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP  
    init_params.depth_mode = sl.DEPTH_MODE.ULTRA
    init_params.depth_maximum_distance = 20
    is_playback = False                             # Defines if an SVO is used
        
    # If applicable, use the SVO given as parameter
    # Otherwise use ZED live stream
    if len(sys.argv) == 2:
        filepath = sys.argv[1]
        print("Using SVO file: {0}".format(filepath))
        init_params.svo_real_time_mode = True
        init_params.set_from_svo_file(filepath)
        is_playback = True

    status = zed.open(init_params)
    if status != sl.ERROR_CODE.SUCCESS:
        print(repr(status))
        exit()


    # Enable positional tracking module
    positional_tracking_parameters = sl.PositionalTrackingParameters()
    # If the camera is static in space, enabling this setting below provides better depth quality and faster computation
    positional_tracking_parameters.set_as_static = True
    positional_tracking_parameters.set_floor_as_origin = True
    zed.enable_positional_tracking(positional_tracking_parameters)

    # Enable object detection module
    batch_parameters = sl.BatchParameters()
    if USE_BATCHING:
        batch_parameters.enable = True
        batch_parameters.latency = 2.0
        batch_handler = BatchSystemHandler(batch_parameters.latency*2)
    else:
        batch_parameters.enable = False
    obj_param = sl.ObjectDetectionParameters(batch_trajectories_parameters=batch_parameters)
        
    obj_param.detection_model = sl.DETECTION_MODEL.MULTI_CLASS_BOX
    # Defines if the object detection will track objects across images flow.
    obj_param.enable_tracking = True
    zed.enable_object_detection(obj_param)

    camera_infos = zed.get_camera_information()
    # Create OpenGL viewer
    viewer = gl.GLViewer()
    point_cloud_res = sl.Resolution(min(camera_infos.camera_resolution.width, 720), min(camera_infos.camera_resolution.height, 404)) 
    point_cloud_render = sl.Mat()
    viewer.init(camera_infos.camera_model, point_cloud_res, obj_param.enable_tracking)
    
    # Configure object detection runtime parameters
    obj_runtime_param = sl.ObjectDetectionRuntimeParameters()
    detection_confidence = 10#60
    obj_runtime_param.detection_confidence_threshold = detection_confidence
    # To select a set of specific object classes
    obj_runtime_param.object_class_filter = [sl.OBJECT_CLASS.PERSON]
    # To set a specific threshold
    obj_runtime_param.object_class_detection_confidence_threshold = {sl.OBJECT_CLASS.PERSON: detection_confidence} 

    # Runtime parameters
    runtime_params = sl.RuntimeParameters()
    runtime_params.confidence_threshold = 10#50
#######################
    runtime_params.measure3D_reference_frame = sl.REFERENCE_FRAME.WORLD
########################
    # Create objects that will store SDK outputs
    point_cloud = sl.Mat(point_cloud_res.width, point_cloud_res.height, sl.MAT_TYPE.F32_C4, sl.MEM.CPU)
    objects = sl.Objects()
    image_left = sl.Mat()

    # Utilities for 2D display
    display_resolution = sl.Resolution(min(camera_infos.camera_resolution.width, 1280), min(camera_infos.camera_resolution.height, 720))
    image_scale = [display_resolution.width / camera_infos.camera_resolution.width
                 , display_resolution.height / camera_infos.camera_resolution.height]
    image_left_ocv = np.full((display_resolution.height, display_resolution.width, 4), [245, 239, 239,255], np.uint8)

    # Utilities for tracks view
    camera_config = zed.get_camera_information().camera_configuration
    tracks_resolution = sl.Resolution(400, display_resolution.height)
    track_view_generator = cv_viewer.TrackingViewer(tracks_resolution, camera_config.camera_fps, init_params.depth_maximum_distance)
    track_view_generator.set_camera_calibration(camera_config.calibration_parameters)
    image_track_ocv = np.zeros((tracks_resolution.height, tracks_resolution.width, 4), np.uint8)

    # Will store the 2D image and tracklet views 
    global_image = np.full((display_resolution.height, display_resolution.width+tracks_resolution.width, 4), [245, 239, 239,255], np.uint8)

    # Camera pose
    cam_w_pose = sl.Pose()
    cam_c_pose = sl.Pose()

    quit_app = False

    while(viewer.is_available() and (quit_app == False)):
        if zed.grab(runtime_params) == sl.ERROR_CODE.SUCCESS:
            # Retrieve objects
            returned_state = zed.retrieve_objects(objects, obj_runtime_param)
            
            if (returned_state == sl.ERROR_CODE.SUCCESS and objects.is_new):
                # Retrieve point cloud
                zed.retrieve_measure(point_cloud, sl.MEASURE.XYZRGBA,sl.MEM.CPU, point_cloud_res)
                point_cloud.copy_to(point_cloud_render)
                # Retrieve image
                zed.retrieve_image(image_left, sl.VIEW.LEFT, sl.MEM.CPU, display_resolution)
                image_render_left = image_left.get_data()
                # Get camera pose
                zed.get_position(cam_w_pose, sl.REFERENCE_FRAME.WORLD)

                update_render_view = True
                update_3d_view = True
                update_tracking_view = True

                if USE_BATCHING:
                    zed.get_position(cam_c_pose, sl.REFERENCE_FRAME.CAMERA)
                    objects_batch = []
                    zed.get_objects_batch(objects_batch)
                    batch_handler.push(cam_c_pose,cam_w_pose,image_left,point_cloud,objects_batch)
                    cam_c_pose, cam_w_pose, image_left, point_cloud_render, objects = batch_handler.pop(cam_c_pose,cam_w_pose,image_left,point_cloud,objects)
                    
                    image_render_left = image_left.get_data()
                    
                    update_tracking_view = objects.is_new

                    if WITH_IMAGE_RETENTION:
                        update_render_view = objects.is_new
                        update_3d_view = objects.is_new
                    else:
                        update_render_view = True
                        update_3d_view = True

#####################
            for object in objects.object_list:
                print("Person ID  = {} {}".format(object.id, object.position))
#                if(abs(float(object.position[1]))< 0.4):
#                    print("The person is on the floor")
#######################
                # 3D rendering
                if update_3d_view:
                    viewer.updateData(point_cloud_render, objects)

                # 2D rendering
                if update_render_view:
                    np.copyto(image_left_ocv,image_render_left)
                    cv_viewer.render_2D(image_left_ocv,image_scale,objects, obj_param.enable_tracking)
                    global_image = cv2.hconcat([image_left_ocv,image_track_ocv])

                # Tracking view
                if update_tracking_view:
                    track_view_generator.generate_view(objects, cam_w_pose, image_track_ocv, objects.is_tracked)
                    
            cv2.imshow("ZED | 2D View and Birds View",global_image)
            cv2.waitKey(10)

        if (is_playback and (zed.get_svo_position() == zed.get_svo_number_of_frames()-1)):
            print("End of SVO")
            quit_app = True


    cv2.destroyAllWindows()
    viewer.exit()
    image_left.free(sl.MEM.CPU)
    point_cloud.free(sl.MEM.CPU)
    point_cloud_render.free(sl.MEM.CPU)

    if USE_BATCHING:
        batch_handler.clear()

    # Disable modules and close camera
    zed.disable_object_detection()
    zed.disable_positional_tracking()

    zed.close()

Hi,

This video seems better. Same code. How can I know if it can detect the floor? And use the floor as reference?
Also, why at 6.3m away from camera, y is different by almost 20cm? Thx
Note: I did setup the camera and keep it stable before running my code.

y from -1.36 at 00:00 (6.3m from camera)
-1.34 at 00:11 (16.6m from camera)
-1.18 at 00:28 (6.3m from camera)

HI,

And I also tried to use the skeleton. Use the nose y axis to determine the height of the person. It is even worst. 4m tall… :< Sorry, I am new to ZED and I merge several sample codes together.

I just want to proper way to use the floor as a reference to determine the height of the person. Thx

And also, if I disable the “init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP” line, the cloud view is flipped… How can I fit it? Thx

Here is my messy code, :stuck_out_tongue:

########################################################################
#
# Copyright (c) 2022, STEREOLABS.
#
# All rights reserved.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
########################################################################

"""
   This sample shows how to detect a human bodies and draw their 
   modelised skeleton in an OpenGL window
"""
import cv2
import sys
import pyzed.sl as sl
import ogl_viewer.viewer as gl
import cv_viewer.tracking_viewer as cv_viewer
import numpy as np

if __name__ == "__main__":
    print("Running Body Tracking sample ... Press 'q' to quit")

    # Create a Camera object
    zed = sl.Camera()

    # Create a InitParameters object and set configuration parameters
    init_params = sl.InitParameters()
    init_params.camera_resolution = sl.RESOLUTION.HD1080  # Use HD1080 video mode
#	init_params.camera_resolution = sl.RESOLUTION.HD2K
    init_params.coordinate_units = sl.UNIT.METER          # Set coordinate units
    init_params.depth_mode = sl.DEPTH_MODE.ULTRA
    init_params.depth_maximum_distance = 20
    is_playback = False 
#    init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP
    
    # If applicable, use the SVO given as parameter
    # Otherwise use ZED live stream
    if len(sys.argv) == 2:
        filepath = sys.argv[1]
        print("Using SVO file: {0}".format(filepath))
        init_params.svo_real_time_mode = True
        init_params.set_from_svo_file(filepath)

    # Open the camera
    err = zed.open(init_params)
    if err != sl.ERROR_CODE.SUCCESS:
        exit(1)

    # Enable Positional tracking (mandatory for object detection)
    positional_tracking_parameters = sl.PositionalTrackingParameters()
    # If the camera is static, uncomment the following line to have better performances and boxes sticked to the ground.
    positional_tracking_parameters.set_as_static = True
    positional_tracking_parameters.set_floor_as_origin = True
    zed.enable_positional_tracking(positional_tracking_parameters)
    
    obj_param = sl.ObjectDetectionParameters()
#skeleton move
    obj_param.enable_tracking = True                # Track people across images flow
    obj_param.detection_model = sl.DETECTION_MODEL.HUMAN_BODY_FAST 
#    obj_param.detection_model = sl.DETECTION_MODEL.HUMAN_BODY_ACCURATE 
    obj_param.enable_body_fitting = True
#    obj_param.body_format = sl.BODY_FORMAT.POSE_18  # Choose the BODY_FORMAT you wish to use
    obj_param.body_format = sl.BODY_FORMAT.POSE_34  # Choose the BODY_FORMAT you wish to use

    # Create ZED objects filled in the main loop
    bodies = sl.Objects()
    image = sl.Mat()

    # Enable Object Detection module
    zed.enable_object_detection(obj_param)
    runtime_params = sl.RuntimeParameters()
    obj_runtime_param = sl.ObjectDetectionRuntimeParameters()
#andy original 40
    obj_runtime_param.detection_confidence_threshold = 0.01 #40
    runtime_params.measure3D_reference_frame = sl.REFERENCE_FRAME.WORLD
    if zed.grab(runtime_params) == sl.ERROR_CODE.SUCCESS :
        zed.retrieve_objects(bodies, obj_runtime_param) # Retrieve the detected objects
    # Get ZED camera information
    camera_info = zed.get_camera_information()

    # 2D viewer utilities
    display_resolution = sl.Resolution(min(camera_info.camera_resolution.width, 1280), min(camera_info.camera_resolution.height, 720))
    image_scale = [display_resolution.width / camera_info.camera_resolution.width
                 , display_resolution.height / camera_info.camera_resolution.height]

    # Create OpenGL viewer
    viewer = gl.GLViewer()
    viewer.init(camera_info.calibration_parameters.left_cam, obj_param.enable_tracking,obj_param.body_format)

    while viewer.is_available():
#        print("####################new frame###################3")
        # Grab an image
        if zed.grab() == sl.ERROR_CODE.SUCCESS:
            # Retrieve left image
            zed.retrieve_image(image, sl.VIEW.LEFT, sl.MEM.CPU, display_resolution)
            # Retrieve objects
            zed.retrieve_objects(bodies, obj_runtime_param)
#            print("bodies = ", bodies) # SUCCESS
            # Update GL view
            for object in bodies.object_list:
                print("Person ID  = {} {}".format(object.id, object.position))
#                if(abs(float(object.position[1]))> 0.6): #0.85 floor, 0.39 sit
#                    print("The person is on the floor")
#                print("keypoints {}".format(object.keypoint))
#                print("{} {}".format(object.id, object.position))
                i = 0
                for kp_3d in object.keypoint:
                    if(i==27):
                        print("nose = ", kp_3d)
                    i = i+1
            viewer.update_view(image, bodies) 
            # Update OCV view
            image_left_ocv = image.get_data()
            cv_viewer.render_2D(image_left_ocv,image_scale,bodies.object_list, obj_param.enable_tracking, obj_param.body_format)
            cv2.imshow("ZED | 2D View", image_left_ocv)
            cv2.waitKey(10)

    viewer.exit()

    image.free(sl.MEM.CPU)
    # Disable modules and close camera
    zed.disable_object_detection()
    zed.disable_positional_tracking()
    zed.close()

Hi,

It is Sunday today… it has been almost a week for me to try the code for measuring the nose from the floor. Still not working…
I did carefully modify the code from body_tracking.py sample code.
The height of the nose is not related to the floor. :< 6m tall??

There are 5 places (new0,new1,new2,new3,new4) modification from your body_tracking.py example
Note: I have tried to enable/disable init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP
It does not affect the height. (If I disable it, I cannot see the stick man in the black screen)

Below is the modified code, pls let me know if I miss any setting. (Do I need IMU as the camera tilted download)

########################################################################
#
# Copyright (c) 2022, STEREOLABS.
#
# All rights reserved.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
########################################################################

"""
#   This sample shows how to detect a human bodies and draw their 
#   modelised skeleton in an OpenGL window
"""
import cv2
import sys
import pyzed.sl as sl
import ogl_viewer.viewer as gl
import cv_viewer.tracking_viewer as cv_viewer
import numpy as np

if __name__ == "__main__":
    print("Running Body Tracking sample ... Press 'q' to quit")

    # Create a Camera object
    zed = sl.Camera()

    # Create a InitParameters object and set configuration parameters
    init_params = sl.InitParameters()
    init_params.camera_resolution = sl.RESOLUTION.HD1080  # Use HD1080 video mode
    init_params.coordinate_units = sl.UNIT.METER          # Set coordinate units
    init_params.depth_mode = sl.DEPTH_MODE.ULTRA

#new0###################
    init_params.depth_maximum_distance = 20
    init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP
#######################    

    # If applicable, use the SVO given as parameter
    # Otherwise use ZED live stream
    if len(sys.argv) == 2:
        filepath = sys.argv[1]
        print("Using SVO file: {0}".format(filepath))
        init_params.svo_real_time_mode = True
        init_params.set_from_svo_file(filepath)

    # Open the camera
    err = zed.open(init_params)
    if err != sl.ERROR_CODE.SUCCESS:
        exit(1)

    # Enable Positional tracking (mandatory for object detection)
    positional_tracking_parameters = sl.PositionalTrackingParameters()
    # If the camera is static, uncomment the following line to have better performances and boxes sticked to the ground.

#new1###################
    positional_tracking_parameters.set_as_static = True
    positional_tracking_parameters.set_floor_as_origin = True
#######################

    zed.enable_positional_tracking(positional_tracking_parameters)
    
    obj_param = sl.ObjectDetectionParameters()
    obj_param.enable_body_fitting = True            # Smooth skeleton move
    obj_param.enable_tracking = True                # Track people across images flow

#new2###################
#    obj_param.detection_model = sl.DETECTION_MODEL.HUMAN_BODY_FAST 
    obj_param.detection_model = sl.DETECTION_MODEL.HUMAN_BODY_ACCURATE 
#    obj_param.body_format = sl.BODY_FORMAT.POSE_18  # Choose the BODY_FORMAT you wish to use
    obj_param.body_format = sl.BODY_FORMAT.POSE_34  # Choose the BODY_FORMAT you 
####################

    # Enable Object Detection module
    zed.enable_object_detection(obj_param)

    obj_runtime_param = sl.ObjectDetectionRuntimeParameters()
    obj_runtime_param.detection_confidence_threshold = 40

##new3#################
    runtime_params = sl.RuntimeParameters()
    runtime_params.measure3D_reference_frame = sl.REFERENCE_FRAME.WORLD
###################

    # Get ZED camera information
    camera_info = zed.get_camera_information()

    # 2D viewer utilities
    display_resolution = sl.Resolution(min(camera_info.camera_resolution.width, 1280), min(camera_info.camera_resolution.height, 720))
    image_scale = [display_resolution.width / camera_info.camera_resolution.width
                 , display_resolution.height / camera_info.camera_resolution.height]

    # Create OpenGL viewer
    viewer = gl.GLViewer()
    viewer.init(camera_info.calibration_parameters.left_cam, obj_param.enable_tracking,obj_param.body_format)

    # Create ZED objects filled in the main loop
    bodies = sl.Objects()
    image = sl.Mat()

    while viewer.is_available():
        # Grab an image
        if zed.grab() == sl.ERROR_CODE.SUCCESS:
            # Retrieve left image
            zed.retrieve_image(image, sl.VIEW.LEFT, sl.MEM.CPU, display_resolution)
            # Retrieve objects
            zed.retrieve_objects(bodies, obj_runtime_param)

            # Update GL view
            viewer.update_view(image, bodies) 
            # Update OCV view
            image_left_ocv = image.get_data()
#new4#####################################################3
            for object in bodies.object_list:
                print("Person ID  = {} {}".format(object.id, object.position))
                i = 0
                for kp_3d in object.keypoint:
                    if(i==27):
                        print("nose = ", kp_3d)
                    i = i+1
############################################################
            cv_viewer.render_2D(image_left_ocv,image_scale,bodies.object_list, obj_param.enable_tracking, obj_param.body_format)
            cv2.imshow("ZED | 2D View", image_left_ocv)
            cv2.waitKey(10)

    viewer.exit()

    image.free(sl.MEM.CPU)
    # Disable modules and close camera
    zed.disable_object_detection()
    zed.disable_positional_tracking()
    zed.close()

Hi,

when I use your plane detection example, I can only see small part of the floor…
Pls let me verify again, is it hard for ZED to detect the floor?
If not, what does this line do? “positional_tracking_parameters.set_floor_as_origin = True”

At this moment, what I need is to check if the height of a person is the same when he walks around the area. After that, I can use the feet coordinate to check if he is jumping.

Note: I will install the ZED in a fix location, if it is requires, I can hard code or draw the floor? If yes, it there any sample code I can follow? Or, I mark the person feet locations on the hallway to be the floor (several points on the floor from near to far), then, make a look up table (or equation), then, the height is related to the feet location away from the camera… Does this Plan B ok?

Thx

Oh, I got it work. :>
I didn’t put the runtime_params before, silly me. :stuck_out_tongue:
zed.grab(runtime_params)

Cheers