<gh_stars>0
from argparse import ArgumentParser
import os
import time
import json
import multiprocessing

import cv2
import numpy as np
import norfair
from norfair import Detection, Tracker
from modules.input_reader import VideoReader, ImageReader
from modules.draw import Plotter3d, draw_poses
#from modules.parse_poses import parse_poses

from modules.myconst import *
import myutils as mu

#define Norfair thresholds and keypoints distance function
detection_threshold = 0.01
distance_threshold = 0.6
keypoint_dist_threshold = 30   #image height/25
def keypoints_distance(detected_pose, tracked_pose):
    distances = np.linalg.norm(detected_pose.points - tracked_pose.estimate, axis=1)
    match_num = np.count_nonzero(
        (distances < keypoint_dist_threshold)
        * (detected_pose.scores > detection_threshold)
        * (tracked_pose.last_detection.scores > detection_threshold)
    )

    return 1 / (1 + match_num)


# python demo_unitycam.py --model human-pose-estimation-3d.xml --device CPU --use-openvino --height-size 256 --cam_id 2 --cam_width 640 --cam_height 480
# python demo_unitycam.py --model human-pose-estimation-3d.pth --height-size 256 --cam_id 2 --cam_width 640 --cam_height 480
if __name__ == '__main__':
    parser = ArgumentParser(description='Lightweight 3D human pose estimation demo. '
                                        'Press esc to exit, "p" to (un)pause video or process next image.')
    parser.add_argument('-m', '--model',
                        help='Required. Path to checkpoint with a trained model '
                             '(or an .xml file in case of OpenVINO inference).',
                        type=str, required=True)
    parser.add_argument('--video', help='Optional. Path to video file.', type=str, default='')
    parser.add_argument('--cam_id', type=int, default=1)
    parser.add_argument('--cam_width', help='Optional. camera width.', type=int, default=640)
    parser.add_argument('--cam_height', help='Optional. camera height.', type=int, default=480)    
    parser.add_argument('--mirror_flip', help='Optional. Do mirror flipping on the image frame.',
                        action='store_true')
    parser.add_argument('-d', '--device', help='Optional. The target device to infer on: CPU or GPU (default).',
                        type=str, default='GPU')
    parser.add_argument('--use-openvino',
                        help='Optional. Run network with OpenVINO as inference engine, support CPU, GPU, FPGA, HDDL or MYRIAD.',
                        action='store_true')
    parser.add_argument('--use-tensorrt', help='Optional. Run network with TensorRT as inference engine.',
                        action='store_true')
    parser.add_argument('--height-size', help='Optional. Network input layer height size.', type=int, default=256)
    parser.add_argument('--extrinsics-path',
                        help='Optional. Path to file with camera extrinsics.',
                        type=str, default=None)
    parser.add_argument('--fx', type=np.float32, default=-1, help='Optional. Camera focal length.')
    parser.add_argument('--skipframes', type=int, default=1, help='Optional. Skip frames to speed up the detection.')
    args = parser.parse_args()

    if args.video == '' and args.cam_id == '':
        raise ValueError('Either --video or --cam_id has to be provided')
    stride = 8
    if args.use_openvino:
        from modules.inference_engine_openvino import InferenceEngineOpenVINO
        net = InferenceEngineOpenVINO(args.model, args.device)
    else:
        from modules.inference_engine_pytorch import InferenceEnginePyTorch
        net = InferenceEnginePyTorch(args.model, args.device, use_tensorrt=args.use_tensorrt)

    file_path = args.extrinsics_path
    if file_path is None:
        file_path = os.path.join('data', 'extrinsics.json')
    with open(file_path, 'r') as f:
        extrinsics = json.load(f)
    R = np.array(extrinsics['R'], dtype=np.float32)
    t = np.array(extrinsics['t'], dtype=np.float32)
    base_height = args.height_size
    fx = args.fx

    mirror_flip = args.mirror_flip
    if args.skipframes == '':
        raise ValueError('--skipframes has to be provided')
    else:
        skip_frames = args.skipframes

    #setup the video capture stream
    is_video = True
    if args.video != '':
        cap = cv2.VideoCapture(args.video)
        if (cap.isOpened()== False): 
            raise IOError('Video {} cannot be opened'.format(args.video))
        else:
            frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    else:
        cap = cv2.VideoCapture(args.cam_id, cv2.CAP_DSHOW)
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, args.cam_width)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, args.cam_height)
        cap.set(cv2.CAP_PROP_FPS, 30)            
        # Check if camera opened successfully
        if (cap.isOpened()== False): 
            raise IOError('Video {} cannot be opened'.format(args.cam_id))
        else:
            frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    if not cv2.useOptimized():
        cv2.setUseOptimized(True)

    #setup the canvas_3d window to show skeletons
    canvas_3d = np.zeros((frame_height, frame_width, 3), dtype=np.uint8)
    plotter = Plotter3d(canvas_3d.shape[:2])
    canvas_3d_window_name = 'PoseCam 3D'
    cv2.namedWindow(canvas_3d_window_name)
    cv2.setMouseCallback(canvas_3d_window_name, Plotter3d.mouse_callback)

    # setup Norfair tracker
    tracker = Tracker(
        distance_function=keypoints_distance,
        distance_threshold=distance_threshold,
        detection_threshold=detection_threshold,
        hit_inertia_min=5,
        hit_inertia_max=15,
        point_transience=4,
    )

    #use panopatic order, all 19 keypoints, ignore the last element in pose data
    kpts_list = KPTS_PANOPATIC_IDX
    #kpts_list = [0, 1, 2, 3, 4, 5]      #use panopatic order, just head & neck
    num_kpts = len(kpts_list) // 3

    delay = 1
    esc_code = 27
    p_code = 112
    space_code = 32
    num_poses = 0
    pin = mu.Params4poses([], 0, RESIZE_SQUARE_PADDING, base_height, stride, net, fx, R, t, is_video)
    is_tracked = False
    fps = mu.Framerate()
    frame_count = 0
    tic_start = cv2.getTickCount()    
    #tasks = multiprocessing.Queue()
    #tasks.put((fib, 8))
    #tasks.put((ackermann, 2, 4))
    #tasks.put((fib, 18))
    #tasks.put((ackermann, 3, 1))
    #tasks.put((fib, 28))
    #tasks.put((ackermann, 3, 4))
    #tasks.put((fib, 34))
    #results = []
    #with multiprocessing.Pool(4) as pool:        
    if 1 == 1:
        while (cap.isOpened()):
            tic0 = cv2.getTickCount()                            
            res, frame = cap.read()
            if not res:
                break
            if mirror_flip:
                frame = cv2.flip(frame, 1)
            fps.video = cv2.getTickFrequency() / (cv2.getTickCount() - tic0)            
            
            tic1 = cv2.getTickCount()            
            if frame_count % skip_frames == 0:
            #if 1 == 1:
                pin.frame_no = frame_count
                pin.frame = frame
                #task = tasks.get()
                #func, *args = task
                #result = pool.apply_async(func, *args) 
                #results.append((func.__name__, args, result))
                pout = mu.get_poses(pin)        
                if len(pout.poses_2d):
                    poses_2d = pout.poses_2d
                    poses_3d = pout.poses_3d
                    poses_id = pout.poses_id
                    poses_id_last = pout.poses_id_last
                is_tracked = False
                fps.openpose = cv2.getTickFrequency() / (cv2.getTickCount() - tic1)                                        
            else:
                if len(pout.poses_2d):
                    poses_2d = pout.poses_2d
                    poses_3d = pout.poses_3d
                    poses_id = pout.poses_id
                    poses_id_last = pout.poses_id_last
                is_tracked = True
                fps.tracking = cv2.getTickFrequency() / (cv2.getTickCount() - tic1)                        

            frame_count += 1
            fps.processing = frame_count / ((cv2.getTickCount() - tic_start) / cv2.getTickFrequency())                    

            edges = []
            if len(poses_3d) > 0:
                edges = (Plotter3d.SKELETON_EDGES + NUMKPTS_PANOPATIC * np.arange(poses_3d.shape[0]).reshape((-1, 1, 1))).reshape((-1, 2))
                plotter.plot(canvas_3d, poses_3d, edges)
            cv2.imshow(canvas_3d_window_name, canvas_3d)
            if len(poses_2d) > 0:                
                draw_poses(frame, poses_2d)                

            #norfair.draw_points(frame, detections)
            #norfair.draw_tracked_objects(frame, tracked_objects)
            #norfair.draw_debug_metrics(frame, tracked_objects) 
            #norfair.print_objects_as_table(tracked_objects)                                       
            #draw_poses(frame, poses_2d)        
            #if not is_tracked:
                #if len(poses_2d) > 0:                
                    #draw_poses(frame, poses_2d)                
            #else:
                #if len(tracked_objects) > 0:
                #    norfair.draw_tracked_objects(frame, tracked_objects)
                #if len(poses_2d_tracked) > 0:
                    #draw_poses(frame, poses_2d_tracked, (128, 128, 0), 1, 5, (0, 0, 255), -1)
            if is_video:
                if len(poses_id)>0 and len(poses_id_last)>0 and \
                    len(poses_id) == len(poses_id_last):
                    for pose_idx in range(len(poses_2d)):        
                        cv2.putText(frame, 'id:{0:3d}'.format(min(int(poses_id[pose_idx]),int(poses_id_last[pose_idx]))), \
                            (max(int(poses_2d[pose_idx, 3]), 20), max(20,int(poses_2d[pose_idx, 4])-40)), \
                            cv2.FONT_HERSHEY_COMPLEX, 0.6, (255, 0, 0), 1)
            
            cv2.putText(frame, 'FPS-video: {}'.format(int(fps.video)), (20, 20), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 255), 1)
            cv2.putText(frame, 'FPS-openpose: {}'.format(int(fps.openpose)), (20, 45), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 255), 1)
            cv2.putText(frame, 'FPS-norfair: {}'.format(int(fps.norfair)), (20, 70), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 255), 1)
            cv2.putText(frame, 'FPS-tracking: {}'.format(int(fps.tracking)), (20, 95), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 255), 1)        
            cv2.putText(frame, 'FPS-processing: {}'.format(int(fps.processing)), (20, 120), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 255), 1)        
            cv2.imshow('PoseCam View', frame)

            key = cv2.waitKey(delay)
            if key == esc_code:
                break
            if key == p_code:
                if delay == 1:
                    delay = 0
                else:
                    delay = 1
            if delay == 0 or not is_video:  # allow to rotate 3D canvas while on pause
                key = 0
                while (key != p_code
                    and key != esc_code
                    and key != space_code):
                    plotter.plot(canvas_3d, poses_3d, edges)
                    cv2.imshow(canvas_3d_window_name, canvas_3d)
                    key = cv2.waitKey(33)
                if key == esc_code:
                    break
                else:
                    delay = 1

        #for func_name, args, result in results:
            #result = result.result()
            #args = ', '.join(str(arg) for arg in args)
            #print('{}({}) = {}'.format(func_name, args, result))
from argparse import ArgumentParser
import os
import time
import json
import multiprocessing

import cv2
import numpy as np
import norfair
from norfair import Detection, Tracker
from modules.input_reader import VideoReader, ImageReader
from modules.draw import Plotter3d, draw_poses
#from modules.parse_poses import parse_poses

from modules.myconst import *
import myutils as mu

#define Norfair thresholds and keypoints distance function
detection_threshold = 0.01
distance_threshold = 0.6
keypoint_dist_threshold = 30   #image height/25
def keypoints_distance(detected_pose, tracked_pose):
    distances = np.linalg.norm(detected_pose.points - tracked_pose.estimate, axis=1)
    match_num = np.count_nonzero(
        (distances < keypoint_dist_threshold)
        * (detected_pose.scores > detection_threshold)
        * (tracked_pose.last_detection.scores > detection_threshold)
    )

    return 1 / (1 + match_num)


# python demo_unitycam.py --model human-pose-estimation-3d.xml --device CPU --use-openvino --height-size 256 --cam_id 2 --cam_width 640 --cam_height 480
# python demo_unitycam.py --model human-pose-estimation-3d.pth --height-size 256 --cam_id 2 --cam_width 640 --cam_height 480
if __name__ == '__main__':
    parser = ArgumentParser(description='Lightweight 3D human pose estimation demo. '
                                        'Press esc to exit, "p" to (un)pause video or process next image.')
    parser.add_argument('-m', '--model',
                        help='Required. Path to checkpoint with a trained model '
                             '(or an .xml file in case of OpenVINO inference).',
                        type=str, required=True)
    parser.add_argument('--video', help='Optional. Path to video file.', type=str, default='')
    parser.add_argument('--cam_id', type=int, default=1)
    parser.add_argument('--cam_width', help='Optional. camera width.', type=int, default=640)
    parser.add_argument('--cam_height', help='Optional. camera height.', type=int, default=480)    
    parser.add_argument('--mirror_flip', help='Optional. Do mirror flipping on the image frame.',
                        action='store_true')
    parser.add_argument('-d', '--device', help='Optional. The target device to infer on: CPU or GPU (default).',
                        type=str, default='GPU')
    parser.add_argument('--use-openvino',
                        help='Optional. Run network with OpenVINO as inference engine, support CPU, GPU, FPGA, HDDL or MYRIAD.',
                        action='store_true')
    parser.add_argument('--use-tensorrt', help='Optional. Run network with TensorRT as inference engine.',
                        action='store_true')
    parser.add_argument('--height-size', help='Optional. Network input layer height size.', type=int, default=256)
    parser.add_argument('--extrinsics-path',
                        help='Optional. Path to file with camera extrinsics.',
                        type=str, default=None)
    parser.add_argument('--fx', type=np.float32, default=-1, help='Optional. Camera focal length.')
    parser.add_argument('--skipframes', type=int, default=1, help='Optional. Skip frames to speed up the detection.')
    args = parser.parse_args()

    if args.video == '' and args.cam_id == '':
        raise ValueError('Either --video or --cam_id has to be provided')
    stride = 8
    if args.use_openvino:
        from modules.inference_engine_openvino import InferenceEngineOpenVINO
        net = InferenceEngineOpenVINO(args.model, args.device)
    else:
        from modules.inference_engine_pytorch import InferenceEnginePyTorch
        net = InferenceEnginePyTorch(args.model, args.device, use_tensorrt=args.use_tensorrt)

    file_path = args.extrinsics_path
    if file_path is None:
        file_path = os.path.join('data', 'extrinsics.json')
    with open(file_path, 'r') as f:
        extrinsics = json.load(f)
    R = np.array(extrinsics['R'], dtype=np.float32)
    t = np.array(extrinsics['t'], dtype=np.float32)
    base_height = args.height_size
    fx = args.fx

    mirror_flip = args.mirror_flip
    if args.skipframes == '':
        raise ValueError('--skipframes has to be provided')
    else:
        skip_frames = args.skipframes

    #setup the video capture stream
    is_video = True
    if args.video != '':
        cap = cv2.VideoCapture(args.video)
        if (cap.isOpened()== False): 
            raise IOError('Video {} cannot be opened'.format(args.video))
        else:
            frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    else:
        cap = cv2.VideoCapture(args.cam_id, cv2.CAP_DSHOW)
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, args.cam_width)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, args.cam_height)
        cap.set(cv2.CAP_PROP_FPS, 30)            
        # Check if camera opened successfully
        if (cap.isOpened()== False): 
            raise IOError('Video {} cannot be opened'.format(args.cam_id))
        else:
            frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    if not cv2.useOptimized():
        cv2.setUseOptimized(True)

    #setup the canvas_3d window to show skeletons
    canvas_3d = np.zeros((frame_height, frame_width, 3), dtype=np.uint8)
    plotter = Plotter3d(canvas_3d.shape[:2])
    canvas_3d_window_name = 'PoseCam 3D'
    cv2.namedWindow(canvas_3d_window_name)
    cv2.setMouseCallback(canvas_3d_window_name, Plotter3d.mouse_callback)

    # setup Norfair tracker
    tracker = Tracker(
        distance_function=keypoints_distance,
        distance_threshold=distance_threshold,
        detection_threshold=detection_threshold,
        hit_inertia_min=5,
        hit_inertia_max=15,
        point_transience=4,
    )

    #use panopatic order, all 19 keypoints, ignore the last element in pose data
    kpts_list = KPTS_PANOPATIC_IDX
    #kpts_list = [0, 1, 2, 3, 4, 5]      #use panopatic order, just head & neck
    num_kpts = len(kpts_list) // 3

    delay = 1
    esc_code = 27
    p_code = 112
    space_code = 32
    num_poses = 0
    pin = mu.Params4poses([], 0, RESIZE_SQUARE_PADDING, base_height, stride, net, fx, R, t, is_video)
    is_tracked = False
    fps = mu.Framerate()
    frame_count = 0
    tic_start = cv2.getTickCount()    
    #tasks = multiprocessing.Queue()
    #tasks.put((fib, 8))
    #tasks.put((ackermann, 2, 4))
    #tasks.put((fib, 18))
    #tasks.put((ackermann, 3, 1))
    #tasks.put((fib, 28))
    #tasks.put((ackermann, 3, 4))
    #tasks.put((fib, 34))
    #results = []
    #with multiprocessing.Pool(4) as pool:        
    if 1 == 1:
        while (cap.isOpened()):
            tic0 = cv2.getTickCount()                            
            res, frame = cap.read()
            if not res:
                break
            if mirror_flip:
                frame = cv2.flip(frame, 1)
            fps.video = cv2.getTickFrequency() / (cv2.getTickCount() - tic0)            
            
            tic1 = cv2.getTickCount()            
            if frame_count % skip_frames == 0:
            #if 1 == 1:
                pin.frame_no = frame_count
                pin.frame = frame
                #task = tasks.get()
                #func, *args = task
                #result = pool.apply_async(func, *args) 
                #results.append((func.__name__, args, result))
                pout = mu.get_poses(pin)        
                if len(pout.poses_2d):
                    poses_2d = pout.poses_2d
                    poses_3d = pout.poses_3d
                    poses_id = pout.poses_id
                    poses_id_last = pout.poses_id_last
                is_tracked = False
                fps.openpose = cv2.getTickFrequency() / (cv2.getTickCount() - tic1)                                        
            else:
                if len(pout.poses_2d):
                    poses_2d = pout.poses_2d
                    poses_3d = pout.poses_3d
                    poses_id = pout.poses_id
                    poses_id_last = pout.poses_id_last
                is_tracked = True
                fps.tracking = cv2.getTickFrequency() / (cv2.getTickCount() - tic1)                        

            frame_count += 1
            fps.processing = frame_count / ((cv2.getTickCount() - tic_start) / cv2.getTickFrequency())                    

            edges = []
            if len(poses_3d) > 0:
                edges = (Plotter3d.SKELETON_EDGES + NUMKPTS_PANOPATIC * np.arange(poses_3d.shape[0]).reshape((-1, 1, 1))).reshape((-1, 2))
                plotter.plot(canvas_3d, poses_3d, edges)
            cv2.imshow(canvas_3d_window_name, canvas_3d)
            if len(poses_2d) > 0:                
                draw_poses(frame, poses_2d)                

            #norfair.draw_points(frame, detections)
            #norfair.draw_tracked_objects(frame, tracked_objects)
            #norfair.draw_debug_metrics(frame, tracked_objects) 
            #norfair.print_objects_as_table(tracked_objects)                                       
            #draw_poses(frame, poses_2d)        
            #if not is_tracked:
                #if len(poses_2d) > 0:                
                    #draw_poses(frame, poses_2d)                
            #else:
                #if len(tracked_objects) > 0:
                #    norfair.draw_tracked_objects(frame, tracked_objects)
                #if len(poses_2d_tracked) > 0:
                    #draw_poses(frame, poses_2d_tracked, (128, 128, 0), 1, 5, (0, 0, 255), -1)
            if is_video:
                if len(poses_id)>0 and len(poses_id_last)>0 and \
                    len(poses_id) == len(poses_id_last):
                    for pose_idx in range(len(poses_2d)):        
                        cv2.putText(frame, 'id:{0:3d}'.format(min(int(poses_id[pose_idx]),int(poses_id_last[pose_idx]))), \
                            (max(int(poses_2d[pose_idx, 3]), 20), max(20,int(poses_2d[pose_idx, 4])-40)), \
                            cv2.FONT_HERSHEY_COMPLEX, 0.6, (255, 0, 0), 1)
            
            cv2.putText(frame, 'FPS-video: {}'.format(int(fps.video)), (20, 20), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 255), 1)
            cv2.putText(frame, 'FPS-openpose: {}'.format(int(fps.openpose)), (20, 45), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 255), 1)
            cv2.putText(frame, 'FPS-norfair: {}'.format(int(fps.norfair)), (20, 70), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 255), 1)
            cv2.putText(frame, 'FPS-tracking: {}'.format(int(fps.tracking)), (20, 95), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 255), 1)        
            cv2.putText(frame, 'FPS-processing: {}'.format(int(fps.processing)), (20, 120), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 255), 1)        
            cv2.imshow('PoseCam View', frame)

            key = cv2.waitKey(delay)
            if key == esc_code:
                break
            if key == p_code:
                if delay == 1:
                    delay = 0
                else:
                    delay = 1
            if delay == 0 or not is_video:  # allow to rotate 3D canvas while on pause
                key = 0
                while (key != p_code
                    and key != esc_code
                    and key != space_code):
                    plotter.plot(canvas_3d, poses_3d, edges)
                    cv2.imshow(canvas_3d_window_name, canvas_3d)
                    key = cv2.waitKey(33)
                if key == esc_code:
                    break
                else:
                    delay = 1

        #for func_name, args, result in results:
            #result = result.result()
            #args = ', '.join(str(arg) for arg in args)
            #print('{}({}) = {}'.format(func_name, args, result))
#from modules.parse_poses import parse_poses #define Norfair thresholds and keypoints distance function #image height/25 # python demo_unitycam.py --model human-pose-estimation-3d.xml --device CPU --use-openvino --height-size 256 --cam_id 2 --cam_width 640 --cam_height 480 # python demo_unitycam.py --model human-pose-estimation-3d.pth --height-size 256 --cam_id 2 --cam_width 640 --cam_height 480 #setup the video capture stream # Check if camera opened successfully #setup the canvas_3d window to show skeletons # setup Norfair tracker #use panopatic order, all 19 keypoints, ignore the last element in pose data #kpts_list = [0, 1, 2, 3, 4, 5]      #use panopatic order, just head & neck #tasks = multiprocessing.Queue() #tasks.put((fib, 8)) #tasks.put((ackermann, 2, 4)) #tasks.put((fib, 18)) #tasks.put((ackermann, 3, 1)) #tasks.put((fib, 28)) #tasks.put((ackermann, 3, 4)) #tasks.put((fib, 34)) #results = [] #with multiprocessing.Pool(4) as pool: #if 1 == 1: #task = tasks.get() #func, *args = task #result = pool.apply_async(func, *args) #results.append((func.__name__, args, result)) #norfair.draw_points(frame, detections) #norfair.draw_tracked_objects(frame, tracked_objects) #norfair.draw_debug_metrics(frame, tracked_objects) #norfair.print_objects_as_table(tracked_objects) #draw_poses(frame, poses_2d) #if not is_tracked: #if len(poses_2d) > 0: #draw_poses(frame, poses_2d) #else: #if len(tracked_objects) > 0: #    norfair.draw_tracked_objects(frame, tracked_objects) #if len(poses_2d_tracked) > 0: #draw_poses(frame, poses_2d_tracked, (128, 128, 0), 1, 5, (0, 0, 255), -1) # allow to rotate 3D canvas while on pause #for func_name, args, result in results: #result = result.result() #args = ', '.join(str(arg) for arg in args) #print('{}({}) = {}'.format(func_name, args, result))