text: ######################################################################
  # Title : MediaPipe Holistic for webcam input
  # Project : Wallbo
  ######################################################################
  # File : holistic_webcam-input.py
  # Author : Kaichun Hu
  # Created : crtime: 0x60cca448:723ac010 -- Fri Jun 18 14:48:56 2021
  # Last modified : Mon 12 Jul 2021 16∶27∶47 BST
  ######################################################################
  # Description :
  # take webcam as camera input and apply mediapipe holistic
  # and output joint point to JSON format
  #
  # Keyboard short in PyCharm:
  # Auto-format: Ctrl + Alt + l
  # Run: Shift + Alt + F10
  # Stop: Esc
  ######################################################################
  
  import cv2
  import mediapipe as mp
  import copy
  import json
  
  from utils import CvFpsCalc
  
  mp_drawing = mp.solutions.drawing_utils
  mp_holistic = mp.solutions.holistic
  
  # For webcam input:
  # cap = cv2.VideoCapture(0) -> build in webcam as default input
  # cap = cv2.VideoCapture(2) -> USB camera as default input
  cap = cv2.VideoCapture(2)
  with mp_holistic.Holistic(
          min_detection_confidence=0.5,
          min_tracking_confidence=0.5) as holistic:
      while cap.isOpened():
          success, image = cap.read()
          if not success:
              print("Ignoring empty camera frame.")
              # If loading a video, use 'break' instead of 'continue'.
              continue
  
          #################################################################### Draw frames per second
          cvFpsCalc = CvFpsCalc(buffer_len=10)
          display_fps = cvFpsCalc.get()
  
          # Flip the image horizontally for a later selfie-view display, and convert
          # the BGR image to RGB.
          image = cv2.cvtColor(cv2.flip(image, 1), cv2.COLOR_BGR2RGB)
  
          #################################################################### Draw frames per second
          debug_image = copy.deepcopy(image)
  
          # To improve performance, optionally mark the image as not writeable to
          # pass by reference.
          debug_image.flags.writeable = False
          results = holistic.process(debug_image)
  
          # Draw landmark annotation on the image.
          debug_image.flags.writeable = True
          debug_image = cv2.cvtColor(debug_image, cv2.COLOR_RGB2BGR)
          mp_drawing.draw_landmarks(
              debug_image, results.face_landmarks, mp_holistic.FACE_CONNECTIONS)
          mp_drawing.draw_landmarks(
              debug_image, results.left_hand_landmarks, mp_holistic.HAND_CONNECTIONS)
          mp_drawing.draw_landmarks(
              debug_image, results.right_hand_landmarks, mp_holistic.HAND_CONNECTIONS)
          mp_drawing.draw_landmarks(
              debug_image, results.pose_landmarks, mp_holistic.POSE_CONNECTIONS)
  
          #################################################################### Draw frames per second
          # https: // www.geeksforgeeks.org / python - opencv - cv2 - puttext - method /
          cv2.putText(debug_image, "FPS:" + str(display_fps), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2,
                      cv2.LINE_AA)
  
          # Title of the video window
          cv2.imshow('MediaPipe Holistic video input', debug_image)
  
  
          # Output to JSON format
          jointpoints = {}
          jointpoints['Person ID'] = []
          for data_point in results.pose_landmarks.landmark:
              jointpoints['Person ID'].append({
                  'x': data_point.x,
                  'y': data_point.y,
                  'z': data_point.z,
                  # z: Should be discarded as currently the model is not fully trained
                  # to predict depth, but this is something on the roadmap.
  
                  'visibility': data_point.visibility,
              })
          # Output json data to a file
          with open('person_webcam.txt', 'w') as json_file:
              json.dump(jointpoints, json_file)
  
          if cv2.waitKey(5) & 0xFF == 27:
              break
  cap.release()
  