text: import math, logging, numpy as np
  from tqdm import tqdm
  
  
  def rotation_matrix(axis, theta):
      if np.abs(axis).sum() < 1e-6 or np.abs(theta) < 1e-6:
          return np.eye(3)
      axis = np.asarray(axis)
      axis = axis / math.sqrt(np.dot(axis, axis))
      a = math.cos(theta / 2.0)
      b, c, d = -axis * math.sin(theta / 2.0)
      aa, bb, cc, dd = a * a, b * b, c * c, d * d
      bc, ad, ac, ab, bd, cd = b * c, a * d, a * c, a * b, b * d, c * d
      return np.array([[aa + bb - cc - dd, 2 * (bc + ad), 2 * (bd - ac)],
                       [2 * (bc - ad), aa + cc - bb - dd, 2 * (cd + ab)],
                       [2 * (bd + ac), 2 * (cd - ab), aa + dd - bb - cc]])
  
  
  def angle_between(v1, v2):
      if np.abs(v1).sum() < 1e-6 or np.abs(v2).sum() < 1e-6:
          return 0
      v1_u = v1 / np.linalg.norm(v1)  # unit_vector
      v2_u = v2 / np.linalg.norm(v2)  # unit_vector
      return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))
  
  
  def pre_normalization(data, progress_bar=True, zaxis=[0, 1], xaxis=[8, 4]):
      N, C, T, V, M = data.shape
      s = np.transpose(data, [0, 4, 2, 3, 1])  # N, C, T, V, M  to  N, M, T, V, C
  
      logging.info('Pad the null frames with the previous frames')
      items = tqdm(s, dynamic_ncols=True) if progress_bar else s
      for i_s, skeleton in enumerate(items):  # pad
          if skeleton.sum() == 0:
              logging.info('Sample {:d} has no skeleton'.format(i_s))
          for i_p, person in enumerate(skeleton):
              if person.sum() == 0:
                  continue
              if person[0].sum() == 0:
                  index = (person.sum(-1).sum(-1) != 0)
                  tmp = person[index].copy()
                  person *= 0
                  person[:len(tmp)] = tmp
              for i_f, frame in enumerate(person):
                  if frame.sum() == 0:
                      if person[i_f:].sum() == 0:
                          rest = len(person) - i_f
                          num = int(np.ceil(rest / i_f))
                          pad = np.concatenate([person[0:i_f] for _ in range(num)], 0)[:rest]
                          s[i_s, i_p, i_f:] = pad
                          break
  
      logging.info('Sub the center joint #1 (spine joint in ntu and neck joint in kinetics)')
      items = tqdm(s, dynamic_ncols=True) if progress_bar else s
      for i_s, skeleton in enumerate(items):
          if skeleton.sum() == 0:
              continue
          main_body_center = skeleton[0][:, 1:2, :].copy()
          for i_p, person in enumerate(skeleton):
              if person.sum() == 0:
                  continue
              mask = (person.sum(-1) != 0).reshape(T, V, 1)
              s[i_s, i_p] = (s[i_s, i_p] - main_body_center) * mask
  
      logging.info('Parallel the bone between hip(jpt 0) and spine(jpt 1) of the first person to the z axis')
      items = tqdm(s, dynamic_ncols=True) if progress_bar else s
      for i_s, skeleton in enumerate(items):
          if skeleton.sum() == 0:
              continue
          joint_bottom = skeleton[0, 0, zaxis[0]]
          joint_top = skeleton[0, 0, zaxis[1]]
          axis = np.cross(joint_top - joint_bottom, [0, 0, 1])
          angle = angle_between(joint_top - joint_bottom, [0, 0, 1])
          matrix_z = rotation_matrix(axis, angle)
          for i_p, person in enumerate(skeleton):
              if person.sum() == 0:
                  continue
              for i_f, frame in enumerate(person):
                  if frame.sum() == 0:
                      continue
                  for i_j, joint in enumerate(frame):
                      s[i_s, i_p, i_f, i_j] = np.dot(matrix_z, joint)
  
      logging.info('Parallel the bone between right shoulder(jpt 8) and left shoulder(jpt 4) of the first person to the x axis')
      items = tqdm(s, dynamic_ncols=True) if progress_bar else s
      for i_s, skeleton in enumerate(items):
          if skeleton.sum() == 0:
              continue
          joint_rshoulder = skeleton[0, 0, xaxis[0]]
          joint_lshoulder = skeleton[0, 0, xaxis[1]]
          axis = np.cross(joint_rshoulder - joint_lshoulder, [1, 0, 0])
          angle = angle_between(joint_rshoulder - joint_lshoulder, [1, 0, 0])
          matrix_x = rotation_matrix(axis, angle)
          for i_p, person in enumerate(skeleton):
              if person.sum() == 0:
                  continue
              for i_f, frame in enumerate(person):
                  if frame.sum() == 0:
                      continue
                  for i_j, joint in enumerate(frame):
                      s[i_s, i_p, i_f, i_j] = np.dot(matrix_x, joint)
  
      data = np.transpose(s, [0, 4, 2, 3, 1])
      return data
  