文章目录
- 1.GM465-E1相机
-
- [1.1 GM465-E1工作场景](#1.1 GM465-E1工作场景)
- [1.2 GM465-E1 IO线和数据线定义](#1.2 GM465-E1 IO线和数据线定义)
-
- [1.2.1 IO接口定义](#1.2.1 IO接口定义)
- [1.2.2 数据接口线](#1.2.2 数据接口线)
- [1.2.3 GM465-E1相机连接拓扑网络](#1.2.3 GM465-E1相机连接拓扑网络)
- [1.2.4 GM465-E1相机正面安装方向](#1.2.4 GM465-E1相机正面安装方向)
- [1.2.5 上下面螺纹孔安装](#1.2.5 上下面螺纹孔安装)
- [1.3 GM465-E1相机性能指标](#1.3 GM465-E1相机性能指标)
- 2.GM465-E1相机调参技巧
-
- [2.1 深度图滤波设置](#2.1 深度图滤波设置)
- [2.2 如何调整相机左右IR的参数?](#2.2 如何调整相机左右IR的参数?)
-
- [2.2.1 手动调整左右IR曝光](#2.2.1 手动调整左右IR曝光)
- [2.2.2 调整相机左右IR自动曝光](#2.2.2 调整相机左右IR自动曝光)
- [2.3 调试深度图](#2.3 调试深度图)
-
- [2.3.1 查看深度值](#2.3.1 查看深度值)
- [2.3.2 渲染范围调节方法](#2.3.2 渲染范围调节方法)
- [2.3.3 调节深度图渲染效果](#2.3.3 调节深度图渲染效果)
- [2.4 保存图像](#2.4 保存图像)
-
- [2.4.1 存图设置](#2.4.1 存图设置)
- [2.4.2 单张存图](#2.4.2 单张存图)
- [2.4.3 连续存图](#2.4.3 连续存图)
- [2.5 GM465-E1相机保存参数配置](#2.5 GM465-E1相机保存参数配置)
- [2.6 GM465-E1相机参数补充说明](#2.6 GM465-E1相机参数补充说明)
- 3.GM465-E1相机SDK相关
-
- [3.1 C++语言SDK(`推荐`)](#3.1 C++语言SDK(
推荐)) -
- [3.1.1 完整参考例子](#3.1.1 完整参考例子)
- [3.1.2 GM465-E1相机软触发注意事项](#3.1.2 GM465-E1相机软触发注意事项)
- [3.1.3 TYSendSoftTrigger软触发指令不生效](#3.1.3 TYSendSoftTrigger软触发指令不生效)
- [3.1.4 GM465-E1相机推荐SDK版本](#3.1.4 GM465-E1相机推荐SDK版本)
- [3.1.5 C++语言SDK升级注意事项](#3.1.5 C++语言SDK升级注意事项)
- [3.2 ROS1版本(`推荐`)](#3.2 ROS1版本(
推荐)) - [3.3 ROS2版本(`推荐`)](#3.3 ROS2版本(
推荐)) - 3.4 C#语言SDK
- [3.5 Python语言SDK](#3.5 Python语言SDK)
- [3.1 C++语言SDK(`推荐`)](#3.1 C++语言SDK(
- 4.GM465-E1相机常见FAQ
-
- [4.1 如何获取GM465-E1相机内参?](#4.1 如何获取GM465-E1相机内参?)
-
- [4.1.1 方法一 运行sample_read_calibration_data](#4.1.1 方法一 运行sample_read_calibration_data)
- [4.1.2 方法二 运行x64中的例子](#4.1.2 方法二 运行x64中的例子)
- [4.1.3 方法三 运行DumpCalibInfo](#4.1.3 方法三 运行DumpCalibInfo)
- [4.2 GM465-E1相机内参说明](#4.2 GM465-E1相机内参说明)
-
- [4.2.1 深度图内参](#4.2.1 深度图内参)
- [4.2.2 彩色图内参/畸变系数/外参](#4.2.2 彩色图内参/畸变系数/外参)
- [4.2.3 左右IR极限约束前内参/极限校正后内参](#4.2.3 左右IR极限约束前内参/极限校正后内参)
- [4.3 GM465-E1相机光心位置](#4.3 GM465-E1相机光心位置)
- 5.GM465-E1相机测试结果
-
- [5.1 GM465-E1 帧率测试](#5.1 GM465-E1 帧率测试)
-
- [5.1.1 GM465-E1 出图延迟时间](#5.1.1 GM465-E1 出图延迟时间)
- [5.1.2 GM465-E1 帧率测试](#5.1.2 GM465-E1 帧率测试)
- 6.成像问题FAQ
-
- [6.1 拍摄低反或者高亮材质,点云缺失](#6.1 拍摄低反或者高亮材质,点云缺失)
-
- [6.1.1 开启/关闭纹理滤波](#6.1.1 开启/关闭纹理滤波)
- [6.1.2 调整左右IR参数](#6.1.2 调整左右IR参数)
- 7.常见问题FAQ
-
- [7.1 图漾相机获取的是有序点云还是无序点云?](#7.1 图漾相机获取的是有序点云还是无序点云?)
-
- [7.1.1 PCD文件数据](#7.1.1 PCD文件数据)
- [7.2 相机是否带IMU?](#7.2 相机是否带IMU?)
- 8.GM465相机属性表
-
- [8.1 DeviceControl模块](#8.1 DeviceControl模块)
- [8.2 AcquisitionControl模块](#8.2 AcquisitionControl模块)
- [8.3 TransportLayerControl模块](#8.3 TransportLayerControl模块)
- [8.4 SourceControl模块](#8.4 SourceControl模块)
-
- [8.4.1 Depth组件](#8.4.1 Depth组件)
- [8.4.2 Left和Right组件](#8.4.2 Left和Right组件)
- [8.4.3 Texture组件](#8.4.3 Texture组件)
- [8.5 LightControl模块](#8.5 LightControl模块)
- [8.6 ImageFormatControl模块](#8.6 ImageFormatControl模块)
- [8.7 UserSetControl模块](#8.7 UserSetControl模块)
- [8.8 FileAccessControl模块](#8.8 FileAccessControl模块)
-
- [8.8.1 FileAccess介绍](#8.8.1 FileAccess介绍)
- [8.8.2 FileAccess初探](#8.8.2 FileAccess初探)
- [8.8.3 节点解释](#8.8.3 节点解释)
- 9.其他学习资料
1.GM465-E1相机

GM465-E1相机外观
1.1 GM465-E1工作场景
GM465是一款高性价比的3D工业相机新品,兼具工业级的精度优势和消费级的价格优势,并提供高速 和高精度两种工作模式,产品通用性强,可广泛使用于如工业、物流、移动机器人、商业、安全、教育等多种应用场景。
1.2 GM465-E1 IO线和数据线定义
1.2.1 IO接口定义

相机的电源&数据接口线定义如下:

1.2.2 数据接口线
GM465-E1相机数据线如下图:

1.2.3 GM465-E1相机连接拓扑网络
GM465-E1相机拓扑网络如下图:

1.2.4 GM465-E1相机正面安装方向
GM465-E1相机正面安装方向如下:

从左到右依次是右IR镜头 ,散斑投射器 ,RGB相机 ,左IR镜头。
1.2.5 上下面螺纹孔安装

GM465相机上下面有一组M3螺纹孔(螺纹深度5mm)
1.3 GM465-E1相机性能指标
GM465-E1相机的性能指标如下:

2.GM465-E1相机调参技巧
1.GM465-E1相机,需要搭配图漾新版本的看图软件使用,可联系图漾技术获取。
2.新的看图软件详细操作,可查看此链接:新版看图软件操作手册
2.1 深度图滤波设置
建议在开启相机取流前,打开散斑滤波设置开关

0.5.11及其以后的版本,增加了自动开启散斑滤波的设置,具体如下图:

新的看图软件详细操作,可查看此链接:新版看图软件操作手册
2.2 如何调整相机左右IR的参数?
首先需要开启左右取流:

2.2.1 手动调整左右IR曝光

2.2.2 调整相机左右IR自动曝光

0.5.11及其以后的版本,增加了自动设置左右IR的ROI设置。

根据设置的AOI 区域的图像信息,来调整整个画面的亮度。
调整逻辑
1. 如果检测到划定区域的亮度较低 ,算法"觉得"应该增强亮度,于是会调亮图像画面。
2. 如果检测到划定区域的亮度较亮 ,算法"觉得"应该减弱亮度,于是会调暗图像画面。

2.3 调试深度图
2.3.1 查看深度值
打开深度取图开关,点击
按钮开始采图
2.将鼠标放置于深度图上,即可查看当前像素点对应的像素坐标与实际深度值(单位:mm)。

2.3.2 渲染范围调节方法
深度图支持动态渲染范围调整。通过优化目标深度区间的色彩映射 ,显著增强深度细节的可辨识度。
1.通过上滑块 调节渲染深度上限,通过下滑块调节渲染深度下限。
2.直接在输入框 键入目标值,或通过箭头微调。

2.3.3 调节深度图渲染效果
1.深度值位于下滑块值和上滑块值之间时,色彩梯度均匀分布 ;
2.深度值小于下滑块值显示为红色,深度值大于上滑块值显示为紫色。
当场景深度集中分布在 400-800 mm 区间时:
使用默认渲染范围(0-5000 mm):如下方左图所示,色彩梯度平缓,细节难以区分**。
缩小范围至400--800mm:如下方右图所示,色彩对比鲜明,可清晰辨识三个物体的深度差异。

使用默认深度渲染范围(左)/调节渲染范围后(右)
2.4 保存图像
2.4.1 存图设置
新的Percipio Viewer支持保存当前帧图像,可同时保存彩色图、深度图、渲染后的深度图、左/右IR图、点云数据
(.ply/.pcd格式)。
操作步骤:
1.点击
,弹出保存图片设置对话框。
2.点击
,选择存图文件夹,并点击 "确定"。
2.4.2 单张存图

2.4.3 连续存图

2.5 GM465-E1相机保存参数配置
保存相机参数配置,上电加载参数,具体操作流程如下图:

2.6 GM465-E1相机参数补充说明
1.开启DepthSgbmSaturateFilterEnable、DepthSgbmTextureFilterEnable这两个后处理后,深度图像帧率会减半。
3.GM465-E1相机SDK相关
GM465-E1相机,推荐使用的编程语言和SDK版本如下:
3.1 C++语言SDK(推荐)
GM465-E1相机,只能搭配4.X.X版本的SDK使用,如果相机固件是106版本之后的,需要配合使用最新版本的SDK(4.1.9版本及以上)、最新版本的Viewer。
具体操作和Sample和案例,可打开如下链接:
3.1.1 完整参考例子
cpp
#include <limits>
#include <cassert>
#include <cmath>
#include "../common/common.hpp"
#include <TYImageProc.h>
#include <chrono>
//深度图对齐到彩色图开关,置1则将深度图对齐到彩色图坐标系,置0则不对齐
//因彩色图对齐到深度图时会有部分深度缺失的区域丢失彩色信息,因此默认使用深度图对齐到彩色图方式
#define MAP_DEPTH_TO_COLOR 1
//开启以下深度图渲染显示将会降低帧率
DepthViewer depthViewer0("OrgDepth");//用于显示渲染后的原深度图
DepthViewer depthViewer1("FillHoleDepth");//用于显示渲染后的填洞处理之后的深度图
DepthViewer depthViewer2("SpeckleFilterDepth"); //用于显示渲染后的经星噪滤波过的深度图
DepthViewer depthViewer3("EnhenceFilterDepth"); //用于显示渲染后的经时域滤波过的深度图
DepthViewer depthViewer4("MappedDepth"); //用于显示渲染后的对齐到彩色图坐标系的深度图
//设置相机参数开关,默认使用相机内保存的参数。(使用保存的参数,也可以修改参数)
//不同型号相机具备不同的参数属性,可以使用PercipioViewer看图软件确认相机支持的参数属性和参数取值范围
bool setParameters = false;
static void use_new_apis()
{
LOGD("This is a new device. We have provided GenICam style API in TYParameter.h to get/set parameters.");
}
static void use_old_apis()
{
LOGD("This is a old device. Please use the API in TYApi.h to get/set parameters");
}
//事件回调
void eventCallback(TY_EVENT_INFO *event_info, void *userdata)
{
if (event_info->eventId == TY_EVENT_DEVICE_OFFLINE)
{
LOGD("=== Event Callback: Device Offline!");
// Note:
// Please set TY_BOOL_KEEP_ALIVE_ON OFF feature to false if you need to debug with breakpoint!
}
else if (event_info->eventId == TY_EVENT_LICENSE_ERROR)
{
LOGD("=== Event Callback: License Error!");
}
}
//数据格式转换
//cv pixel format to TY_PIXEL_FORMAT
static int cvpf2typf(int cvpf)
{
switch(cvpf)
{
case CV_8U: return TY_PIXEL_FORMAT_MONO;
case CV_8UC3: return TY_PIXEL_FORMAT_RGB;
case CV_16UC1: return TY_PIXEL_FORMAT_DEPTH16;
default: return TY_PIXEL_FORMAT_UNDEFINED;
}
}
//数据格式转换
//mat to TY_IMAGE_DATA
static void mat2TY_IMAGE_DATA(int comp, const cv::Mat& mat, TY_IMAGE_DATA& data)
{
data.status = 0;
data.componentID = comp;
data.size = mat.total() * mat.elemSize();
data.buffer = mat.data;
data.width = mat.cols;
data.height = mat.rows;
data.pixelFormat = cvpf2typf(mat.type());
}
struct CallbackData
{
int index;
TY_DEV_HANDLE hDevice;
TY_CAMERA_CALIB_INFO depth_calib;
TY_CAMERA_CALIB_INFO color_calib;
float f_depth_scale;
bool isTof;
bool saveOneFramePoint3d;
bool exit_main;
int fileIndex;
bool map_depth_to_color;
};
static CallbackData cb_data;
//通过内参实训深度图转点云,方式供参考
//depth to pointcloud
cv::Mat depthToWorld(float* intr, const cv::Mat &depth,float scale_unit)
{
cv::Mat world(depth.rows, depth.cols, CV_32FC3);
float cx = intr[2];
float cy = intr[5];
float inv_fx = 1.0f / intr[0];
float inv_fy = 1.0f / intr[4];
for (int r = 0; r < depth.rows; r++)
{
uint16_t* pSrc = (uint16_t*)depth.data + r * depth.cols;
cv::Vec3f* pDst = (cv::Vec3f*)world.data + r * depth.cols;
for (int c = 0; c < depth.cols; c++)
{
uint16_t z = pSrc[c] * scale_unit;
if(z == 0){
pDst[c][0] = NAN;
pDst[c][1] = NAN;
pDst[c][2] = NAN;
} else {
pDst[c][0] = (c - cx) * z * inv_fx;
pDst[c][1] = (r - cy) * z * inv_fy;
pDst[c][2] = z;
}
}
}
return world;
}
//输出畸变校正的彩色图,并实现深度图对齐到彩色图
static void doRegister(const TY_CAMERA_CALIB_INFO& depth_calib
, const TY_CAMERA_CALIB_INFO& color_calib
, const cv::Mat& depth
, const float f_scale_unit
, const cv::Mat& color
, cv::Mat& undistort_color
, cv::Mat& out
, bool map_depth_to_color
)
{
// do undistortion RGB校正畸变
TY_IMAGE_DATA src;
src.width = color.cols;
src.height = color.rows;
src.size = color.size().area() * 3;
src.pixelFormat = TYPixelFormatRGB8;
src.buffer = color.data;
undistort_color = cv::Mat(color.size(), CV_8UC3);
TY_IMAGE_DATA dst;
dst.width = color.cols;
dst.height = color.rows;
dst.size = undistort_color.size().area() * 3;
dst.buffer = undistort_color.data;
dst.pixelFormat = TYPixelFormatRGB8;
ASSERT_OK(TYUndistortImage(&color_calib, &src, NULL, &dst));
//TM265相机这里,新相机的RGB加入了鱼眼标定,如果使用TM265相机,则用TYGetEnum(hDevice, comp_id, TY_ENUM_LENS_OPTICAL_TYPE, &lens_tpye);
// TY_LENS_PINHOLE是老的小孔成像,TY_LENS_FISHEYE是新的鱼眼
// ASSERT_OK(TYUndistortImage(&color_calib, &src, NULL, &dst , TY_LENS_FISHEYE));
// 新的do register,用了最邻近插值
if (map_depth_to_color)
{
int outW = depth.cols;
int outH = depth.cols * undistort_color.rows / undistort_color.cols;
out = cv::Mat::zeros(cv::Size(outW, outH), CV_16U);
ASSERT_OK(
TYMapDepthImageToColorCoordinate(
&depth_calib,
depth.cols, depth.rows, depth.ptr<uint16_t>(),
&color_calib,
out.cols, out.rows, out.ptr<uint16_t>(), f_scale_unit
)
);
cv::Mat temp;
cv::resize(out, temp, undistort_color.size(), 0, 0, cv::INTER_NEAREST);
out = temp;
}
}
//图像帧处理
void frameHandler(TY_FRAME_DATA* frame, void* userdata)
{
CallbackData* pData = (CallbackData*) userdata;
LOGD("=== Get frame %d", ++pData->index);
std::vector<TY_VECT_3F> P3dtoColor,P3d;//点云
std::vector<cv::Mat> depths;
cv::Mat depth, color;
auto StartParseFrame = std::chrono::steady_clock::now();
//解析图像帧
parseFrame(*frame, &depth, 0, 0, &color);//拿深度图和color图
auto ParseFrameFinished = std::chrono::steady_clock::now();
auto duration2 = std::chrono::duration_cast<std::chrono::microseconds>(ParseFrameFinished - StartParseFrame);
LOGI("*******ParseFrame spend Time : %lld", duration2);
//填洞开关,开启后会降低帧率
bool FillHole = 1;
//星噪滤波开关,深度图中离散点降噪处理
bool SpeckleFilter = 0;
//时域滤波,可降低单点抖动,提升点云平面度
bool EnhenceFilter = 0;
//如果需要使用时域滤波功能,可设置该值范围
int depthnum = 1;
//深度图处理
if (!depth.empty())
{
if (pData->isTof)
{
//TOF相机深度图校正畸变
TY_IMAGE_DATA src;
src.width = depth.cols;
src.height = depth.rows;
src.size = depth.size().area() * 2;
src.pixelFormat = TYPixelFormatCoord3D_C16;
src.buffer = depth.data;
cv::Mat undistort_depth = cv::Mat(depth.size(), CV_16U);
TY_IMAGE_DATA dst;
dst.width = depth.cols;
dst.height = depth.rows;
dst.size = undistort_depth.size().area() * 2;
dst.buffer = undistort_depth.data;
dst.pixelFormat = TYPixelFormatCoord3D_C16;
ASSERT_OK(TYUndistortImage(&cb_data.depth_calib, &src, NULL, &dst));
depth = undistort_depth.clone();
}
if (FillHole)
{
TY_IMAGE_DATA sfFilledDepth;
cv::Mat fillDepth(depth.size(), depth.type());
fillDepth = depth.clone();
mat2TY_IMAGE_DATA(TY_COMPONENT_DEPTH_CAM, fillDepth, sfFilledDepth);
//深度图填洞处理
struct DepthInpainterParameters inpainter = DepthInpainterParameters_Initializer;
inpainter.kernel_size = 10;
inpainter.max_internal_hole = 1800;
TYDepthImageInpainter(&sfFilledDepth, &inpainter);
//空洞填充后度图渲染
depthViewer1.show(fillDepth);
depth = fillDepth.clone();
}
if (SpeckleFilter)
{
//使用星噪滤波
TY_IMAGE_DATA sfFilteredDepth;
cv::Mat filteredDepth(depth.size(), depth.type());
filteredDepth = depth.clone();
mat2TY_IMAGE_DATA(TY_COMPONENT_DEPTH_CAM, filteredDepth, sfFilteredDepth);
struct DepthSpeckleFilterParameters sfparam = DepthSpeckleFilterParameters_Initializer;
sfparam.max_speckle_size = 300;//噪点面积小于该值将被过滤
sfparam.max_speckle_diff = 64;//相邻像素视差大于该值将被视为噪点
TYDepthSpeckleFilter(&sfFilteredDepth, &sfparam);
//显示星噪滤波后深度图渲染
depthViewer2.show(filteredDepth);
depth = filteredDepth.clone();
}
//深度图时域滤波设置
if (EnhenceFilter)
{
depths.push_back(depth.clone());
LOGD("depths_size %d", depths.size());
if (depths.size() >= depthnum)
{
// filter
//LOGD("count %d ", ++cnt);
LOGD("depthnum count %d ", depthnum);
std::vector<TY_IMAGE_DATA> tyDepth(depthnum);
for (size_t i = 0; i < depthnum; i++)
{
mat2TY_IMAGE_DATA(TY_COMPONENT_DEPTH_CAM, depths[i], tyDepth[i]);
}
//使用时域滤波
TY_IMAGE_DATA tyFilteredDepth;
cv::Mat filteredDepth2(depth.size(), depth.type());
mat2TY_IMAGE_DATA(TY_COMPONENT_DEPTH_CAM, filteredDepth2, tyFilteredDepth);
struct DepthEnhenceParameters param = DepthEnhenceParameters_Initializer;
param.sigma_s = 0; //空间滤波系数
param.sigma_r = 0; //深度滤波系数
param.outlier_rate = 0; //以像素为单位的滤波窗口
param.outlier_win_sz = 0.f;//噪音过滤系数
TYDepthEnhenceFilter(&tyDepth[0], depthnum, NULL, &tyFilteredDepth, ¶m);
depths.clear();
//显示时域滤波后深度图渲染
depthViewer3.show(filteredDepth2);
}
}
else if (!FillHole && !SpeckleFilter&& !EnhenceFilter)
{
//显示原深度图渲染
depthViewer0.show(depth);
}
}
//彩色图处理
cv::Mat color_data_mat,p3dtocolorMat, undistort_color;
uint8_t* color_data = NULL;
if (!color.empty())
{
cv::Mat undistort_color, MappedDepth;
bool hasColorCalib = false;
ASSERT_OK(TYHasFeature(pData->hDevice, TY_COMPONENT_RGB_CAM, TY_STRUCT_CAM_CALIB_DATA, &hasColorCalib));
if (hasColorCalib)
{
cv::Mat tmp;
//cv::resize(out, tmp, undistort_color.size(), 0, 0, cv::INTER_NEAREST);
switch (color.type())
{
case CV_16U:
color.convertTo(tmp, CV_8U, 1.f / 256);
cv::cvtColor(tmp, color, cv::COLOR_GRAY2BGR);
break;
case CV_16UC3:
tmp = color;
tmp.convertTo(color, CV_8UC3, 1.f / 256);
break;
default:
break;
}
if (MAP_DEPTH_TO_COLOR)
{
doRegister(pData->depth_calib, pData->color_calib, depth, pData->f_depth_scale, color, color_data_mat, MappedDepth, MAP_DEPTH_TO_COLOR);
//生成对齐到彩色图坐标系的点云,两种方法
//方法一:生成点云放在TY_VECT_3F---P3dtoColor
P3dtoColor.resize(MappedDepth.size().area());
ASSERT_OK(TYMapDepthImageToPoint3d(&pData->color_calib, MappedDepth.cols, MappedDepth.rows, (uint16_t*)MappedDepth.data, &P3dtoColor[0], pData->f_depth_scale));
//方法二:生成点云放在32FC3 Mat---p3dtocolorMat
//p3dtocolorMat = depthToWorld(pData->intri_color->data, MappedDepth, pData->scale_unit);
//显示畸变校正后的彩色图
imshow("undistort_color", color_data_mat);
//显示对齐到彩色图坐标系的深度图
depthViewer4.show(MappedDepth);
}
else
{
//彩色图去畸变,不对齐的深度图
doRegister(pData->depth_calib, pData->color_calib, depth, pData->f_depth_scale, color, color_data_mat, MappedDepth, MAP_DEPTH_TO_COLOR);
//显示畸变校正后的彩色图
imshow("undistort_color", color_data_mat);
//方法一:生成点云放在TY_VECT_3F---P3dtoColor
P3d.resize(MappedDepth.size().area());
ASSERT_OK(TYMapDepthImageToPoint3d(&pData->depth_calib, MappedDepth.cols, MappedDepth.rows
, (uint16_t*)MappedDepth.data, &P3d[0], pData->f_depth_scale));
//方法二 pointcloud in CV_32FC3 format
//newP3d = depthToWorld(pData->intri_depth->data, depth, pData->scale_unit);
}
}
}
//保存点云
//save pointcloud
if (pData->saveOneFramePoint3d)
{
char file[32];
if (MAP_DEPTH_TO_COLOR)
{
LOGD("Save p3dtocolor now!!!");
//保存对齐到color坐标系XYZRGB格式彩色点云
sprintf(file, "pointsToColor-%d.xyz", pData->fileIndex++);
//方式一点云保存
writePointCloud((cv::Point3f*)&P3dtoColor[0], (const cv::Vec3b*)color_data_mat.data, P3dtoColor.size(), file, PC_FILE_FORMAT_XYZ);
//方式二点云保存
//writePointCloud((cv::Point3f*)p3dtocolorMat.data, (const cv::Vec3b*)color_data_mat.data, p3dtocolorMat.total(), file, PC_FILE_FORMAT_XYZ);
}
else
{
LOGD("Save point3d now!!!");
//保存XYZ格式点云
sprintf(file, "points-%d.xyz", pData->fileIndex++);
//方式一点云保存
writePointCloud((cv::Point3f*)&P3d[0], 0, P3d.size(), file, PC_FILE_FORMAT_XYZ);
//方式二点云保存
//writePointCloud((cv::Point3f*)newP3d.data, 0, newP3d.total(), file, PC_FILE_FORMAT_XYZ);
}
pData->saveOneFramePoint3d = false;
}
//归还Buffer队列
LOGD("=== Re-enqueue buffer(%p, %d)", frame->userBuffer, frame->bufferSize);
ASSERT_OK( TYEnqueueBuffer(pData->hDevice, frame->userBuffer, frame->bufferSize) );
}
int main(int argc, char* argv[])
{
std::string ID, IP;
TY_INTERFACE_HANDLE hIface = NULL;
TY_DEV_HANDLE hDevice = NULL;
TY_CAMERA_INTRINSIC intri_depth;
TY_CAMERA_INTRINSIC intri_color;
TY_CAMERA_DISTORTION dist;
TY_CAMERA_EXTRINSIC extri;
int32_t resend = 1;
bool isTof = 1;
for(int i = 1; i < argc; i++)
{
if(strcmp(argv[i], "-id") == 0)
{
ID = argv[++i];
} else if(strcmp(argv[i], "-ip") == 0)
{
IP = argv[++i];
} else if(strcmp(argv[i], "-h") == 0)
{
LOGI("Usage: SimpleView_Callback [-h] [-id <ID>]");
return 0;
}
}
LOGD("=== Init lib");
ASSERT_OK( TYInitLib() );
TY_VERSION_INFO ver;
ASSERT_OK( TYLibVersion(&ver) );
LOGD("- lib version: %d.%d.%d", ver.major, ver.minor, ver.patch);
std::vector<TY_DEVICE_BASE_INFO> selected;
//选择相机
ASSERT_OK( selectDevice(TY_INTERFACE_ALL, ID, IP, 10, selected) );
ASSERT(selected.size() > 0);
//默认加载第一个相机
TY_DEVICE_BASE_INFO& selectedDev = selected[0];
if (TYIsNetworkInterface(selectedDev.iface.type))
{
LOGD(" - device %s:", selectedDev.id);
if (strlen(selectedDev.userDefinedName) != 0)
{
LOGD(" vendor : %s", selectedDev.userDefinedName);
}
else {
LOGD(" vendor : %s", selectedDev.vendorName);
}
LOGD(" model : %s", selectedDev.modelName);
LOGD(" device MAC : %s", selectedDev.netInfo.mac);
LOGD(" device IP : %s", selectedDev.netInfo.ip);
LOGD(" TL version : %s", selectedDev.netInfo.tlversion);
if (strcmp(selectedDev.netInfo.tlversion, "Gige_2_1") == 0)
{
use_new_apis();
}
else
{
use_old_apis();
}
}
else
{
TY_DEV_HANDLE handle;
int32_t ret = TYOpenDevice(hIface, selectedDev.id, &handle);
if (ret == 0)
{
TYGetDeviceInfo(handle, &selectedDev);
TYCloseDevice(handle);
LOGD(" - device %s:", selectedDev.id);
}
else
{
LOGD(" - device %s(open failed, error: %d)", selectedDev.id, ret);
}
if (strlen(selectedDev.userDefinedName) != 0)
{
LOGD(" vendor : %s", selectedDev.userDefinedName);
}
else {
LOGD(" vendor : %s", selectedDev.vendorName);
}
LOGD(" model : %s", selectedDev.modelName);
use_old_apis();
if (!setParameters)
{
std::string js_data;
int ret;
ret = load_parameters_from_storage(hDevice, js_data);//使用相机内保存参数
if (ret == TY_STATUS_ERROR)
{
LOGD("no save parameters in the camera");
setParameters = true;
}
else if (ret != TY_STATUS_OK)
{
LOGD("Failed: error %d(%s)", ret, TYErrorString(ret));
setParameters = true;
}
}
}
//打开接口和设备
ASSERT_OK( TYOpenInterface(selectedDev.iface.id, &hIface) );
ASSERT_OK( TYOpenDevice(hIface, selectedDev.id, &hDevice) );
//使能相机组件
TY_COMPONENT_ID allComps;
ASSERT_OK(TYGetComponentIDs(hDevice, &allComps));
ASSERT_OK(TYDisableComponents(hDevice, allComps));
//使能彩色相机
//try to enable color camera
if (allComps & TY_COMPONENT_RGB_CAM )
{
LOGD("Has RGB camera, open RGB cam");
ASSERT_OK(TYEnableComponents(hDevice, TY_COMPONENT_RGB_CAM));
}
//使能Depth相机
//try to enable color camera
if (allComps & TY_COMPONENT_DEPTH_CAM)
{
LOGD("Has Depth camera, open Depth cam");
ASSERT_OK(TYEnableComponents(hDevice, TY_COMPONENT_DEPTH_CAM));
}
//使能IR相机
//try to enable ir cam
if (allComps & TY_COMPONENT_IR_CAM_LEFT)
{
LOGD("=== Configure components, open ir cam");
ASSERT_OK(TYEnableComponents(hDevice, TY_COMPONENT_IR_CAM_LEFT));
}
//读取彩色相机标定数据
//TY_STRUCT_CAM_CALIB_DATA内参是相机出厂标定分辨率的内参
//TY_STRUCT_CAM_INTRINSIC内参是相机当前分辨率的内参
LOGD("=== Get color intrinsic");
ASSERT_OK(TYGetStruct(hDevice, TY_COMPONENT_RGB_CAM, TY_STRUCT_CAM_INTRINSIC, &intri_color, sizeof(intri_color)));
////打印当前彩色相机分辨率内参,分辨率不同,fx,fy,cx,cy不一样。
//打印这里也可引入C++标准库iomanip,之后调用setw()函数打印
LOGD("===%23s%f %f %f", "", intri_color.data[0], intri_color.data[1], intri_color.data[2]);
LOGD("===%23s%f %f %f", "", intri_color.data[3], intri_color.data[4], intri_color.data[5]);
LOGD("===%23s%f %f %f", "", intri_color.data[6], intri_color.data[7], intri_color.data[8]);
LOGD("=== Read color calib data");
ASSERT_OK(TYGetStruct(hDevice, TY_COMPONENT_RGB_CAM, TY_STRUCT_CAM_CALIB_DATA
, &cb_data.color_calib, sizeof(cb_data.color_calib)));
//读取深度相机内参和深度相机标定数据
//TY_STRUCT_CAM_CALIB_DATA内参是相机出厂标定分辨率的内参
//TY_STRUCT_CAM_INTRINSIC内参是相机当前分辨率的内参
LOGD("=== Get depth intrinsic");
ASSERT_OK(TYGetStruct(hDevice, TY_COMPONENT_DEPTH_CAM, TY_STRUCT_CAM_INTRINSIC, &intri_depth, sizeof(intri_depth)));
////打印当前深度图相机分辨率内参,分辨率不同,fx,fy,cx,cy不一样。
LOGD("===%23s%f %f %f", "", intri_depth.data[0], intri_depth.data[1], intri_depth.data[2]);
LOGD("===%23s%f %f %f", "", intri_depth.data[3], intri_depth.data[4], intri_depth.data[5]);
LOGD("===%23s%f %f %f", "", intri_depth.data[6], intri_depth.data[7], intri_depth.data[8]);
LOGD("=== Read depth calib data");
ASSERT_OK(TYGetStruct(hDevice, TY_COMPONENT_DEPTH_CAM, TY_STRUCT_CAM_CALIB_DATA
, &cb_data.depth_calib, sizeof(cb_data.depth_calib)));
//////获取彩色图畸变系数;
//////跑GM46X最新固件有问题,先屏蔽
//LOGD("=== Get color distortion");
//ASSERT_OK(TYGetStruct(hDevice, TY_COMPONENT_RGB_CAM, TY_STRUCT_CAM_DISTORTION, &dist, sizeof(dist)));
//LOGD("===%23s%f %f %f %f", "", dist.data[0], dist.data[1], dist.data[2], dist.data[3]);
//LOGD("===%23s%f %f %f %f", "", dist.data[4], dist.data[5], dist.data[6], dist.data[7]);
//LOGD("===%23s%f %f %f %f", "", dist.data[8], dist.data[9], dist.data[10], dist.data[11]);
////获取RGB至相机左IR的外参
// //TY_STRUCT_EXTRINSIC_TO_IR_LEFT
//////跑GM46X最新固件有问题,先屏蔽
//
//ASSERT_OK(TYGetStruct(hDevice, TY_COMPONENT_RGB_CAM_LEFT, TY_STRUCT_EXTRINSIC_TO_DEPTH, &extri, sizeof(extri)));
//LOGD("===%23s%f %f %f %f", "", extri.data[0], extri.data[1], extri.data[2], extri.data[3]);
//LOGD("===%23s%f %f %f %f", "", extri.data[4], extri.data[5], extri.data[6], extri.data[7]);
//LOGD("===%23s%f %f %f %f", "", extri.data[8], extri.data[9], extri.data[10], extri.data[11]);
//LOGD("===%23s%f %f %f %f", "", extri.data[12], extri.data[13], extri.data[14], extri.data[15]);
//获取所需Buffer大小
LOGD("=== Prepare image buffer");
uint32_t frameSize;
ASSERT_OK( TYGetFrameBufferSize(hDevice, &frameSize) );
LOGD(" - Get size of framebuffer, %d", frameSize);
//分配两个Buffer,并压入队列
LOGD(" - Allocate & enqueue buffers");
char* frameBuffer[2];
frameBuffer[0] = new char[frameSize];
frameBuffer[1] = new char[frameSize];
LOGD(" - Enqueue buffer (%p, %d)", frameBuffer[0], frameSize);
ASSERT_OK( TYEnqueueBuffer(hDevice, frameBuffer[0], frameSize) );
LOGD(" - Enqueue buffer (%p, %d)", frameBuffer[1], frameSize);
ASSERT_OK( TYEnqueueBuffer(hDevice, frameBuffer[1], frameSize) );
//注册事件回调
bool device_offline = false;;
LOGD("=== Register event callback");
ASSERT_OK(TYRegisterEventCallback(hDevice, eventCallback, &device_offline));
////触发模式设置
//bool hasTrigger;
//ASSERT_OK(TYHasFeature(hDevice, TY_COMPONENT_DEVICE, TY_STRUCT_TRIGGER_PARAM, &hasTrigger));
//if (hasTrigger)
//{
// TY_TRIGGER_PARAM trigger;
// LOGD("=== enable trigger mode");
// //trigger.mode = TY_TRIGGER_MODE_OFF;
// trigger.mode = TY_TRIGGER_MODE_SLAVE;//软触发和硬触发模式
// ASSERT_OK(TYSetStruct(hDevice, TY_COMPONENT_DEVICE, TY_STRUCT_TRIGGER_PARAM, &trigger, sizeof(trigger)));
//
//
//}
ASSERT_OK(TYEnumSetString(hDevice, "AcquisitionMode", "SingleFrame"));
ASSERT_OK(TYEnumSetString(hDevice, "TriggerSource", "Software"));//触发源是软触发
//4.0.7之后版本的SDK,删除Resned开关,逻辑修改为相机支持则默认打开。
////for network only
//LOGD("=== resend: %d", resend);
//if (resend)
//{
// bool hasResend;
// ASSERT_OK(TYHasFeature(hDevice, TY_COMPONENT_DEVICE, TY_BOOL_GVSP_RESEND, &hasResend));
// if (hasResend)
// {
// LOGD("=== Open resend");
// ASSERT_OK(TYSetBool(hDevice, TY_COMPONENT_DEVICE, TY_BOOL_GVSP_RESEND, true));
// }
// else
// {
// LOGD("=== Not support feature TY_BOOL_GVSP_RESEND");
// }
//}
//开始采集
LOGD("=== Start capture");
ASSERT_OK( TYStartCapture(hDevice) );
//回调数据初始化
cb_data.index = 0;
cb_data.hDevice = hDevice;
cb_data.saveOneFramePoint3d = false;
cb_data.fileIndex = 0;
// cb_data.intri_depth = &intri_depth;
// cb_data.intri_color = &intri_color;
//float scale_unit = 1.;
float scale_unit =1.;
TYGetFloat(hDevice, TY_COMPONENT_DEPTH_CAM, TY_FLOAT_SCALE_UNIT, &scale_unit);
std::cout << "scale_uint:" << scale_unit << std::endl;
cb_data.f_depth_scale = scale_unit;
cb_data.isTof = isTof;
depthViewer0.depth_scale_unit = scale_unit;
depthViewer1.depth_scale_unit = scale_unit;
depthViewer2.depth_scale_unit = scale_unit;
depthViewer3.depth_scale_unit = scale_unit;
depthViewer4.depth_scale_unit = scale_unit;
//循环取图
LOGD("=== While loop to fetch frame");
TY_FRAME_DATA frame;
bool exit_main = false;
int index = 0;
uint32_t source = 8;
while(!exit_main)
{
int key = cv::waitKey(1);
switch(key & 0xff)
{
case 0xff:
break;
case 'q':
exit_main = true;
break;
case 's':
cb_data.saveOneFramePoint3d = true;//图片显示窗口上按s键则存一张点云图
break;
default:
LOGD("Pressed key %d", key);
}
auto timeTrigger = std::chrono::steady_clock::now();
//GM461相机发送一次软触发
if (source == 8)
{
ASSERT_OK(TYCommandExec(hDevice, "TriggerSoftware"));
std::cout << "triggermode:" << source << std::endl;
}
//旧相机的发送软触发指令
//while (TY_STATUS_BUSY == TYSendSoftTrigger(hDevice));
//获取帧,默认超时设置为8s
int err = TYFetchFrame(hDevice, &frame, 8000);
//获取图像时间戳代码
LOGD("=== Time Stamp (%" PRIu64 ")", frame.image[0].timestamp);
time_t tick = (time_t)(frame.image[0].timestamp / 1000000);
struct tm tm;
char s[100];
tm = *localtime(&tick);
strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", &tm);
int milliseconds = (int)((frame.image[0].timestamp % 1000000) / 1000);
char ms_str[5];
sprintf(ms_str, ".%d", milliseconds);
strcat(s, ms_str);
LOGD("===Time Stamp %d:%s\n", (int)tick, s);
auto timeGetFrame = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(timeGetFrame - timeTrigger);
LOGI("*******FetchFrame spend Time : %lld", duration);
if( err != TY_STATUS_OK )
{
LOGD("... Drop one frame");
continue;
}
if (err == TY_STATUS_OK)
{
LOGD("Get frame %d", ++index);
int fps = get_fps();
if (fps > 0)
{
LOGI("***************************fps: %d", fps);
}
}
frameHandler(&frame, &cb_data);
}
ASSERT_OK( TYStopCapture(hDevice) );
ASSERT_OK( TYCloseDevice(hDevice) );
ASSERT_OK( TYCloseInterface(hIface) );
ASSERT_OK( TYDeinitLib() );
delete frameBuffer[0];
delete frameBuffer[1];
LOGD("=== Main done!");
return 0;
}
3.1.2 GM465-E1相机软触发注意事项
建议选择下面软触发指令,依次时选择触发模式 --->选择触发源 --->发送软触发指令
cpp
ASSERT_OK(TYEnumSetString(hDevice, "AcquisitionMode", "SingleFrame"));
ASSERT_OK(TYEnumSetString(hDevice, "TriggerSource", "Software"));//触发源是软触发
ASSERT_OK(TYCommandExec(hDevice, "TriggerSoftware"));//通过此命令控制相机采图
3.1.3 TYSendSoftTrigger软触发指令不生效
而之前的Sample_V1里面提供的,对GM465-E1/相机是不生效的。
cpp
//触发模式设置
bool hasTrigger;
ASSERT_OK(TYHasFeature(hDevice, TY_COMPONENT_DEVICE, TY_STRUCT_TRIGGER_PARAM, &hasTrigger));
if (hasTrigger)
{
TY_TRIGGER_PARAM trigger;
//trigger.mode = TY_TRIGGER_MODE_OFF;//连续采集模式
LOGD("=== enable trigger mode");
trigger.mode = TY_TRIGGER_MODE_SLAVE;//软触发和硬触发模式
ASSERT_OK(TYSetStruct(hDevice, TY_COMPONENT_DEVICE, TY_STRUCT_TRIGGER_PARAM, &trigger, sizeof(trigger)));
//bool hasDI0_WORKMODE;
//ASSERT_OK(TYHasFeature(hDevice, TY_COMPONENT_DEVICE, TY_STRUCT_DI0_WORKMODE, &hasDI0_WORKMODE));
//if (hasDI0_WORKMODE)
//{
// //硬触发模式防抖
// TY_DI_WORKMODE di_wm;
// di_wm.mode = TY_DI_PE_INT;
// di_wm.int_act = TY_DI_INT_TRIG_CAP;
// uint32_t time_hw = 10;//单位ms,硬件滤波,小于设定时间的电平信号会被过滤
// uint32_t time_sw = 200;//单位ms,软件滤波,连续高频触发情形,小于设置周期的后一个触发信号将被过滤
// di_wm.reserved[0] = time_hw | (time_sw << 16);
// ASSERT_OK(TYSetStruct(hDevice, TY_COMPONENT_DEVICE, TY_STRUCT_DI0_WORKMODE, &di_wm, sizeof(di_wm)));
//}
}
旧相机(GM46X和PMD系列相机除外)支持的软触发指令
cpp
auto timeTrigger = std::chrono::steady_clock::now();
//发送一次软触发
while (TY_STATUS_BUSY == TYSendSoftTrigger(hDevice));
//获取帧,默认超时设置为10s
int err = TYFetchFrame(hDevice, &frame, 3000);
auto timeGetFrame = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(timeGetFrame - timeTrigger);
LOGI("*******FetchFrame spend Time : %lld", duration);
3.1.4 GM465-E1相机推荐SDK版本

1.如果固件是0.0.106版本及其以前版本,推荐使用4.1.1版本(无痛切换)
2.如果固件是1.0.X版本以上,推荐使用4.1.14及其以上版本(引入了tyimgproc.dll)
3.1.5 C++语言SDK升级注意事项
待补充
3.2 ROS1版本(推荐)
GM465-E1相机,只能搭配4.X.X版本的SDK使用,如果相机固件是106版本之后的,需要配合使用最新版本的SDK(4.1.9版本及以上)和最新版本的Viewer。
具体操作和Sample和案例,可打开如下链接:
图漾相机-ROS1_SDK_ubuntu 4.X.X版本编译
1.GM465-E1 相机,推荐使用4.1.14及其以上SDK版本(引入了tyimgproc.dll)。
2.目前官网ROS1的SDK还是4.0.21版本,建议联系图漾技术获取最新版本的ROS1的SDK。
3.3 ROS2版本(推荐)
GM465-E1相机,只能搭配4.X.X版本的SDK使用,如果相机固件是106版本之后的,需要配合使用最新版本的SDK(4.1.9版本及以上)、最新版本的Viewer。
具体操作和Sample和案例,可打开如下链接:
图漾相机-ROS2-SDK-Ubuntu 4.X.X版本编译
1.GM465-E1 相机,推荐使用4.1.14及其以上SDK版本(引入了tyimgproc.dll)。
2.目前官网ROS2的SDK还是4.0.21版本,建议联系图漾技术获取最新版本的ROS2的SDK。
3.4 C#语言SDK
新的看图软件,自带的C#例程比较简陋。
如需要使用,请联系图漾技术获取新的看图软件和SDK接口手手册。

3.5 Python语言SDK
新的看图软件,自带的Python例程比较简陋。
如需要使用,请联系图漾技术获取新的看图软件和SDK接口手手册。

4.GM465-E1相机常见FAQ
4.1 如何获取GM465-E1相机内参?
4.1.1 方法一 运行sample_read_calibration_data
编译C++语言中的sample_read_calibration_data 例子,之后运行,会打印GM461相机的内参。

4.1.2 方法二 运行x64中的例子
使用本贴子中的x64 压缩包,通过鼠标右键+shift键 ,进入到PowerShell界面,运行sample_read_calibration_data例子,详细步骤如下:

4.1.3 方法三 运行DumpCalibInfo
编译C++语言中的例子,之后运行Sample_V1文件夹中的DumpCalibInfo 例子,会生成一个json文件,里面记录GM465--E1相机的内外参信息。

生成的json文件如下图:
cpp
{
"sn": "207000166286",
"timestamp": "2025-12-07 12:04:45",
"depth_calib_info" : {
"intri": [
796.573975,
0.000000,
623.528137,
0.000000,
796.573975,
524.820496,
0.000000,
0.000000,
1.000000
],
"image_width": 1280,
"image_height": 960,
"scale_unit": 1.000000
},
"color_calib_info" : {
"intri": [
806.483154,
0.000000,
679.170349,
0.000000,
806.446960,
509.685120,
0.000000,
0.000000,
1.000000
],
"extri": [
0.999996,
0.001604,
-0.002481,
10.541627,
-0.001618,
0.999982,
-0.005724,
0.038848,
0.002472,
0.005728,
0.999981,
-0.076800,
0.000000,
0.000000,
0.000000,
1.000000,
0.417379
],
"distortion": [
0.417379,
0.724274,
-0.000041,
0.000845,
0.791459,
0.433178,
0.647546,
0.883819,
-0.000347,
-0.001221,
-0.000396,
-0.000046
],
"image_width": 1280,
"image_height": 960
}
}
4.2 GM465-E1相机内参说明
运行sample_read_calibration_data例子,打印出来的内参如下:
cpp
Depth
IntrinsicWidth: 1280
IntrinsicHeight: 960
Intrinsic:Camera intrinsic parameter matrix (3x3) containing focal lengths (fx,fy) and principal point (cx,cy). Stored as 9 double values in row-major order.
796.574002 0.000000 623.528156
0.000000 796.574002 524.820467
0.000000 0.000000 1.000000
No rectifyed intrinsic data.
No rotation data.
No distortion data.
No extrinsic data.
Texture
IntrinsicWidth: 1280
IntrinsicHeight: 960
Intrinsic:Camera intrinsic parameter matrix (3x3) containing focal lengths (fx,fy) and principal point (cx,cy). Stored as 9 double values in row-major order.
806.483170 0.000000 679.170352
0.000000 806.446980 509.685109
0.000000 0.000000 1.000000
No rectifyed intrinsic data.
No rotation data.
Distortion:Camera distortion coefficients (12x1 vector) including radial (k1-k6), tangential (p1-p2), and prism (s1-s4) distortions. Stored as 12 double values.
0.417379 0.724274 -0.000041 0.000845 0.791459 0.433178 0.647546 0.883819 -0.000347 -0.001221 -0.000396 -0.000046
Extrinsic:Camera extrinsic matrix (4x4) containing rotation and translation relative to world coordinate system. Stored as 16 double values in row-major order.
0.999996 0.001604 -0.002481 10.541627
-0.001618 0.999982 -0.005724 0.038848
0.002472 0.005728 0.999981 -0.076800
0.000000 0.000000 0.000000 1.000000
Left
IntrinsicWidth: 1280
IntrinsicHeight: 960
Intrinsic:Camera intrinsic parameter matrix (3x3) containing focal lengths (fx,fy) and principal point (cx,cy). Stored as 9 double values in row-major order.
806.586392 0.000000 643.286915
0.000000 806.743459 528.616193
0.000000 0.000000 1.000000
Rectifyed intrinsic:Rectified camera intrinsic parameter matrix (3x3) after distortion correction. Contains modified focal lengths and principal point. Stored as 9 double values.
796.574002 0.000000 623.528156
0.000000 796.574002 524.820467
0.000000 0.000000 1.000000
Rotation:Camera rotation matrix (3x3) representing orientation in 3D space. Orthonormal matrix with determinant +1. Stored as 9 double values in row-major order.
0.999786 -0.016189 0.012876
0.016139 0.999862 0.003965
-0.012939 -0.003756 0.999909
Distortion:Camera distortion coefficients (12x1 vector) including radial (k1-k6), tangential (p1-p2), and prism (s1-s4) distortions. Stored as 12 double values.
0.063406 0.714537 0.005509 0.004339 0.888911 0.088787 0.637815 0.982104 -0.006173 0.001521 -0.006877 0.000288
Extrinsic:Camera extrinsic matrix (4x4) containing rotation and translation relative to world coordinate system. Stored as 16 double values in row-major order.
1.000000 0.000000 0.000000 0.000000
0.000000 1.000000 0.000000 0.000000
0.000000 0.000000 1.000000 0.000000
0.000000 0.000000 0.000000 1.000000
Right
IntrinsicWidth: 1280
IntrinsicHeight: 960
Intrinsic:Camera intrinsic parameter matrix (3x3) containing focal lengths (fx,fy) and principal point (cx,cy). Stored as 9 double values in row-major order.
805.869688 0.000000 611.506091
0.000000 806.044896 520.463614
0.000000 0.000000 1.000000
Rectifyed intrinsic:Rectified camera intrinsic parameter matrix (3x3) after distortion correction. Contains modified focal lengths and principal point. Stored as 9 double values.
796.574002 0.000000 623.528156
0.000000 796.574002 524.820467
0.000000 0.000000 1.000000
Rotation:Camera rotation matrix (3x3) representing orientation in 3D space. Orthonormal matrix with determinant +1. Stored as 9 double values in row-major order.
0.999980 0.001923 -0.005954
-0.001946 0.999991 -0.003855
0.005946 0.003866 0.999975
Distortion:Camera distortion coefficients (12x1 vector) including radial (k1-k6), tangential (p1-p2), and prism (s1-s4) distortions. Stored as 12 double values.
0.029058 0.602260 0.001870 -0.001230 0.905308 0.057339 0.524205 0.999930 0.002434 -0.000969 -0.001922 -0.000064
Extrinsic:Camera extrinsic matrix (4x4) containing rotation and translation relative to world coordinate system. Stored as 16 double values in row-major order.
0.999658 -0.018157 0.018814 -66.032819
0.018012 0.999807 0.007856 -0.126984
-0.018953 -0.007514 0.999792 0.393137
0.000000 0.000000 0.000000 1.000000
4.2.1 深度图内参
cpp
Depth
IntrinsicWidth: 1280
IntrinsicHeight: 960
Intrinsic:Camera intrinsic parameter matrix (3x3) containing focal lengths (fx,fy) and principal point (cx,cy). Stored as 9 double values in row-major order.
796.574002 0.000000 623.528156
0.000000 796.574002 524.820467
0.000000 0.000000 1.000000
No rectifyed intrinsic data.
No rotation data.
No distortion data.
No extrinsic data.

1.cx和cy通常大约是图像分辨率W和H的一半,得出GM461相机深度图出厂标定分辨率为1280x960 。
2.由于深度相机是虚拟相机,所以其畸变参数以及外参都是零矩阵。
4.2.2 彩色图内参/畸变系数/外参
cpp
Texture
IntrinsicWidth: 1280
IntrinsicHeight: 960
Intrinsic:Camera intrinsic parameter matrix (3x3) containing focal lengths (fx,fy) and principal point (cx,cy). Stored as 9 double values in row-major order.
806.483170 0.000000 679.170352
0.000000 806.446980 509.685109
0.000000 0.000000 1.000000
No rectifyed intrinsic data.
No rotation data.
Distortion:Camera distortion coefficients (12x1 vector) including radial (k1-k6), tangential (p1-p2), and prism (s1-s4) distortions. Stored as 12 double values.
0.417379 0.724274 -0.000041 0.000845 0.791459 0.433178 0.647546 0.883819 -0.000347 -0.001221 -0.000396 -0.000046
1.cx和cy通常大约是图像分辨率W和H的一半,得出GM461相机深度图出厂标定分辨率为1280x960
2.彩色图相机的畸变系数如下:

cpp
用TYGetEnum(hDevice, comp_id, TY_ENUM_LENS_OPTICAL_TYPE, &lens_tpye)来区分新旧相机。
//TY_LENS_PINHOLE是小孔成像,RGB畸变系数依次是k1,k2,p1,p2,k3,k4,k5,k6,s1,s2,s3,s4
//TY_LENS_FISHEYE是新的鱼眼标定,RGB畸变系数依次是k1,k2,k3,k4
3.彩色图相机的外参如下:

4.2.3 左右IR极限约束前内参/极限校正后内参

双目立体匹配模型

cpp
Left
IntrinsicWidth: 1280
IntrinsicHeight: 960
Intrinsic:Camera intrinsic parameter matrix (3x3) containing focal lengths (fx,fy) and principal point (cx,cy). Stored as 9 double values in row-major order.
806.586392 0.000000 643.286915
0.000000 806.743459 528.616193
0.000000 0.000000 1.000000
Rectifyed intrinsic:Rectified camera intrinsic parameter matrix (3x3) after distortion correction. Contains modified focal lengths and principal point. Stored as 9 double values.
796.574002 0.000000 623.528156
0.000000 796.574002 524.820467
0.000000 0.000000 1.000000
Rotation:Camera rotation matrix (3x3) representing orientation in 3D space. Orthonormal matrix with determinant +1. Stored as 9 double values in row-major order.
0.999786 -0.016189 0.012876
0.016139 0.999862 0.003965
-0.012939 -0.003756 0.999909
Distortion:Camera distortion coefficients (12x1 vector) including radial (k1-k6), tangential (p1-p2), and prism (s1-s4) distortions. Stored as 12 double values.
0.063406 0.714537 0.005509 0.004339 0.888911 0.088787 0.637815 0.982104 -0.006173 0.001521 -0.006877 0.000288
Extrinsic:Camera extrinsic matrix (4x4) containing rotation and translation relative to world coordinate system. Stored as 16 double values in row-major order.
1.000000 0.000000 0.000000 0.000000
0.000000 1.000000 0.000000 0.000000
0.000000 0.000000 1.000000 0.000000
0.000000 0.000000 0.000000 1.000000
cpp
Right
IntrinsicWidth: 1280
IntrinsicHeight: 960
Intrinsic:Camera intrinsic parameter matrix (3x3) containing focal lengths (fx,fy) and principal point (cx,cy). Stored as 9 double values in row-major order.
805.869688 0.000000 611.506091
0.000000 806.044896 520.463614
0.000000 0.000000 1.000000
Rectifyed intrinsic:Rectified camera intrinsic parameter matrix (3x3) after distortion correction. Contains modified focal lengths and principal point. Stored as 9 double values.
796.574002 0.000000 623.528156
0.000000 796.574002 524.820467
0.000000 0.000000 1.000000
Rotation:Camera rotation matrix (3x3) representing orientation in 3D space. Orthonormal matrix with determinant +1. Stored as 9 double values in row-major order.
0.999980 0.001923 -0.005954
-0.001946 0.999991 -0.003855
0.005946 0.003866 0.999975
Distortion:Camera distortion coefficients (12x1 vector) including radial (k1-k6), tangential (p1-p2), and prism (s1-s4) distortions. Stored as 12 double values.
0.029058 0.602260 0.001870 -0.001230 0.905308 0.057339 0.524205 0.999930 0.002434 -0.000969 -0.001922 -0.000064
Extrinsic:Camera extrinsic matrix (4x4) containing rotation and translation relative to world coordinate system. Stored as 16 double values in row-major order.
0.999658 -0.018157 0.018814 -66.032819
0.018012 0.999807 0.007856 -0.126984
-0.018953 -0.007514 0.999792 0.393137
0.000000 0.000000 0.000000 1.000000
4.3 GM465-E1相机光心位置
散斑相机以左IR 为光心。

同时通过Texture (彩色)外参,可得知Texture至左IR应该在10mm左右。
cpp
Extrinsic:Camera extrinsic matrix (4x4) containing rotation and translation relative to world coordinate system. Stored as 16 double values in row-major order.
0.999996 0.001604 -0.002481 10.541627
-0.001618 0.999982 -0.005724 0.038848
0.002472 0.005728 0.999981 -0.076800
0.000000 0.000000 0.000000 1.000000
5.GM465-E1相机测试结果
5.1 GM465-E1 帧率测试
5.1.1 GM465-E1 出图延迟时间
出图延迟时间 :相机使用默认UserSet,在连续采集模式下统计从开始曝光到系统完全处理完图像的总之时间,单位微秒。
UserSet0 :三帧模式,关闭后处理滤波,开启AEC。
UserSet1 :单帧模式,开启后处理滤波,开启AEC。
说明 :
Depth/Texture:Bin1- 1280x960,Bin2- 640x480,Bin4-320x240。
出图延时时间测试结果如下所示:

GM465-E1相机出图延迟时间结果
5.1.2 GM465-E1 帧率测试
FPS(帧率) :指相机设置在自由采集模式下,上位机每秒采集的图像帧数。
UserSet0 :三帧模式,关闭后处理滤波,开启AEC。
UserSet1 :单帧模式,开启后处理滤波,开启AEC。
说明 :
Depth/Texture:Bin1- 1280x960,Bin2- 640x480,Bin4-320x240。
GM465-E1帧率测试结果如下所示:


GM465-E1相机帧率结果
6.成像问题FAQ
6.1 拍摄低反或者高亮材质,点云缺失
6.1.1 开启/关闭纹理滤波
纹理滤波参数
| 纹理滤波属性 | 参数及描述 | 描述 |
|---|---|---|
| DepthSgbmTextureFilterEnable | 纹理滤波使能开关 | true/false |
| DepthSgbmTextureFilterMaxDistance | 纹理滤波最大有效距离 | [0,20000] |
| DepthSgbmTextureFilterThreshold | 纹理滤波梯度阈值 | [0,512] |
| DepthSgbmTextureFilterValue0ffset | 纹理滤波偏移值 | [0,512] |
| DepthSgbmTextureFilterWindowSize | 纹理滤波的滑动窗⼝⼤⼩ | [7,71] |
1.如果图像缺失较多,首先调整降低DepthSgbmTextureFilterMaxDistance有效距离距离--->之后降低DepthSgbmTextureFilterThreshold---->之后降低DepthSgbmTextureFilterValue0ffset---->增大DepthSgbmTextureFilterWindowSize

2.如果还是不行,建议关闭纹理滤波。
6.1.2 调整左右IR参数

根据设置的AOI 区域的图像信息,来调整整个画面的亮度。
调整逻辑
1. 如果检测到划定区域的亮度较低 ,算法"觉得"应该增强 亮度,于是会调亮图像画面。
2. 如果检测到划定区域的亮度较亮 ,算法"觉得"应该减弱 亮度,于是会调暗图像画面。
7.常见问题FAQ
7.1 图漾相机获取的是有序点云还是无序点云?
看图软件和SDK获取的都是无序点云。
1.通过看图软件保存.pcd格式点云,之后通过Notepad++软件打开,打开.pcd格式点云,会发现如下:

HEIGHT :用点的数目表示点云数据集的度,HEIGHT有两层解释:
1)它表示有序点云数据集的高度(行的总数);
2)对于无序数据集它被设置成1(被用来检查一个数据集是有序还是无序)。
有序点云例子:
cpp
WIDTH 640 # 像图像一样的有序结构,有640行和480列,
HEIGHT 480 # 这样该数据集中共有640*480=307200个点
无序点云例子:
cpp
WIDTH 307200
HEIGHT 1 # 有307200个点的无序点云数据集
7.1.1 PCD文件数据
cpp
# .PCD v.7 - Point Cloud Data file format
VERSION .7 # 版本号
FIELDS x y z rgb # 指定一个点可以有的每一个维度和字段的名字
SIZE 4 4 4 4 # 用字节数指定每一个维度的大小。例如:
TYPE F FFF # 用一个字符指定每一个维度的类型 int uint folat
COUNT 1 1 1 1 # 指定每一个维度包含的元素数目
WIDTH 640 # 像图像一样的有序结构,有640行和480列,
HEIGHT 480 # 这样该数据集中共有640*480=307200个点
VIEWPOINT 0 0 0 1 0 0 0 # 指定数据集中点云的获取视点 视点信息被指定为平移(txtytz)+四元数(qwqxqyqz)
POINTS 307200 # 指定点云中点的总数。从0.7版本开始,该字段就有点多余了
DATA ascii # 指定存储点云数据的数据类型。支持两种数据类型:ascii和二进制
0.93773 0.33763 0 4.2108e+06
0.90805 0.35641 0 4.2108e+06
详情可参考双愚PCL
7.2 相机是否带IMU?
目前基线版本是不带的。
8.GM465相机属性表

8.1 DeviceControl模块
主要包含读取相机设备信息等测试。

8.2 AcquisitionControl模块
主要包含相机采集的工作模式、曝光参数测试曝光参数的测试在 SourceControl 模块中进行。

8.3 TransportLayerControl模块
主要包含相机网络方面的参数测试.

8.4 SourceControl模块
主要包含 Depth 组件、Texture 组件、Left/Right 组件及其相关参数的测试。
8.4.1 Depth组件

8.4.2 Left和Right组件

8.4.3 Texture组件

8.5 LightControl模块
主要包含激光以及泛光的参数测试

8.6 ImageFormatControl模块
主要包含图像分辨率、图像格式、数据流的使能/失能测试。

8.7 UserSetControl模块
主要包含相机参数保存到用户集的功能测试。

8.8 FileAccessControl模块

8.8.1 FileAccess介绍
为了防止文件共享可能会导致文件被破坏或未经核准的用户修改文件,文件系统必须控制用户对文件的存取,即解决对文件的读、写、执行的许可问题。
为此,必须在文件系统中建立相应的文件保护机制。FileAcces 在GenICam手册中的标准术语是 File Access Control,中文理解意思就是文件访问控制,描述了设备中与访问文件相关的所有特性。
它包含符合GenICam的设备的通用文件访问模式的定义。
它基于一组标准特性,这些特性由设备中的适配器代码控制GenICam参考实现。适配器代码通过继承自std::iostream的接口提供它的服务。 下面的图表描述了控制所基于的模型:

它确保可以在持久性存储上执行的所有操作都可以由使用语义为fopen/fclose/fread/
Fwrite的操作。操作及其参数映射到文件访问控制列表的功能上。
为了在文件访问控制之上提供通用API,GenApi中定义了FileAccessAdapter。适配器为设备文件提供两个iostream接口:
• IDevFileStream 从设备中读取
• ODevFileStream 写入设备
文件协议适配器(fileaccess adapter)负责映射文件访问控制上的(I/O)数据流(DevFileStreamBuf)操作打开、关闭、下溢(UnderFlow)和溢出(Overflow)。
8.8.2 FileAccess初探
适配器的作用主要是在读数据和写数据上,所以关于Fileaccess的使用也就不复杂了,主要是这两个部分,当写数据的时候,打开文件,从缓冲区读取数据,写入到内存flash 中,最后关闭文件;
读数据的时候,打开文件,将数据从内存中取出来,存放在缓冲区,最后关闭文件。当然每次读取和写入的字节大小可以由程序员自己选择,作用的次数也就不一样了。

8.8.3 节点解释
1.文件选择器(FileSelector):选择设备中用于操作的目标文件。此枚举的条目定义设备中可通过文件访问访问的所有文件的名称。
文件操作选择器(FileOperaSelector):指定要对文件执行的操作;
文件操作执行(FileOperationExecute):命令启动所选的操作执行;
文件打开模式(FileOpenMode):是Open操作的参数,并控制访问模式(读、写、读写),在其中打开文件
文件操作状态(FileOperationStatus):返回在文件上执行的最后一个操作的状态。如果操作按照请求执行,该特性必须返回Success。
文件操作结果(FileOperationResult):返回上一次读或写操作中成功读/写的字节数。
文件大小(FileSize):以字节为单位返回文件的大小;
文件偏移位置(FileAccessOffset):控制文件中访问的起始位置;
文件长度(FileAccessLength):控制在接下来的读或写操作期间要传输到或从FileAccessBuffer的字节数
总之,FileSelector、FileAccessOffset和FileAccessLength特性控制了设备文件存储和FileAccessBuffer之间的映射。

9.其他学习资料
1. 图漾官网相机规格书