从单个 2D 视频重建飞行 object 的 3D 轨迹

Reconstructing a flying object's 3D trajectory off a single 2D-video

我正在尝试重建篮球的 3D 轨迹,仅使用广播信号。 为此,我必须计算单应矩阵,因此在每一帧中我都成功地跟踪了球,并且在 "real world" 中已知它们位置的 6 个点(球场本身有 4 个,篮板上有 2 个)如图所示。

利用物理定律,我还估算了每一帧中球的 z-coordinate。

现在我想将球的位置从 2D 像素坐标映射到现实世界。我现在拥有的代码(稍后附上)输入像素位置(u,v)和高度(z)并输出 x,y,z 位置。它适用于球场上的点(意味着 z=0),但是当我需要跟踪空中的东西(球)时,结果就没有意义了。如果有人可以帮助告诉我我需要做什么才能获得映射,我将不胜感激。

# Make empty list for ball's 3D location
ball_3d_location = []
# Fixed things 
size         = frame_list[0].shape
focal_length = size[1]
center       = (size[1]/2, size[0]/2)
camera_matrix= np.array(
                         [[focal_length, 0, center[0]],
                         [0, focal_length, center[1]],
                         [0, 0, 1]], dtype = "double"
                         )
def groundProjectPoint(image_point, z = 0.0):
    camMat = np.asarray(camera_matrix)
    iRot   = np.linalg.inv(rotMat)
    iCam   = np.linalg.inv(camMat)
uvPoint = np.ones((3, 1))

# Image point
uvPoint[0, 0] = image_point[0]
uvPoint[1, 0] = image_point[1]

tempMat = np.matmul(np.matmul(iRot, iCam), uvPoint)
tempMat2 = np.matmul(iRot, translation_vector)

s = (z + tempMat2[2, 0]) / tempMat[2, 0]
wcPoint = np.matmul(iRot, (np.matmul(s * iCam, uvPoint) - translation_vector))

# wcPoint[2] will not be exactly equal to z, but very close to it
assert int(abs(wcPoint[2] - z) * (10 ** 8)) == 0
wcPoint[2] = z

return wcPoint
dist_coeffs = np.zeros((4,1)) # Assuming no lens distortion

# The tracked points coordinates in the "Real World"
model_points = np.array([
(0,1524/2,0),         #Baseline-sideline
(0,-244,0),           #Paint-sideline
(579,-244,0),         #Paint-FT
(579,1524/2,0),       #Sideline-FT
(122,-182.9/2,396.32),#Top Left Backboard
(122,182.9/2,396.32)],dtype=np.float32 #Top Right BackBoard
)
for i,frame in enumerate(bball_frames):
  f             =frame
  #This array has the pixel coordinates of the court & backboard points
  image_points  =np.array([f.baseline_sideline,
  f.paint_sideline,
  f.paint_ft,
  f.sideline_ft,
  f.top_left_backboard,
  f.top_right_backboard],dtype=np.float32)

  (success, rotation_vector, translation_vector) = cv2.solvePnP(model_points, image_points, camera_matrix, dist_coeffs, flags=cv2.SOLVEPNP_ITERATIVE)

  rotMat, _ = cv2.Rodrigues(rotation_vector)
  #We assume we know the ball's height in each frame due to the laws of physics.
  ball_3d_location+=[groundProjectPoint(image_point=ball_2d_location[i],z = ball_height[i])]

编辑:

首先,我想澄清一下参考平面:

  1. 您的视频是 3D 世界的 2D 投影(观看平面),作为垂直于相机镜头中心线的平面。
  2. 投篮弧嵌入一个平面(投篮平面)中,该平面垂直于真实世界 (3D) 地板,由释放点(射手的手)和接触点(篮板)定义。

您在视频中看到的镜头弧线是该镜头平面在观察平面上的投影。

I want to make sure we're clear with respect to your most recent comment: So let's say I can estimate the shooting location on the court (x,y). using the laws of physics I can say where the ball is in each frame (x,y) wise and then from that and the pixel coordinates I can extract the height coordinate?

  1. 您确实可以估计 (x,y) 坐标。但是,我不会将我的方法归因于 "the laws of physics"。我会使用解析几何。
  2. 您可以非常准确地估计出手点(从射手脚的已知 (x, y, 0) 位置)和篮板上的终点(其角已知)的 3D 坐标).
  3. 从这些点中的每一个点到地板 (z=0) 垂下一条垂线。地板上的那条线是弧线到地板的垂直投影——这些是飞行中球的 (x,y) 坐标。
  4. 对于每个视频帧,从球的图像投射垂直线到地板上的那条线... 给你球的 (x,y) 坐标, 物有所值。
  5. 你有视平面、视点(相机)和圆弧平面的定义(方程)。要为每个视频帧确定球的位置,请从视点画一条线,穿过视图平面上的球图像。确定这条线与圆弧平面的交点。 为您提供该帧中球的 3D 坐标。

这是否阐明了有用的攻击路线?