camera.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. # Copyright (c) 2018-present, Facebook, Inc.
  2. # All rights reserved.
  3. #
  4. # This source code is licensed under the license found in the
  5. # LICENSE file in the root directory of this source tree.
  6. #
  7. import numpy as np
  8. import torch
  9. from video_pose.common.utils import wrap
  10. from video_pose.common.quaternion import qrot, qinverse
  11. def normalize_screen_coordinates(X, w, h):
  12. assert X.shape[-1] == 2
  13. # Normalize so that [0, w] is mapped to [-1, 1], while preserving the aspect ratio
  14. return X/w*2 - [1, h/w]
  15. def image_coordinates(X, w, h):
  16. assert X.shape[-1] == 2
  17. # Reverse camera frame normalization
  18. return (X + [1, h/w])*w/2
  19. def world_to_camera(X, R, t):
  20. Rt = wrap(qinverse, R) # Invert rotation
  21. return wrap(qrot, np.tile(Rt, (*X.shape[:-1], 1)), X - t) # Rotate and translate
  22. def camera_to_world(X, R, t):
  23. return wrap(qrot, np.tile(R, (*X.shape[:-1], 1)), X) + t
  24. def project_to_2d(X, camera_params):
  25. """
  26. Project 3D points to 2D using the Human3.6M camera projection function.
  27. This is a differentiable and batched reimplementation of the original MATLAB script.
  28. Arguments:
  29. X -- 3D points in *camera space* to transform (N, *, 3)
  30. camera_params -- intrinsic parameteres (N, 2+2+3+2=9)
  31. """
  32. assert X.shape[-1] == 3
  33. assert len(camera_params.shape) == 2
  34. assert camera_params.shape[-1] == 9
  35. assert X.shape[0] == camera_params.shape[0]
  36. while len(camera_params.shape) < len(X.shape):
  37. camera_params = camera_params.unsqueeze(1)
  38. f = camera_params[..., :2]
  39. c = camera_params[..., 2:4]
  40. k = camera_params[..., 4:7]
  41. p = camera_params[..., 7:]
  42. XX = torch.clamp(X[..., :2] / X[..., 2:], min=-1, max=1)
  43. r2 = torch.sum(XX[..., :2]**2, dim=len(XX.shape)-1, keepdim=True)
  44. radial = 1 + torch.sum(k * torch.cat((r2, r2**2, r2**3), dim=len(r2.shape)-1), dim=len(r2.shape)-1, keepdim=True)
  45. tan = torch.sum(p*XX, dim=len(XX.shape)-1, keepdim=True)
  46. XXX = XX*(radial + tan) + p*r2
  47. return f*XXX + c
  48. def project_to_2d_linear(X, camera_params):
  49. """
  50. Project 3D points to 2D using only linear parameters (focal length and principal point).
  51. Arguments:
  52. X -- 3D points in *camera space* to transform (N, *, 3)
  53. camera_params -- intrinsic parameteres (N, 2+2+3+2=9)
  54. """
  55. assert X.shape[-1] == 3
  56. assert len(camera_params.shape) == 2
  57. assert camera_params.shape[-1] == 9
  58. assert X.shape[0] == camera_params.shape[0]
  59. while len(camera_params.shape) < len(X.shape):
  60. camera_params = camera_params.unsqueeze(1)
  61. f = camera_params[..., :2]
  62. c = camera_params[..., 2:4]
  63. XX = torch.clamp(X[..., :2] / X[..., 2:], min=-1, max=1)
  64. return f*XX + c