【PCL】根据点对,获取仿射变换矩阵及姿态

  • CMAKE配置
cmake_minimum_required(VERSION 3.16)
project(FridayLibrary)

set(CMAKE_CXX_STANDARD 14)


SET(BOOST_INCLUDE_DIR C:/Program\ Files/PCL\ 1.11.0/3rdParty/Boost/include)
SET(BOOST_LIBRARY_DIR C:/Program\ Files/PCL\ 1.11.0/3rdParty/Boost/lib)

set(PLC_ROOT        C:/Program\ Files/PCL\ 1.11.0)
set(PLC_INCLUDE_DIR C:/Program\ Files/PCL\ 1.11.0/include)
set(PLC_LIBRARY_DIR C:/Program\ Files/PCL\ 1.11.0/lib)

find_package(PCL REQUIRED)
if(PCL_FOUND)
    message ("PCL found")
else()
    message (FATAL_ERROR "Cannot find PCL")
endif(PCL_FOUND)
include_directories(${PLC_INCLUDE_DIR} ${BOOST_INCLUDE_DIR})
link_directories(${PLC_LIBRARY_DIR} ${BOOST_LIBRARY_DIR})


add_library(FridayLibrary SHARED library.cpp library.h)
target_link_libraries( FridayLibrary PRIVATE
        ${PCL_LIBRARIES}
        ${BOOST_LIBRARIES}
        )
  • PCL + C++
pcl::PointCloud<pcl::PointXYZ>::Ptr srcCloud(new pcl::PointCloud<pcl::PointXYZ>());
pcl::PointCloud<pcl::PointXYZ>::Ptr dstCloud(new pcl::PointCloud<pcl::PointXYZ>());

srcCloud->width = 12;
srcCloud->height = 1;
srcCloud->is_dense = false;
srcCloud->resize(srcCloud->width * srcCloud->height);

dstCloud->width = 12;
dstCloud->height = 1;
dstCloud->is_dense = false;
dstCloud->resize(dstCloud->width * dstCloud->height);

srcCloud->points[0].x = 0.0625075, srcCloud->points[0].y = 0.0341182, srcCloud->points[0].z = -0.0291991;
srcCloud->points[1].x = 0.0466103, srcCloud->points[1].y = 0.0437115, srcCloud->points[1].z = 0.0275582;
srcCloud->points[2].x = 0.0702050, srcCloud->points[2].y = 0.0316673, srcCloud->points[2].z = -0.0269043;
srcCloud->points[3].x = 0.0527458, srcCloud->points[3].y = 0.0392645, srcCloud->points[3].z = 0.0298687;
srcCloud->points[4].x = 0.0670084, srcCloud->points[4].y = 0.0275866, srcCloud->points[4].z = -0.0272287;
srcCloud->points[5].x = 0.0514137, srcCloud->points[5].y = 0.0382540, srcCloud->points[5].z = 0.029152;
srcCloud->points[6].x = 0.0575101, srcCloud->points[6].y = 0.0254605, srcCloud->points[6].z = -0.0302174;
srcCloud->points[7].x = 0.0535772, srcCloud->points[7].y = 0.0332998, srcCloud->points[7].z = -0.0328697;
srcCloud->points[8].x = 0.0383195, srcCloud->points[8].y = 0.0486851, srcCloud->points[8].z = 0.0244912;
srcCloud->points[9].x = 0.0560232, srcCloud->points[9].y = 0.0385878, srcCloud->points[9].z = -0.0330957;
srcCloud->points[10].x = 0.0660206, srcCloud->points[10].y = 0.0425857, srcCloud->points[10].z = -0.0297611;
srcCloud->points[11].x = 0.0489257, srcCloud->points[11].y = 0.053031, srcCloud->points[11].z = 0.0257074;

dstCloud->points[0].x = 5.299e-06, dstCloud->points[0].y = -7.164e-06, dstCloud->points[0].z = -0.0300047;
dstCloud->points[1].x = 5.299e-06, dstCloud->points[1].y = -7.164e-06, dstCloud->points[1].z = 0.0300047;
dstCloud->points[2].x = 0.00883181, dstCloud->points[2].y = 0.00174854, dstCloud->points[2].z = -0.0300047;
dstCloud->points[3].x = 0.0088318, dstCloud->points[3].y = -0.00176288, dstCloud->points[3].z = 0.0300047;
dstCloud->points[4].x = 0.00831968, dstCloud->points[4].y = -0.00345109, dstCloud->points[4].z = -0.0300047;
dstCloud->points[5].x = 0.00831968, dstCloud->points[5].y = -0.00345111, dstCloud->points[5].z = 0.0300047;
dstCloud->points[6].x = 5.297e-06, dstCloud->points[6].y = -0.00900659, dstCloud->points[6].z = -0.0300047;
dstCloud->points[7].x = -0.00747745, dstCloud->points[7].y = -0.00500697, dstCloud->points[7].z = -0.0300047;
dstCloud->points[8].x = -0.00899412, dstCloud->points[8].y = -7.2e-06,    dstCloud->points[8].z = 0.0300047;
dstCloud->points[9].x = -0.00882121, dstCloud->points[9].y = 0.00174855, dstCloud->points[9].z = -0.0300047;
dstCloud->points[10].x = -0.00175039, dstCloud->points[10].y = 0.00881934, dstCloud->points[10].z = -0.0300047;
dstCloud->points[11].x = -0.00175046, dstCloud->points[11].y = 0.00881932, dstCloud->points[11].z = 0.0300047;


//利用SVD方法求解变换矩阵  
pcl::registration::TransformationEstimationSVD<pcl::PointXYZ, pcl::PointXYZ> TESVD;
pcl::registration::TransformationEstimationSVD<pcl::PointXYZ, pcl::PointXYZ>::Matrix4 transformation2;
TESVD.estimateRigidTransformation(*srcCloud, *dstCloud, transformation2);
//输出变换矩阵信息  
std::cout << "The Estimated Rotation and translation matrices (using getTransformation function) are : \n" << std::endl;
printf("\n");
printf("    | %6.3f %6.3f %6.3f | \n", transformation2(0, 0), transformation2(0, 1), transformation2(0, 2));
printf("R = | %6.3f %6.3f %6.3f | \n", transformation2(1, 0), transformation2(1, 1), transformation2(1, 2));
printf("    | %6.3f %6.3f %6.3f | \n", transformation2(2, 0), transformation2(2, 1), transformation2(2, 2));
printf("\n");
printf("t = < %0.3f, %0.3f, %0.3f >\n", transformation2(0, 3), transformation2(1, 3), transformation2(2, 3));

//rpyMatrix();

Eigen::Matrix3d rotation_matrix;
rotation_matrix(0, 0) = transformation2(0, 0);
rotation_matrix(0, 1) = transformation2(0, 1);
rotation_matrix(0, 2) = transformation2(0, 2);
rotation_matrix(1, 0) = transformation2(1, 0);
rotation_matrix(1, 1) = transformation2(1, 1);
rotation_matrix(1, 2) = transformation2(1, 2);
rotation_matrix(2, 0) = transformation2(2, 0);
rotation_matrix(2, 1) = transformation2(2, 1);
rotation_matrix(2, 2) = transformation2(2, 2);

auto eulerAngle = rotation_matrix.eulerAngles(0, 1, 2);
std::cout << eulerAngle * 180 / 3.14 << std::endl;
  • C# 封装

头文件

#ifndef FRIDAYLIBRARY_LIBRARY_H
#define FRIDAYLIBRARY_LIBRARY_H
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_plane.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include <pcl/point_cloud.h>
#include <pcl/registration/transformation_estimation_svd.h>
#include <vector>
#ifdef __DLL_BUILD
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C" {
#endif

/// <summary>
/// 通过对应点获取目标点云在原始点云坐标空间下的姿态
/// </summary>
/// <param name="p_src_x">原始点云的X坐标</param>
/// <param name="p_src_y">原始点云的Y坐标</param>
/// <param name="p_src_z">原始点云的Z坐标</param>
/// <param name="p_dst_x">目标点云的X坐标</param>
/// <param name="p_dst_y">目标点云的Y坐标</param>
/// <param name="p_dst_z">目标点云的Z坐标</param>
/// <param name="length">点云个数</param>
/// <param name="pose">返回的姿态[X, Y, Z, RX, RY, RZ ]</param>
DLL_EXPORT void get_plane_pose( const float* p_src_x,
								const float* p_src_y,
								const float* p_src_z,
								const float* p_dst_x,
								const float* p_dst_y,
								const float* p_dst_z,
								const size_t length, float* pose);
#ifdef __cplusplus
}
#endif
#endif //FRIDAYLIBRARY_LIBRARY_H

源文件

#define __DLL_BUILD
#include "library.h"

/// <summary>
/// 通过对应点获取目标点云在原始点云坐标空间下的姿态
/// </summary>
/// <param name="p_src_x">原始点云的X坐标</param>
/// <param name="p_src_y">原始点云的Y坐标</param>
/// <param name="p_src_z">原始点云的Z坐标</param>
/// <param name="p_dst_x">目标点云的X坐标</param>
/// <param name="p_dst_y">目标点云的Y坐标</param>
/// <param name="p_dst_z">目标点云的Z坐标</param>
/// <param name="length">点云个数</param>
/// <param name="pose">返回的姿态[X, Y, Z, RX, RY, RZ ]</param>
void get_plane_pose(const float* p_src_x,
					const float* p_src_y,
					const float* p_src_z,
					const float* p_dst_x,
					const float* p_dst_y,
					const float* p_dst_z,
					const size_t length, float* pose)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr src_cloud(new pcl::PointCloud<pcl::PointXYZ>());
	pcl::PointCloud<pcl::PointXYZ>::Ptr dst_cloud(new pcl::PointCloud<pcl::PointXYZ>());

	src_cloud->width = length;
	src_cloud->height = 1;
	src_cloud->is_dense = false;
	src_cloud->resize(src_cloud->width * src_cloud->height);

	dst_cloud->width = length;
	dst_cloud->height = 1;
	dst_cloud->is_dense = false;
	dst_cloud->resize(dst_cloud->width * dst_cloud->height);

	for (size_t i = 0; i < length; i++)
	{
		src_cloud->points[i].x = p_src_x[i];
		src_cloud->points[i].y = p_src_y[i];
		src_cloud->points[i].z = p_src_z[i];

		dst_cloud->points[i].x = p_dst_x[i];
		dst_cloud->points[i].y = p_dst_y[i];
		dst_cloud->points[i].z = p_dst_z[i];
	}


	const pcl::registration::TransformationEstimationSVD<pcl::PointXYZ, pcl::PointXYZ> estimation_svd;
	pcl::registration::TransformationEstimationSVD<pcl::PointXYZ, pcl::PointXYZ>::Matrix4 transformation_matrix;

	estimation_svd.estimateRigidTransformation(*src_cloud, *dst_cloud, transformation_matrix);

	Eigen::Matrix3d rotation_matrix;
	rotation_matrix(0, 0) = transformation_matrix(0, 0);
	rotation_matrix(0, 1) = transformation_matrix(0, 1);
	rotation_matrix(0, 2) = transformation_matrix(0, 2);
	rotation_matrix(1, 0) = transformation_matrix(1, 0);
	rotation_matrix(1, 1) = transformation_matrix(1, 1);
	rotation_matrix(1, 2) = transformation_matrix(1, 2);
	rotation_matrix(2, 0) = transformation_matrix(2, 0);
	rotation_matrix(2, 1) = transformation_matrix(2, 1);
	rotation_matrix(2, 2) = transformation_matrix(2, 2);

	const auto euler_angles = rotation_matrix.eulerAngles(0, 1, 2) * 180 / 3.1415926f;

	pose[0] = transformation_matrix(0, 3);
	pose[1] = transformation_matrix(1, 3);
	pose[2] = transformation_matrix(2, 3);
	pose[3] = static_cast<float>(euler_angles[0]);
	pose[4] = static_cast<float>(euler_angles[1]);
	pose[5] = static_cast<float>(euler_angles[2]);
}

C# 调用

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    internal class Program
    {
        public struct Buffer
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
            public byte[] DstAddr;
        }


        [DllImport("./FridayLibrary", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_plane_pose")]
        internal static extern void GetPose(float[] srcX, float[] srcY, float[] srcZ, float[] dstX, float[] dstY, float[] dstZ, int length, ref Buffer buf);

        static void Main(string[] args)
        {
            var srcX = new float[]
            {
                0.0625075f, 0.0466103f, 0.0702050f, 0.0527458f, 0.0670084f, 0.0514137f, 0.0575101f, 0.0535772f, 0.0383195f, 0.0560232f, 0.0660206f, 0.0489257f
            };
            var srcY = new float[]
            {
                0.0341182f, 0.0437115f, 0.0316673f, 0.0392645f, 0.0275866f, 0.0382540f, 0.0254605f, 0.0332998f, 0.0486851f, 0.0385878f, 0.0425857f, 0.053031f
            };
            var srcZ = new float[]
            {
                -0.0291991f, 0.0275582f, -0.0269043f, 0.0298687f, -0.0272287f, 0.029152f, -0.0302174f, -0.0328697f, 0.0244912f, -0.0330957f, -0.0297611f, 0.0257074f
            };

            var dstX = new float[]
            {
                5.299e-06f, 5.299e-06f, 0.00883181f, 0.0088318f, 0.00831968f, 0.00831968f, 5.297e-06f, -0.00747745f, -0.00899412f, -0.00882121f, -0.00175039f, -0.00175046f
            };
            var dstY = new float[]
            {
                -7.164e-06f, -7.164e-06f, 0.00174854f, -0.00176288f, -0.00345109f, -0.00345111f, -0.00900659f, -0.00500697f, -7.2e-06f, 0.00174855f, 0.00881934f, 0.00881932f
            };
            var dstZ = new float[]
            {
                -0.0300047f, 0.0300047f, -0.0300047f, 0.0300047f, -0.0300047f, 0.0300047f, -0.0300047f, -0.0300047f, 0.0300047f, -0.0300047f, -0.0300047f, 0.0300047f
            };

            GetPose(srcX, srcY, srcZ,dstX,dstY,dstZ,9,ref buf);
            using (var stream = new MemoryStream(buf.DstAddr))
            {
                using (var reader = new BinaryReader(stream))
                {
                    var tx = reader.ReadSingle();
                    var ty = reader.ReadSingle();
                    var tz = reader.ReadSingle();
                    var rx = reader.ReadSingle();
                    var ry = reader.ReadSingle();
                    var rz = reader.ReadSingle();

                    Console.WriteLine($"{tx}, {ty}, {tz}, {rx}, {ry}, {rz}");
                }
            }

            Console.ReadKey();
        }
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值