摄像头 外参数标定

1)标定摄像头内参得到: mtx dist
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(world_position, image_position, gray.shape[::-1], None, None)


棋盘格标定内参

2)通过4个点坐标对儿,计算摄像头地板画面到2D平面图的透视变换矩阵:
M = np.matrix(cv2.getPerspectiveTransform(c.pts_cam, c.pts_2d_world))



image.png

用 out_img = cv2.warpPerspective(img_cam, M, (w, h)) 验证M矩阵准不准


image.png

3)在2D平面图上构造方格点阵,并用 M 的逆矩阵投影在摄像头画面上。
chessboard_cam = cv2.perspectiveTransform(chessboard_2dmap, M.I)
list_cam_chessboard = chessboard_cam.reshape(-1, 2).tolist()


2D平面图上,构造方格点阵

4)在投影到摄像头画面的点list_cam_chessboard中,挑选画面中可见的,并且去掉在画面边缘的点,建立一个点集,并配合找到这些点在2D平面图的坐标,增加一个z=0的维度,转变成3D世界坐标系的三维坐标。 得到:world_points 和 exact_points

    world_points = []
    exact_points = []
    w = _cam.img.shape[1]
    h = _cam.img.shape[0]
    for i, cam_pt in enumerate(list_cam_chessboard):
        if cam_pt[0] > 100 and cam_pt[0] < w-100 and cam_pt[1] > 100 and cam_pt[1] < h-100:
            exact_points.append(cam_pt)
            world_points.append([*list_world_chessboard[i], 0])
投影点阵,粉色是选中的点

5)用 solvePnPRansac() 计算摄像头外参 rvet, tvec
ok, rvec, tvec, inliers = cv2.solvePnPRansac(world_points, exact_points, mtx, dist)

6)用外参数计算 摄像头坐标系到世界坐标系的RT矩阵
RT = CamTools.RT(tuple(rvec.reshape(-1)), tuple(tvec.reshape(-1)))
RT = np.matrix(RT)

7)用 RT 矩阵,把相机坐标系原点,转到世界坐标系表示, 这样就知道摄像头在世界坐标系的什么位置了。有了RT矩阵,世界坐标系和摄像头坐标系什么都可以转了。这里就不多说了。

举例用RT矩阵计算摄像头在3D世界坐标系中的位置,忽略高度,画在2D平面图上。
cam_origin = np.array([0, 0, 0, 1])
cam_origin_in_world = np.dot(RT.I, cam_origin.T)
print("cc in world:", cam_origin_in_world.tolist())


红色是反算的摄像头位置,朝向、俯角也是已知的,偷懒就不画了

8)


image.png

推荐阅读更多精彩内容