解释相对于定义的世界坐标的旋转矩阵
Interpreting the rotation matrix with respect to a defined World coordinates
在下图中,我们看到定义的世界平面坐标 (X,Y,0),其中 Z=0。我们看到的相机正朝着定义的世界平面前进。
世界参考点位于网格 (0,0,0) 的左上角。每两个黄点之间的距离是40厘米
我已经使用棋盘校准了我的相机,然后使用内置函数 cv2.solvePnP 来估计相机的旋转和平移矢量尊重我定义的世界坐标。结果如下:
tvec_cam= [[-5.47884374]
[-3.08581371]
[24.15112048]]
rvec_cam= [[-0.02823308]
[ 0.08623225]
[ 0.01563199]]
根据结果,(tx,ty,tz) 似乎是正确的,因为相机位于 X,Y 世界坐标的负四分之一
但是,我对旋转矢量的解释感到困惑。!
得到的旋转矢量是不是表示相机坐标几乎与世界坐标轴对齐(意思是几乎没有旋转!)?,
如果是,这怎么可能是真的?,因为根据OPENCV的相机坐标,相机的Z轴指向场景(这意味着指向世界平面), X轴指向图像写入(即与X世界轴相反),相机的Y轴指向图像底部(也与Y世界轴相反)
另外,tvec的单位是什么?
注:我已经根据平移向量的结果说明了定义的世界坐标轴的方向(tx和ty均为负数)
我用于计算旋转和平移向量的代码如下所示:
import cv2 as cv
import numpy as np
WPoints = np.zeros((9*3,3), np.float64)
WPoints[:,:2] = np.mgrid[0:9,0:3].T.reshape(-1,2)*0.4
imPoints=np.array([[20,143],[90,143],[161,143],[231,144],[303,144],
[374,144],[446,145],[516,146],[587,147],[18,214],[88,214]
,[159,215],[230,215],[302,216],[374,216],[446,216]
,[517,217],[588,217],[16,285],[87,285],[158,286],[229,287],
[301,288]
,[374,289],[446,289],[518,289],[589,289]],dtype=np.float64)
#load the rotation matrix [[4.38073915e+03 0.00000000e+00 1.00593352e+03]
# [0.00000000e+00 4.37829226e+03 6.97020491e+02]
# [0.00000000e+00 0.00000000e+00 1.00000000e+00]]
with np.load('parameters_cam1.npz') as X:
mtx, dist, _, _ = [X[i] for i in ('mtx','dist','rvecs','tvecs')]
ret,rvecs, tvecs = cv.solvePnP(WPoints, imPoints, mtx, dist)
np.savez("extrincic_camera1.npz",rvecs=rvecs,tvecs=tvecs)
print(tvecs)
print(rvecs)
cv.destroyAllWindows()
估计内在函数的代码如下所示
import numpy as np
import cv2
import glob
import argparse
import pathlib
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--path", required=True, help="path to images folder")
ap.add_argument("-e", "--file_extension", required=False, default=".jpg",
help="extension of images")
args = vars(ap.parse_args())
path = args["path"] + "*" + args["file_extension"]
# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (0.03,0,0), (0.06,0,0) ....,
#(0.18,0.12,0)
objp = np.zeros((5*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:5].T.reshape(-1,2)*0.03
#print(objp)
# Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.
#images = glob.glob('left/*.jpg') #read a series of images
images = glob.glob(path)
path = 'foundContours'
#pathlib.Path(path).mkdir(parents=True, exist_ok=True)
found = 0
for fname in images:
img = cv2.imread(fname) # Capture frame-by-frame
#print(images[im_i])
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv2.findChessboardCorners(gray, (7,5), None)
# print(corners)
# If found, add object points, image points (after refining them)
if ret == True:
print('true')
objpoints.append(objp) # Certainly, every loop objp is the same, in 3D.
#print('obj_point',objpoints)
corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
# print(corners2)
imgpoints.append(corners2)
print(imgpoints)
print('first_point',imgpoints[0])
#print(imgpoints.shape())
# Draw and display the corners
img = cv2.drawChessboardCorners(img, (7,5), corners2, ret)
found += 1
cv2.imshow('img', img)
cv2.waitKey(1000)
# if you want to save images with detected corners
# uncomment following 2 lines and lines 5, 18 and 19
image_name = path + '/calibresult' + str(found) + '.jpg'
cv2.imwrite(image_name, img)
print("Number of images used for calibration: ", found)
# When everything done, release the capture
# cap.release()
cv2.destroyAllWindows()
#calibration
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints,
gray.shape[::-1],None,None)
#save parameters needed in undistortion
np.savez("parameters_cam1.npz",mtx=mtx,dist=dist,rvecs=rvecs,tvecs=tvecs)
np.savez("points_cam1.npz",objpoints=objpoints,imgpoints=imgpoints)
print ("Camera Matrix = |fx 0 cx|")
print (" | 0 fy cy|")
print (" | 0 0 1|")
print (mtx)
print('distortion coefficients=\n', dist)
print('rotation vector for each image=', *rvecs, sep = "\n")
print('translation vector for each image=', *tvecs, sep= "\n")
希望你能帮助我理解这一点
提前致谢
首先,tvec是Axis-angle中的一个表示(https://en.wikipedia.org/wiki/Axis%E2%80%93angle_representation)。
您可以使用cv2.Rodrigues() 获取旋转矩阵。对于你的数据,我得到了差不多的身份:
[[ 0.99616253 -0.01682635 0.08588995]
[ 0.01439347 0.99947963 0.02886672]
[-0.08633098 -0.02751969 0.99588635]]
现在,根据你图片中x和y的方向,z-axis指向向下(仔细应用right-hand规则)。这就解释了为什么相机的 z-axis 几乎与你的世界参考系的 z-axis 对齐。
编辑:根据您发布的代码进一步挖掘:
WPoints = np.zeros((9*3,3), np.float64)
WPoints[:,:2] = np.mgrid[0:9,0:3].T.reshape(-1,2)*0.4
X 和 Y 的值都是正数,分别向右和向下递增,所以你确实使用了通常的约定。 你实际上是在使用 X 和 Y 分别向右和向下递增,错误的只是你在图片中画的箭头。
编辑关于平移向量的解释:在OpenCV约定中,局部相机参考系中的点是从世界参考系中的点获得的,如下所示:
|x_cam| |x_world|
|y_cam| = Rmat * |y_world| + tvec
|z_cam| |z_world|
根据这个约定,tvec 是相机参考系中世界原点的位置。更容易解释的是相机原点在世界参考系中的位置,可以得到:
cam_center = -(tvec * R_inv)
其中R_inv是旋转矩阵的逆矩阵。这里的旋转矩阵几乎是恒等式,所以快速近似是 -tvec,即 (5.4, 3.1, -24.1).
在下图中,我们看到定义的世界平面坐标 (X,Y,0),其中 Z=0。我们看到的相机正朝着定义的世界平面前进。
世界参考点位于网格 (0,0,0) 的左上角。每两个黄点之间的距离是40厘米
我已经使用棋盘校准了我的相机,然后使用内置函数 cv2.solvePnP 来估计相机的旋转和平移矢量尊重我定义的世界坐标。结果如下:
tvec_cam= [[-5.47884374]
[-3.08581371]
[24.15112048]]
rvec_cam= [[-0.02823308]
[ 0.08623225]
[ 0.01563199]]
根据结果,(tx,ty,tz) 似乎是正确的,因为相机位于 X,Y 世界坐标的负四分之一
但是,我对旋转矢量的解释感到困惑。!
得到的旋转矢量是不是表示相机坐标几乎与世界坐标轴对齐(意思是几乎没有旋转!)?,
如果是,这怎么可能是真的?,因为根据OPENCV的相机坐标,相机的Z轴指向场景(这意味着指向世界平面), X轴指向图像写入(即与X世界轴相反),相机的Y轴指向图像底部(也与Y世界轴相反)
另外,tvec的单位是什么?
注:我已经根据平移向量的结果说明了定义的世界坐标轴的方向(tx和ty均为负数)
我用于计算旋转和平移向量的代码如下所示:
import cv2 as cv
import numpy as np
WPoints = np.zeros((9*3,3), np.float64)
WPoints[:,:2] = np.mgrid[0:9,0:3].T.reshape(-1,2)*0.4
imPoints=np.array([[20,143],[90,143],[161,143],[231,144],[303,144],
[374,144],[446,145],[516,146],[587,147],[18,214],[88,214]
,[159,215],[230,215],[302,216],[374,216],[446,216]
,[517,217],[588,217],[16,285],[87,285],[158,286],[229,287],
[301,288]
,[374,289],[446,289],[518,289],[589,289]],dtype=np.float64)
#load the rotation matrix [[4.38073915e+03 0.00000000e+00 1.00593352e+03]
# [0.00000000e+00 4.37829226e+03 6.97020491e+02]
# [0.00000000e+00 0.00000000e+00 1.00000000e+00]]
with np.load('parameters_cam1.npz') as X:
mtx, dist, _, _ = [X[i] for i in ('mtx','dist','rvecs','tvecs')]
ret,rvecs, tvecs = cv.solvePnP(WPoints, imPoints, mtx, dist)
np.savez("extrincic_camera1.npz",rvecs=rvecs,tvecs=tvecs)
print(tvecs)
print(rvecs)
cv.destroyAllWindows()
估计内在函数的代码如下所示
import numpy as np
import cv2
import glob
import argparse
import pathlib
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--path", required=True, help="path to images folder")
ap.add_argument("-e", "--file_extension", required=False, default=".jpg",
help="extension of images")
args = vars(ap.parse_args())
path = args["path"] + "*" + args["file_extension"]
# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (0.03,0,0), (0.06,0,0) ....,
#(0.18,0.12,0)
objp = np.zeros((5*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:5].T.reshape(-1,2)*0.03
#print(objp)
# Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.
#images = glob.glob('left/*.jpg') #read a series of images
images = glob.glob(path)
path = 'foundContours'
#pathlib.Path(path).mkdir(parents=True, exist_ok=True)
found = 0
for fname in images:
img = cv2.imread(fname) # Capture frame-by-frame
#print(images[im_i])
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv2.findChessboardCorners(gray, (7,5), None)
# print(corners)
# If found, add object points, image points (after refining them)
if ret == True:
print('true')
objpoints.append(objp) # Certainly, every loop objp is the same, in 3D.
#print('obj_point',objpoints)
corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
# print(corners2)
imgpoints.append(corners2)
print(imgpoints)
print('first_point',imgpoints[0])
#print(imgpoints.shape())
# Draw and display the corners
img = cv2.drawChessboardCorners(img, (7,5), corners2, ret)
found += 1
cv2.imshow('img', img)
cv2.waitKey(1000)
# if you want to save images with detected corners
# uncomment following 2 lines and lines 5, 18 and 19
image_name = path + '/calibresult' + str(found) + '.jpg'
cv2.imwrite(image_name, img)
print("Number of images used for calibration: ", found)
# When everything done, release the capture
# cap.release()
cv2.destroyAllWindows()
#calibration
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints,
gray.shape[::-1],None,None)
#save parameters needed in undistortion
np.savez("parameters_cam1.npz",mtx=mtx,dist=dist,rvecs=rvecs,tvecs=tvecs)
np.savez("points_cam1.npz",objpoints=objpoints,imgpoints=imgpoints)
print ("Camera Matrix = |fx 0 cx|")
print (" | 0 fy cy|")
print (" | 0 0 1|")
print (mtx)
print('distortion coefficients=\n', dist)
print('rotation vector for each image=', *rvecs, sep = "\n")
print('translation vector for each image=', *tvecs, sep= "\n")
希望你能帮助我理解这一点
提前致谢
首先,tvec是Axis-angle中的一个表示(https://en.wikipedia.org/wiki/Axis%E2%80%93angle_representation)。
您可以使用cv2.Rodrigues() 获取旋转矩阵。对于你的数据,我得到了差不多的身份:
[[ 0.99616253 -0.01682635 0.08588995]
[ 0.01439347 0.99947963 0.02886672]
[-0.08633098 -0.02751969 0.99588635]]
现在,根据你图片中x和y的方向,z-axis指向向下(仔细应用right-hand规则)。这就解释了为什么相机的 z-axis 几乎与你的世界参考系的 z-axis 对齐。
编辑:根据您发布的代码进一步挖掘:
WPoints = np.zeros((9*3,3), np.float64)
WPoints[:,:2] = np.mgrid[0:9,0:3].T.reshape(-1,2)*0.4
X 和 Y 的值都是正数,分别向右和向下递增,所以你确实使用了通常的约定。 你实际上是在使用 X 和 Y 分别向右和向下递增,错误的只是你在图片中画的箭头。
编辑关于平移向量的解释:在OpenCV约定中,局部相机参考系中的点是从世界参考系中的点获得的,如下所示:
|x_cam| |x_world|
|y_cam| = Rmat * |y_world| + tvec
|z_cam| |z_world|
根据这个约定,tvec 是相机参考系中世界原点的位置。更容易解释的是相机原点在世界参考系中的位置,可以得到:
cam_center = -(tvec * R_inv)
其中R_inv是旋转矩阵的逆矩阵。这里的旋转矩阵几乎是恒等式,所以快速近似是 -tvec,即 (5.4, 3.1, -24.1).