相机坐标系转换总结

  • 坐标系示意图

    • 相机坐标系转换总结_第1张图片
  • 像素坐标系与图像坐标系

    • 像素坐标轴为uv,图像坐标轴为xy
    • 参数为:dx, dy, u0, v0
    • 相机坐标系转换总结_第2张图片 相机坐标系转换总结_第3张图片 相机坐标系转换总结_第4张图片
  • 图像坐标系与相机坐标系

    • 相机坐标系转换总结_第5张图片
  • 相机坐标系与世界坐标系

    • 相机坐标系转换总结_第6张图片
    • 旋转矩阵R
  • 像素坐标系映射到世界坐标系

    • 相机坐标系转换总结_第7张图片
    • 相机坐标系转换总结_第8张图片 相机坐标系转换总结_第9张图片 
  • 各坐标系转换代码实现

    • import sys
      import os
      sys.path.append(os.getcwd())
      import numpy as np
      
      
      camera_intrinsic = {
          # R,旋转矩阵
          "R": [[-0.91536173, 0.40180837, 0.02574754],
                [0.05154812, 0.18037357, -0.98224649],
                [-0.39931903, -0.89778361, -0.18581953]],
          # t,平移向量
          "T": [1841.10702775, 4955.28462345, 1563.4453959],
          # 焦距,f/dx, f/dy
          "f": [1145.04940459, 1143.78109572],
          # principal point,主点,主轴与像平面的交点
          "c": [512.54150496, 515.45148698]
      
      }
      
      
      class CoordinateConvert:
          @staticmethod
          def convert_wc_to_cc(joint_world):  # joint_world: n*3
              """
              世界坐标系 -> 相机坐标系: R * pt + T
              :return:
              """
              joint_world = np.asarray(joint_world)
              R = np.asarray(camera_intrinsic["R"])
              T = np.asarray(camera_intrinsic["T"])
              joint_num = len(joint_world)
              # 世界坐标系 -> 相机坐标系
              # [R|t] world coords -> camera coords
              joint_cam = np.zeros((joint_num, 3))  # joint camera
              for i in range(joint_num):  # joint i
                  joint_cam[i] = np.dot(R, joint_world[i]) + T  # R * pt + T
              return joint_cam
      
          @staticmethod
          def __cam2pixel(cam_coord, f, c):
              """
              相机坐标系 -> 像素坐标系: (f / dx) * (X / Z) = f * (X / Z) / dx
              cx,ppx=260.166; cy,ppy=205.197; fx=367.535; fy=367.535
              将从3D(X,Y,Z)映射到2D像素坐标P(u,v)计算公式为:
              u = X * fx / Z + cx
              v = Y * fy / Z + cy
              D(v,u) = Z / Alpha
              =====================================================
              camera_matrix = [[428.30114, 0.,   316.41648],
                              [   0.,    427.00564, 218.34591],
                              [   0.,      0.,    1.]])
              fx = camera_intrinsic[0, 0]
              fy = camera_intrinsic[1, 1]
              cx = camera_intrinsic[0, 2]
              cy = camera_intrinsic[1, 2]
              =====================================================
              :param cam_coord:
              :param f: [fx,fy]
              :param c: [cx,cy]
              :return:
              """
              # 等价于:(f / dx) * (X / Z) = f * (X / Z) / dx
              # 三角变换, / dx, + center_x
              u = cam_coord[..., 0] / cam_coord[..., 2] * f[0] + c[0]
              v = cam_coord[..., 1] / cam_coord[..., 2] * f[1] + c[1]
              d = cam_coord[..., 2]
              return u, v, d
      
          @staticmethod
          def convert_cc_to_ic(joint_cam):
              """
              相机坐标系 -> 像素坐标系
              :param joint_cam:
              :return:
              """
              # 相机坐标系 -> 像素坐标系,并 get relative depth
              # Subtract center depth
              # 选择 Pelvis骨盆 所在位置作为相机中心,后面用之求relative depth
              root_idx = 0
              center_cam = joint_cam[root_idx]  # (x,y,z) mm
              joint_num = len(joint_cam)
              f = camera_intrinsic["f"]
              c = camera_intrinsic["c"]
              # joint image,像素坐标系,Depth 为相对深度 mm
              joint_img = np.zeros((joint_num, 3))
              joint_img[:, 0], joint_img[:, 1], joint_img[:, 2] = CoordinateConvert.__cam2pixel(joint_cam, f, c)  # x,y
              joint_img[:, 2] = joint_img[:, 2] - center_cam[2]  # z: 相对图片某个点的深度信息
              return joint_img
      
      
      if __name__ == "__main__":
          joint_world = [[-91.679, 154.404, 907.261],
                         [-223.23566, 163.80551, 890.5342],
                         [-188.4703, 14.077106, 475.1688],
                         [-261.84055, 186.55286, 61.438915],
                         [39.877888, 145.00247, 923.98785],
                         [-11.675994, 160.89919, 484.39148],
                         [-51.550297, 220.14624, 35.834396],
                         [-132.34781, 215.73018, 1128.8396],
                         [-97.1674, 202.34435, 1383.1466],
                         [-112.97073, 127.96946, 1477.4457],
                         [-120.03289, 190.96477, 1573.4],
                         [25.895456, 192.35947, 1296.1571],
                         [107.10581, 116.050285, 1040.5062],
                         [129.8381, -48.024918, 850.94806],
                         [-230.36955, 203.17923, 1311.9639],
                         [-315.40536, 164.55284, 1049.1747],
                         [-350.77136, 43.442127, 831.3473],
                         [-102.237045, 197.76935, 1304.0605]]
          joint_world = np.asarray(joint_world)
          # show in 世界坐标系
          coordinate_convert = CoordinateConvert()
          # show in 相机坐标系
          joint_cam = coordinate_convert.convert_wc_to_cc(joint_world)
          joint_img = coordinate_convert.convert_cc_to_ic(joint_cam)

  • 内参外参总结

    • 相机的内参数是六个分别为:1/dx、1/dy、r、u0、v0、f。
      • r表示径向畸变量级,r为负值,畸变为桶型畸变,r为正值,畸变为枕型畸变,初始值为0。
      • dx、dy表示图像传感器上水平和垂直方向上相邻像素之间的距离。
      • u0,v0表示图像坐标系原点在像素坐标系中位置。
    • opencv1里说的内参数是4个其为fx、fy、u0、v0。(fx=f/dx、fy=f/dy、r=0)
    • 畸变参数:(k1、k2、p1、p2、k3)
  • 求取内参外参方法

    • 单目相机标定——相机外参估计(二)_黑色五叶草的博客-CSDN博客_相机外参标定
  • OpenCV SolvePnP原理解释

    • Opencv:SolvePNP - 简书

你可能感兴趣的:(工具类,摄像头,坐标系转换,相机)