利用opencv对摄像头做3D空间矫正

标准的calibratecamera函数是对下面的方程求解

[u,v,1]=Intrincs*Transform*[x,y,z,1]

u,v,1对应的2D像素坐标,x,y,z,1对应空间坐标,求解的Intrincs是相机的内部参数,可以理解为相机各种焦距的3x3矩阵,Transform是一个旋转+平移的组合矩阵(3x4)

  1. ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)

上边的mtx就是摄像机矩阵对应Intrincs,rvecs是旋转向量,tvecs是平移向量,dist是求解的误差系数
Transform矩阵可以使用罗德里格斯函数+平移向量组成
np.hstack((cv2.Rodrigues(rvecs[i])[0],tvecs[i]))

对于任意的3D空间坐标,可以用opencv的ProjectPoints来求解2D投影坐标
imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
如果dist设为None,那么就跟用Intrincs*Transform算出来的结果是一模一样的。

  1. Lcam=mtx.dot(np.hstack((cv2.Rodrigues(rvecs[i])[0],tvecs[i])))
  2. for j in range(len(objpoints[i])):
  3. chessPoint=np.hstack((objpoints[i][j], 1))
  4. np.reshape(chessPoint, (4,-1))
  5. imgpoints2=Lcam.dot(chessPoint)
  6. imgpoints2/=imgpoints2[2]

标准的矫正函数一般是用findchessboardcorners 获取棋盘角点坐标,但是这个函数有个缺点,就是不能有遮挡。
想要在有遮挡的情况下获取角点位置,最好的库是libcbdetect,基于facebook的算法实现的。