python实现坐标求取_根据相机位姿求指定点的世界坐标及其python实现

本文介绍如何使用Python和OpenCV进行单目相机位姿估计,进而计算目标点的世界坐标。通过标定板上的四个点,求解相机的旋转和平移向量,再利用旋转和平移信息将像素坐标转换为世界坐标,从而计算未知点的尺寸。应用实例中,通过两张照片测量茶罐的高度和对角线长度。
摘要由CSDN通过智能技术生成

Author

shaniadolphin

求解目的

本文将展示位姿估计的一种应用,即通过单目相机对环境进行测量。简单来说,本文的工作就是利用下面的两幅图,在已知P1、P2、P3、P4四点世界坐标的情况下,计算出其它点的世界坐标。

如图所示,一个标准的标定板,标定板每个格子的尺寸是30mm,通过标定四周的4个点P1、P2、P3、P4,旁边有茶罐,有待求点为P5、P6。

77f7c0cd9ec7

这种应用可以利用一个已经尺寸物体,通过两张不同视角的照片求未知物体的尺寸。比如上图中的通过已知的标定板求茶罐的尺寸。而在现实应用中可以用这种方式来求车的尺寸,建筑的高度,货物的体积等等。

求解原理

如下图,根据P1、P2、P3、P4四点的空间坐标,通过openCV的PNP函数,可以计算出两次拍照的相机位姿,从而进一步计算出相机的坐标

math?formula=Oc_1

math?formula=Oc_2。那么将

math?formula=Oc_1

math?formula=P

math?formula=Oc_2

math?formula=P连成直线,获得两条直线方程

math?formula=A

math?formula=B,组成方程组求解得到它们的交点,即为待求目标点的坐标。

77f7c0cd9ec7

1. 求出

math?formula=P点的相机坐标系坐标

math?formula=P_c

关于P点如何从二维映射到三维,参考上图,

math?formula=O_c的坐标通过解

math?formula=PNP已经求出,待求点P在图像中的像素坐标为

math?formula=(u%2Cv)

求出

math?formula=P在相机坐标系中的坐标

math?formula=P_c(也就是上图中的

math?formula=P_c点)。具体的转换公式如下,式中

math?formula=f为相机镜头的焦距

math?formula=(mm),在本次实验中使用的是中一光学的35mm手动镜头。

math?formula=(u%2Cv)为点的像素坐标,其余为相机内参数。

math?formula=%5Cbegin%7Bcases%7Dx_c%3D(u-u_0)*f%2Ff_x%20%5C%5Cy_c%3D(v-v_0)*f%2Ff_y%20%5C%5Cz_c%3Df%20%5Cend%7Bcases%7D

输入拍到的图片的点,包括待求点的像素坐标,示例如下:

P11 = np.array([0, 0, 0])

P12 = np.array([0, 300, 0])

P13 = np.array([210, 0, 0])

P14 = np.array([210, 300, 0])

p11 = np.array([1765, 725])

p12 = np.array([3068, 1254])

p13 = np.array([1249, 1430])

p14 = np.array([2648, 2072])

p4psolver1.Points3D[0] = np.array([P11,P12,P13,P14])

p4psolver1.Points2D[0] = np.array([p11,p12,p13,p14])

#p4psolver1.point2find = np.array([4149, 671])

#p4psolver1.point2find = np.array([675, 835])

p4psolver1.point2find = np.array([691, 336])

读取标定文件中的相机内参,代码如下,在代码里预设了相机的传感器大小,笔者所用的D7000单反是DX画幅的,根据可查到的资料,传感器的规格为23.6mm*15.6mm。

笔者用在本机的镜头是中一的35mm手动定焦镜头。

def getudistmap(self, filename):

with open(filename, 'r',newline='') as csvfile:

spamreader = csv.reader(csvfile, delimiter=',', quotechar='"')

rows = [row for row in spamreader]

self.cameraMatrix = np.zeros((3, 3))

#Dt = np.zeros((4, 1))

size_w = 23.6

size_h = 15.6

imageWidth = int(rows[0][1])

imageHeight = int(rows[0][2])

self.cameraMatrix[0][0] = rows[1][1]

self.cameraMatrix[1][1] = rows[1][2]

self.cameraMatrix[0][2] = rows[1][3]

self.cameraMatrix[1][2] = rows[1][4]

self.cameraMatrix[2][2] = 1

print(len(rows[2]))

if len(rows[2]) == 5:

print('fisheye')

self.distCoefs = np.zeros((4, 1))

self.distCoefs[0][0] = rows[2][1]

self.distCoefs[1][0] = rows[2][2]

self.distCoefs[2][0] = rows[2][3]

self.distCoefs[3][0] = rows[2][4]

scaled_K = self.cameraMatrix * 0.8 # The values of K is to scale with image dimension.

scaled_K[2][2] = 1.0

#newcameramtx = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(self.cameraMatrix, self.distCoefs, (imageWidth, imageHeight), np.eye(3), balance=0)

#map1, map2 = cv2.fisheye.initUndistortRectifyMap(self.cameraMatrix, self.distCoefs, np.eye(3), newcameramtx, (imageWidth, imageHeight), cv2.CV_32FC1)

else:

print('normal')

self.distCoefs = np.zeros((1, 5))

self.distCoefs[0][0] = rows[2][1]

self.distCoefs[0][1] = rows[2][2]

self.distCoefs[0][2] = rows[2][3]

self.distCoefs[0][3] = rows[2][4]

self.distCoefs[0][4] = rows[2][5]

#newcameramtx, roi = cv2.getOptimalNewCameraMatrix(self.cameraMatrix, self.distCoefs, (imageWidth, imageHeight), 1, (imageWidth, imageHeight))

#map1, map2 = cv2.initUndistortRectifyMap(self.cameraMatrix, self.distCoefs, None, newcameramtx, (imageWidth, imageHeight), cv2.CV_32FC1)

print('dim = %d*%d'%(imageWidth, imageHeight))

print('Kt = \n', self.cameraMatrix)

#print('newcameramtx = \n', newcameramtx)

print('Dt = \n', self.distCoefs)

self.f = [self.cameraMatrix[0][0]*(size_w/imageWidth), self.cameraMatrix[1][1]*(size_h/imageHeight)]

#self.f = [350, 350]

print('f = \n', self.f)

#print

你可以使用以下代码实现Python中使用move_base实现rviz小车定导航: ```python import rospy from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal import actionlib def move_to_goal(x, y): # 初始化节 rospy.init_node('move_base_client') # 创建一个actionlib客户端,连接move_base服务器 client = actionlib.SimpleActionClient('move_base', MoveBaseAction) client.wait_for_server() # 创建一个MoveBaseGoal对象 goal = MoveBaseGoal() goal.target_pose.header.frame_id = "map" goal.target_pose.header.stamp = rospy.Time.now() # 设置目标坐标 goal.target_pose.pose.position.x = x goal.target_pose.pose.position.y = y goal.target_pose.pose.orientation.w = 1.0 # 发送目标给move_base服务器 client.send_goal(goal) # 等待move_base完成导航 wait = client.wait_for_result() # 判断是否成功到达目标 if not wait: rospy.logerr("Action server not available!") rospy.signal_shutdown("Action server not available!") else: return client.get_result() if __name__ == '__main__': try: # 设置目标坐标 x = 1.0 y = 2.0 # 调用move_to_goal函数实现导航 result = move_to_goal(x, y) # 判断是否成功到达目标 if result: rospy.loginfo("Goal execution done!") except rospy.ROSInterruptException: rospy.loginfo("Navigation test finished.") ``` 这段代码使用了move_base_msgs和actionlib库,通过创建一个MoveBaseGoal对象,设置目标坐标,然后发送给move_base服务器,实现小车的定导航。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值