总结笔记20191002/02

哈哈哈哈哈哈哈哈哈哈,还是昨天那个程序,因为很少有Python关于ROS开发的相关文章,自己真的是各种尝试,最后在大佬的帮助下终于成功了。

上代码:

#!/usr/bin/env python
#coding=utf-8
'''
************************************************************
作者:EnKant
************************************************************
'''
import rospy
import os
import numpy as np
import math
import cv2
from sensor_msgs.msg import PointCloud2, PointField
from sensor_msgs import point_cloud2
'''
************************************************************
功能:四元数 转 旋转矩阵
输入:1×4的四元数向量   返回值:3×3的旋转矩阵
************************************************************
'''

def q2R(q):
    q = np.outer(q, q)
    rot_matrix = np.transpose(
        [[1.0 - 2*q[2, 2] - 2*q[3, 3], 2*q[1, 2] + 2*q[0, 3]      , 2*q[1, 3] - 2*q[0, 2]]      ,
         [2*q[1, 2] - 2*q[0, 3]      , 1.0 - 2*q[1, 1] - 2*q[3, 3], 2*q[2, 3] + 2*q[0, 1]]      ,
         [2*q[1, 3] + 2*q[0, 2]      , 2*q[2, 3] - 2*q[0, 1]      , 1.0 - 2*q[1, 1] - 2*q[2, 2]]]
         )
    return rot_matrix

'''
************************************************************
功能:旋转矩阵 转 四元数
输入:3×3的旋转矩阵  返回值:1×4的四元数向量 
************************************************************
'''

def R2q(R):
    q=np.array([0.0,0.0,0.0,0.0])
    q[0]=(math.sqrt(abs(np.trace(R))+1))/2.0   
    q[1]=(R[1,2]-R[2,1])/(4*q[0])      
    q[2]=(R[2,0]-R[0,2])/(4*q[0])      
    q[3]=(R[0,1]-R[1,0])/(4*q[0])
    return q

'''
************************************************************
功能:旋转矩阵 转 变换矩阵
输入:3×3的旋转矩阵 三维平移向量  返回值:4×4的变换矩阵 
************************************************************
'''

def R2T(R,t):
    rot_t = t.reshape(3,1)
    tran_matix = np.concatenate((R,rot_t),axis=1)
    matix_0 =np.array([0,0,0,0]).reshape(1,4)
    tran_matix = np.concatenate((tran_matix,matix_0),axis=0)
    return tran_matix

'''
************************************************************
功能:变换矩阵 转 旋转矩阵
输入:4×4的变换矩阵  返回值:3×3的旋转矩阵 
************************************************************
'''

def T2R(T):
    rot_matix = T[0:3,0:3]
    return rot_matix

'''
************************************************************
功能:主函数
     1.计算任一像素在相机坐标系与世界坐标系下的坐标
     2.将图像拼接成点云
************************************************************
'''

if __name__ == "__main__":
    # 1.利用OpenCV读取RGB图和深度图
    img = []
    img.append(cv2.imread('/home/zk/test/depth/1.pgm',-1))
    img.append(cv2.imread('/home/zk/test/depth/2.pgm',-1))
    img.append(cv2.imread('/home/zk/test/depth/3.pgm',-1))
    img.append(cv2.imread('/home/zk/test/depth/4.pgm',-1))
    img.append(cv2.imread('/home/zk/test/depth/5.pgm',-1))
    img_shape = np.shape(img[0])
    rgb = []
    rgb.append(cv2.imread('/home/zk/test/color/1.png',-1))
    rgb.append(cv2.imread('/home/zk/test/color/2.png',-1))
    rgb.append(cv2.imread('/home/zk/test/color/3.png',-1))
    rgb.append(cv2.imread('/home/zk/test/color/4.png',-1))
    rgb.append(cv2.imread('/home/zk/test/color/5.png',-1))

    # 2.使用之前所完成的函数,将所给的外参转换成变换矩阵
    data = np.zeros((5,7),dtype=float) 
    f = open("/home/zk/test/pose.txt") 
    lines = f.readlines()           
    data_row = 0                       
    for line in lines:              
        list = line.strip('\n').split(' ')      
        data[data_row:] = list[0:7]                    
        data_row+=1
    tran_matix = []
    tran_matix.append( R2T(q2R([data[0,6],data[0,3],data[0,4],data[0,5]]),data[0,0:3]))
    tran_matix.append( R2T(q2R([data[1,6],data[1,3],data[1,4],data[1,5]]),data[1,0:3]))
    tran_matix.append( R2T(q2R([data[2,6],data[2,3],data[2,4],data[2,5]]),data[2,0:3]))
    tran_matix.append( R2T(q2R([data[3,6],data[3,3],data[3,4],data[3,5]]),data[3,0:3]))
    tran_matix.append( R2T(q2R([data[4,6],data[4,3],data[4,4],data[4,5]]),data[4,0:3]))

    # 3.利用所给的相机内参和图像深度信息,将所有像素坐标转换成相机坐标
    # 4.利用步骤2计算出的变换矩阵,将所有相机坐标转换成世界坐标
    in_matix = np.array([[518.0,0    ,325.5],
                         [0    ,519.0,253.5],
                         [0    ,0    ,1    ]])   
    inverse_in_matix = np.linalg.inv(in_matix)
    num = 0
    CCS_matix = []
    world_matix = []
    PointCloud = []
    PointClouds = []
    for p in range(5):
        print(p)
        for i in range(480):
             for j in range(640):
                 CCS_matix.append( np.array(np.dot(inverse_in_matix,np.array([j,i,1]))*(img[p][i][j]/1000.0)) ) #求出相机坐标
                 world_matix.append( np.dot(tran_matix[p],[CCS_matix[num][0],CCS_matix[num][1],CCS_matix[num][2],1]) )
                 PointCloud.append( np.array(([world_matix[num][0],world_matix[num][1],world_matix[num][2],rgb[p][i][j][0],rgb[p][i][j][1],rgb[p][i][j][2]]), dtype = np.float32) )
                 num = num + 1
    
    PointCloud = np.array(PointCloud).flatten()
    # ROS相关操作,将点云信息发布出去

    #建立节点并建立发布者
    rospy.init_node('test', anonymous=True)                 
    pub_cloud = rospy.Publisher("/points", PointCloud2,queue_size=10)     
    #创建点云并将矩阵赋值给点云
    while not rospy.is_shutdown():                          
         pcloud = PointCloud2()
         #设置点云格式

         #宽与高
         pcloud.height = 1
         pcloud.width = img_shape[0]*img_shape[1]*5          
         #二进制数据通道
         pcloud.fields = [PointField('x',0,PointField.FLOAT32,1),
                          PointField('y',4,PointField.FLOAT32,1),
                          PointField('z',8,PointField.FLOAT32,1),
                          PointField('b',12,PointField.FLOAT32,1),
                          PointField('g',16,PointField.FLOAT32,1),
                          PointField('r',20,PointField.FLOAT32,1)]
        #小端格式
         pcloud.is_bigendian = False 
        #点的长度
         pcloud.point_step = 24
        #行的长度
         pcloud.row_step = pcloud.point_step*pcloud.width
        #实际数据(二进制的数据流)
         pcloud.data = PointCloud.tostring()
        #如果包含Inf / NaN值,则为false,否则为真
         pcloud.is_dense = True
         pcloud.header.frame_id = "/map"                     
         pub_cloud.publish(pcloud)
         rospy.sleep(1.0)
 

 

 我遇到的各种坑:

1.ROS系统的教程国内的几乎都是用C++编写的,所以网上几乎找不到python的ROS编程教程,可能是因为ROS的相关教程都是在好几年前编写的,

那时的python还不想现在这么的火,所以只要去读英文文档,但是我觉得英文文档太简洁了,对于新手太不友好了。

2.自己的很多基础知识学得不牢靠,比如python的数组默认为是64位的,以及如何定义数据流,数据流是怎样输入的,都是自己的拦路虎。

3.自己开始还不知道头的定义是怎么回事,重定义了...

关于本次操作的介绍:

1.定义节点,并通过节点发送数据

2.对于数据的格式进行定义,并且把数据给传输进去

3.catkin编译

4.运行文件

效果图:

总结笔记20191002/02_第1张图片

 

你可能感兴趣的:(总结笔记20191002/02)