相对于定义的世界坐标解释旋转矩阵

如何解决相对于定义的世界坐标解释旋转矩阵

在下面的图像中,我们看到了定义的世界平面坐标(X,Y,0),其中Z = 0。我们看到的相机正朝着定义的世界平面前进。

世界参考点位于网格(0,0)的左上方。每两个黄点之间的距离为40厘米

World_coordinate

我已经使用棋盘格对相机进行了校准,然后使用内置功能 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-world轴相反),相机的Y轴指向图像底部(也与Y-world轴相反)

此外,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,[161,[231,144],[303,[374,[446,145],[516,146],[587,147],[18,214],[88,[159,215],[230,[302,216],[517,217],[588,[16,285],[87,[158,286],[229,287],[301,288],289],[518,[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.03,(0.06,0) ....,#(0.18,0.12,0)
objp = np.zeros((5*7,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,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,tvecs = cv2.calibrateCamera(objpoints,imgpoints,gray.shape[::-1],None,None)


#save parameters needed in undistortion
np.savez("parameters_cam1.npz",mtx=mtx,dist=dist,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 是轴角表示形式(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轴指向向下(小心地将右规则)。这就解释了为什么相机的z轴与世界参考系的z轴几乎对齐。


编辑:从您发布的代码中进一步挖掘:

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)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)> insert overwrite table dwd_trade_cart_add_inc > select data.id, > data.user_id, > data.course_id, > date_format(
错误1 hive (edu)> insert into huanhuan values(1,'haoge'); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive> show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 <configuration> <property> <name>yarn.nodemanager.res