1.起因
导师要求用ifm的o3d303这款摄像头来实现点云图像的捕捉,ifm官方是提供了一个软件,叫做“视觉助手”,这个软件能够以一种很简单的方式就能够查看相机捕获的点云图,并且可以通过这个软件来查看和修改相机的一些出厂信息,例如ip(这个特别重要!!)。但是这个软件并不能将你捕获的点云图以.pcd的格式保存下来,只能把捕获的点云图以.h5的格式保存下来,很难进行二次开发,所以,为了满足老师的要求,就要通过ifm官方提供的ifm3d库来进行对相机的连接和点云图的获取
2.环境搭建
1.ifm3d 1.4.2
2.pcl 1.2.1
3.改ip
2.1下载ifm3d库
先挑个你喜欢版本下载(我一般都是下载最新版)
从发布 ·ifm/ifm3d (github.com)这个网站下载
下载这个文件后,就按照官网的教程进行ifm3d库的环境搭建使用 ifm3d 安装程序安装 — ifm3d v1.4.3 文档(就是安装好把所有bin文件的路径库库向path中一顿放,然后在window命令行验证)
到这里,ifm3d库的环境就算搭好了。
2.2pcl库的环境搭建
这里就不细说了,百度一下一抓一大把,注意要选择对应的版本攻略。
2.3ip更改
这点非常重要!!像我这种小白第一次接触这种程序与相机的通信,对于相机ip这个概念特别模糊最开始接触o3d303这款相机的ip是在ifm提供的官方sdk中。
打开start的那个ppt后,细读了一下
发现这段话,大概的意思就是想要打开sdk里的这个“Lighvis”这个可视化插件,相机的ip必须为192.168.0.69
包括后面的很多插件都有提及到ip,我就对相机的ip产生了兴趣,在起因中我讲过,ifm官方提供的那个视觉助手中提供了查看ip和修改ip的功能。
这里我用红框框柱的就是相机的ip,这里我们需要把这串ip复制,然后在上方的方框里粘贴(这操作看起来怪怪的,实际上真的很奇怪,ip那栏明明写着192.168.0.69,但是我当我选择通过手动输入ip连接的时候,输入192.168.0.69,却显示连不上,当我输入169.254.50.239后就能连接上了,这就证明这个相机的ip是169.254.50.239。真的很想骂娘,ifm这么搞是吧,好好好,后面还有更离谱的操作)
ip改好后,就要填写ipv4协议了
找到相机的网络
进入属性后,双击ipv4协议
这些在视觉助手里都有的看。
3.代码展示
在展示代码前我还想吐槽一下ifm,ifm的帮助文档只写了o3r这一个型号的示例代码,所以让我写o3d型号的代码变得异常的艰难
o3r型号的函数和o3d的完全不一样。所以这个“基本库的用法”这章就显的特别鸡肋!!
在我四处溜达的时候,发现ifm的手册里有这句话
我研究了一下,结果发现这是一份大概是17年的代码,老的掉牙,现在ifm自己都不用camera这个类和头文件了!!还不更新,真的想把ifm打一顿。
诶,这条路走不通那还是会ifm官网看有没有相关的示例代码吧
我就又溜达溜达
其中看到了这位大哥用Python实现我的目的
ifm3dlib+Python实现摄像头点云数据保存_ifm相机sdk_okfang616的博客-CSDN博客
我又同时在ifm官网那位大哥的Python代码有少许和这章的c++类似,我就开始重点研究这章
很幸运,这章并没有用到o3r的专属函数,看起来是所有型号相机通用的,那就开始试着写一下,这里就直接给最后的代码吧
#include <iostream>
#include <ifm3d/fg.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/cloud_viewer.h>
#include <ifm3d/device/device.h>
#include <chrono>
#include <ifm3d/fg/buffer.h>
#include <ifm3d/device/o3d.h>
using namespace std::chrono_literals;
using namespace ifm3d::literals;
void Callback(ifm3d::Frame::Ptr frame) {
auto dist = frame->GetBuffer(ifm3d::buffer_id::RADIAL_DISTANCE_IMAGE);
std::cout << dist.height() << " " << dist.width() << std::endl;
}
int main(int argc, const char** argv) {
// 填写相机的 IP 地址和端口号
std::string camera_ip = "169.254.50.239";
int camera_port = 80; // 假设相机的端口号是80
// 创建相机对象
auto cam = ifm3d::Device::MakeShared(camera_ip, camera_port); // 实例化相机
auto fg = std::make_shared<ifm3d::FrameGrabber>(cam, 50010);
// 启动数据流
fg->Start({ ifm3d::buffer_id::AMPLITUDE_IMAGE, ifm3d::buffer_id::RADIAL_DISTANCE_IMAGE, ifm3d::buffer_id::XYZ });
pcl::visualization::CloudViewer viewer("Real-time Point Cloud Viewer");
while (!viewer.wasStopped()) {
auto frame = fg->WaitForFrame().get();
ifm3d::Buffer xyz = frame->GetBuffer(ifm3d::buffer_id::XYZ);
// ifm3d库从相机缓冲器获取的XYZ数据!!!!!
ifm3d::Buffer_<ifm3d::Point3D_16S> xyz_data = xyz;
// Create a Point Cloud object
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
// Populate the Point Cloud with XYZ data
for (const auto& point : xyz_data)
{
pcl::PointXYZ pcl_point;
pcl_point.x = point.val[1];
pcl_point.y = point.val[2];
pcl_point.z = point.val[0];
cloud->push_back(pcl_point);
}
pcl::io::savePCDFileASCII("point_cloud.pcd", *cloud);
// 点云的来源就是通过ifm3d库从相机获取的XYZ数据,然后将其转换为PCL点云,并使用PCL的CloudViewer进行实时可视化。
viewer.showCloud(cloud);
}
return 0;
}
下面顺便展示一下代码运行效果
4.总结
总结一下,最重要的一点就是先让程序与相机完成通信,只要他们完成了通信,后面的操作都简单了