配置3D相机曝光
写在前面
本人从事机器视觉细分的3D相机行业。编写此系列文章主要目的有:
1、便利他人应用3D相机,本系列文章包含公司所出售相机的SDK的使用例程及详细注释; 2、促进行业发展及交流。 欢迎与我深入交流:微信号:liu_zhisensor
配置相机曝光及API说明
相机曝光说明
知微传感Dkam系列3D相机具备灵活的曝光配置功能,广泛适应各种复杂的场景,如同一场景内存在反射率相差太大的两种物体 Dkam系列3D相机有自动曝光和手动曝光两种曝光模式
自动曝光模式下不允许配置曝光时间 手动曝光模式下允许自由配置曝光重数(重复曝光的次数)和曝光时间
多重曝光策略下,曝光时间渐变方法分为等差和等比,即只给定高曝光时间和低曝光时间
比如,配置为3重曝光,低曝光值为10000,高曝光值为40000,在等差模式下,3重曝光的曝光时间分别为10000us、25000us、40000us,在等比模式下,3重曝光的曝光时间分别为10000us、20000us、40000us 多重曝光利用朴素的叠加思想,将每重曝光的有效点进行叠加得到有效点最多的数据 多重曝光的曝光重数上限根据型号不同 曝光时间的上限为100000,单位为us
曝光模式
自动曝光
单重曝光
手动曝光
单重曝光
多重曝光
等差曝光时间
等比曝光时间
Dkam系列3D相机未作任何配置时默认自动曝光和单重曝光 3D相机数据输出的帧率随曝光时间的变化而变化,曝光重数越大,曝光时间越长,帧率越慢
配置流程
连接相机
配置相机为自动曝光或不配置
配置相机为手动曝光
配置相机为单重曝光
配置相机曝光时间
配置相机为多重曝光
配置相机曝光重数
配置相机曝光时间渐变方法
配置相机的高,低曝光时间
采集数据,保存数据
结束
相关API
SetAutoExposure配置相机的曝光模式
int SetAutoExposure(Camera_Object_C* camera_obj, int status,int camera_cnt) 函数功能: 设置曝光模式 参 数: camera_obj:相机的结构体指针; status:曝光模式选择(0 自动曝光 1 手动曝光) camera_cn:CMOS 编号(0:红外 1:RGB) 返回值: 0:设置正常 非 0:设置失败 SetMutipleExposure配置相机曝光重数
int SetMutipleExposure(Camera_Object_C* camera_obj, int stat 函数功能: 设置曝光重数 参 数: camera_obj:相机的结构体指针;status:曝光类型选择(1 单曝光 大于 1(整数)多重曝光) 返回值: 0:设置成功;非 0:设置失败 SetExposureTime配置相机曝光时间
int SetExposureTime(Camera_Object_C* camera_obj,int utime, int camera_cnt) 函数功能: 设置指定相机的曝光时间 参 数: camera_obj:相机的结构体指针;utime:曝光时间: 红外镜头范围 1000 - 100000us, RGB 镜头范围 1000 - 56000us, 默认 16600us; camera_cnt:CMOS 编号(0 红外 1RGB) 返回值: 0:设置成功 非 0:设置失败 SetMultiExpoMode 配置相机曝光时间的渐变方法
int SetMultiExpoMode(int mode) 函数功能:设置相机多重曝光模式 参数:mode:多重曝光模式(0/等差 1/等比) 返回值:0 设置成功 非 0 设置失败 SetMultiExpoMin 配置起始曝光时间
int SetMultiExpoMin(Camera_Object_C* camera_obj, int value) 函数功能:设置相机多重曝光起点 参数: camera_obj:相机的结构体指针 int value:范围:1000-100000,us 返回值:0 设置成功 非 0 设置失败 SetMultiExpoMax 配置起始曝光时间
int SetMultiExpoMax(Camera_Object_C* camera_obj, int value) 函数功能:设置相机多重曝光起点 参数: camera_obj:相机的结构体指针 int value:范围:1000-100000,us 返回值:0 设置成功 非 0 设置失败
例程及注释
本例程基于WIN10+VisualStudio2019+DkamSDK_1.6.71,采用C++语言 DkamSDK的配置方法请参考SDK说明书 本例程在D132S型相机上验证 本例针对点云的效果,仅示例了红外的曝光配置
// Exposure.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <cstring>
//DkamSDK
#include"dkam_discovery.h"
#include"dkam_gige_camera.h"
#include"dkam_gige_stream.h"
int main()
{
std::cout << "Hello ZhiSENSOR!"<<std::endl;
std::vector<DiscoveryInfo> discovery_info;
Discovery discovery;
GigeCamera camera;
GigeStream* pointgigestream = NULL;
GigeStream* graygigestream = NULL;
GigeStream* rgbgigestream = NULL;
std::vector<DiscoveryInfo>().swap(discovery_info);
//**********************************************查询相机****************************************************
//查询局域网内的3D相机
int camer_num = discovery.DiscoverCamera(&discovery_info);
std::cout << "局域网内共有" << camer_num << "台相机" << std::endl;
//显示局域网内相机的IP
for (int i = 0; i < camer_num; i++)
{
std::cout << "局域网内相机的IP为:" << discovery.ConvertIpIntToString(discovery_info[i].camera_ip) << std::endl;
}
//**********************************************连接相机****************************************************
//选定相机
int k = -1;
for (int i = 0; i < camer_num; i++)
{
if (strcmp((discovery.ConvertIpIntToString(discovery_info[i].camera_ip)), "192.168.30.35") == 0)
{
k = i;
std::cout << "将连接第" << k + 1 << "台相机" << std::endl;
}
else
{
std::cout << "局域网内无该IP的相机" << std::endl;
}
}
//连接相机
int connect = camera.CameraConnect(&discovery_info[k]);
if (connect == 0)
{
std::cout << "成功连接相机" << std::endl;
}
else
{
std::cout << "连接相机失败,请检查!!!" << std::endl;
}
//**********************************************配置相机****************************************************
if (connect == 0)
{
//获取当前红外相机的宽和高
int width = -1;
int height = -1;
std::cout << "获取相机红外图的宽和高。。。" << std::endl;
int height_gray = camera.GetCameraHeight(&height, 0);
int width_gray = camera.GetCameraWidth(&width, 0);
std::cout << "camera Grey width:" << width << "---Grey height:" << height << std::endl;
//获取当前RGB相机的宽和高,如相机不支持则无此项
int width_RGB = -1;
int height_RGB = -1;
std::cout << "获取相机RGB图的宽和高。。。" << std::endl;
int height_rgb = camera.GetCameraHeight(&height_RGB, 1);
int width_rgb = camera.GetCameraWidth(&width_RGB, 1);
std::cout << "camera RGB width:" << width_RGB << "-----RGB height:" << height_RGB << std::endl;
//定义点云数据大小
PhotoInfo* point_data = new PhotoInfo;
point_data->pixel = new char[width * height * 6];
memset(point_data->pixel, 0, width * height * 6);
//定义红外数据大小
PhotoInfo* gray_data = new PhotoInfo;
gray_data->pixel = new char[width * height];
memset(gray_data->pixel, 0, width * height);
//定义RGB数据大小
PhotoInfo* RGB_data = new PhotoInfo;
RGB_data->pixel = new char[width_RGB * height_RGB * 3];
memset(RGB_data->pixel, 0, width_RGB * height_RGB * 3);
//设置相机曝光模式
int gray = 0; //红外和点云
int ExpSta = 1; //0为自动曝光,1为手动曝光
if (ExpSta == 0)//自动曝光的配置
{
int set_expusure = camera.SetAutoExposure(ExpSta, gray);
if (set_expusure == 0)
{
std::cout << "设置点云和红外图为自动曝光模式成功!" << std::endl;
}
else
{
std::cout << "设置点云和红外图为走动曝光模式失败!!!" << std::endl;
}
}
if (ExpSta == 1)//手动曝光的配置
{
int set_expusure = camera.SetAutoExposure(ExpSta, gray);
if (set_expusure == 0)
{
std::cout << "设置点云和红外图为手动曝光模式成功!" << std::endl;
}
else
{
std::cout << "设置点云和红外图为手动曝光模式失败!!!" << std::endl;
}
//配置曝光重数
int MltNum = 3;
if (MltNum == 1)//单重曝光
{
int set_mulitexposure = camera.SetMutipleExposure(MltNum);
if (set_mulitexposure == 0)
{
std::cout << "设置点云和红外图单重曝光成功!" << std::endl;
}
else
{
std::cout << "设置点云和红外图单重曝光失败!!!" << std::endl;
}
//配置曝光时间
int ExpuTime = 10000;
int ExpuTimStat = camera.SetExposureTime(ExpuTime,gray);
if (ExpuTimStat == 0)
{
std::cout << "设置点云和红外曝光时间成功!" << std::endl;
std::cout << "设置点云和红外曝光时间为:" << ExpuTime << "us" << std::endl;
}
else
{
std::cout << "设置点云和红外曝光时间失败!!!" << std::endl;
}
}
if (MltNum > 1)//多重曝光
{
int set_mulitexposure = camera.SetMutipleExposure(MltNum);
if (set_mulitexposure == 0)
{
std::cout << "设置点云和红外图多重曝光成功!" << std::endl;
std::cout << "点云和红外图曝光重数为:" << MltNum << std::endl;
}
else
{
std::cout << "设置点云和红外图多重曝光失败!!!" << std::endl;
}
//配置曝光时间渐变方法
int Arithmetic = 0; //等差
int Geometrics = 1; //等比
int ExpuMeth = Arithmetic; //配置为
int set_multiexpomode = camera.SetMultiExpoMode(ExpuMeth);
if (set_multiexpomode == 0)
{
std::cout << "设置曝光时间渐变方法成功!" << std::endl;
if (ExpuMeth == 0)
{
std::cout << "曝光时间渐变方法为:等差" << std::endl;
}
else
{
std::cout << "曝光时间渐变方法为:等比" << std::endl;
}
}
else
{
std::cout << "设置曝光时间渐变方法失败!!!" << std::endl;
}
//配置起始曝光时间
int MinExpu = 2000;//us
int set_multiexpomin = camera.SetMultiExpoMin(MinExpu);
if (set_multiexpomin == 0)
{
std::cout << "多重曝光起始曝光时间设置成功。" << std::endl;
std::cout << "多重曝光起始曝光时间为"<< MinExpu <<"us" << std::endl;
}
else
{
std::cout << "多重曝光起始曝光时间设置失败!!!" << std::endl;
}
//配置终止曝光时间
int MaxExpu = 20000;//us
int set_multiexpomax = camera.SetMultiExpoMax(MaxExpu);
if (set_multiexpomax == 0)
{
std::cout << "多重曝光终止曝光时间设置成功。" << std::endl;
std::cout << "多重曝光终止曝光时间为" << MaxExpu << "us" << std::endl;
}
else
{
std::cout << "多重曝光终止曝光时间设置失败!!!" << std::endl;
}
}
}
//**********************************************打开数据通道****************************************************
//开启数据流通道(0:红外 1:点云 2:RGB)
int stream_gray = camera.StreamOn(0, &graygigestream);
if (stream_gray == 0)
{
std::cout << "红外图通道打开成功!" << std::endl;
}
else
{
std::cout << "红外图通道打开失败!!!" << std::endl;
}
int stream_point = camera.StreamOn(1, &pointgigestream);
if (stream_point == 0)
{
std::cout << "点云通道打开成功!" << std::endl;
}
else
{
std::cout << "点云通道打开失败!!!" << std::endl;
}
int stream_RGB = camera.StreamOn(2, &rgbgigestream);
if (stream_RGB == 0)
{
std::cout << "RGB图通道打开成功!" << std::endl;
}
else
{
std::cout << "RGB图通道打开失败!!!" << std::endl;
}
//开始接受数据
int acquistion = camera.AcquisitionStart();
if (acquistion == 0)
{
std::cout << "可以开始接受数据!" << std::endl;
}
//刷新缓冲区数据
pointgigestream->FlushBuffer();
graygigestream->FlushBuffer();
rgbgigestream->FlushBuffer();
//**********************************************等待相机上传数据***************************************
//采集点云
int capturePoint = -1;
capturePoint = pointgigestream->TimeoutCapture(point_data, 3000000);
if (capturePoint == 0)
{
std::cout << "点云接收成功!" << std::endl;
}
else
{
std::cout << "点云接收失败!!!" << std::endl;
std::cout << "失败代号:" << capturePoint << std::endl;
}
//采集红外
int captureGray = -1;
captureGray = graygigestream->TimeoutCapture(gray_data, 3000000);
if (captureGray == 0)
{
std::cout << "红外接收成功!" << std::endl;
}
else
{
std::cout << "红外接收失败!!!" << std::endl;
std::cout << "失败代号:" << capturePoint << std::endl;
}
//采集RGB
int captureRGB = -1;
captureRGB = rgbgigestream->TimeoutCapture(RGB_data, 3000000);
if (captureRGB == 0)
{
std::cout << "RGB接收成功!" << std::endl;
}
else
{
std::cout << "RGB接收失败!!!" << std::endl;
std::cout << "失败代号:" << capturePoint << std::endl;
}
//**********************************************保存数据到本地***************************************
//保存点云(pcd)
int savepoint = camera.SavePointCloudToPcd(*point_data, (char*)"PointCloud.pcd");
if (savepoint == 0)
{
std::cout << "点云保存成功!" << std::endl;
}
else
{
std::cout << "点云保存失败!!!" << std::endl;
}
//保存红外数据
int savegray = camera.SaveToBMP(*gray_data, (char*)"Gray.bmp");
if (savegray == 0)
{
std::cout << "红外图保存成功!" << std::endl;
}
else
{
std::cout << "红外图保存失败!!!" << std::endl;
}
//保存RGB数据
int savergb = camera.SaveToBMP(*RGB_data, (char*)"RGB.bmp");
if (savergb == 0)
{
std::cout << "RGB图保存成功!" << std::endl;
}
else
{
std::cout << "RGB图保存失败!!!" << std::endl;
}
//保存深度图
int savedepth = camera.SaveDepthToPng(*point_data, (char*)"Depth.png");
if (savedepth == 0)
{
std::cout << "深度图保存成功!" << std::endl;
}
else
{
std::cout << "深度图保存失败!!!" << std::endl;
}
//**********************************************结束工作***************************************
memset(point_data->pixel, 0, width * height * 6);
memset(gray_data->pixel, 0, width * height);
memset(RGB_data->pixel, 0, width_RGB * height_RGB * 3);
//释放内存
delete[] point_data->pixel;
delete point_data;
delete[] gray_data->pixel;
delete gray_data;
delete[] RGB_data->pixel;
delete RGB_data;
//关闭数据流通道
int streamoff_gray = camera.StreamOff(0, graygigestream);
int streamoff_point = camera.StreamOff(1, pointgigestream);
int streamoff_rgb = camera.StreamOff(2, rgbgigestream);
//断开相机连接
int disconnect = camera.CameraDisconnect();
std::cout << "工作结束!!!!!!" << std::endl;
}
return (0);
}
运行结果
结果对比
各种曝光策略下的效果对比,当场景内有低反射物体时,自动曝光不能使低反射物体形成点云,当用手动曝光提高曝光使低反射物体有点云时,其余区域可能会产生过曝而没有点云,使用手动曝光多重曝光策略,则会起到很好的兼容效果。 RGB图片 自动曝光 手动曝光高曝光时间 多重曝光
后记
曝光模式和曝光时间配置好后,可通过相应查询曝光参数的API进行查询,以验证是否配置成功 设置曝光后采集点云时,注意超时时间,即TimeoutCapture要求设置的超时时间
TimeoutCapture要求设置超时时间的目的是防止点云未上传而造成阻塞,当计时达到该值时仍未接收到相机上传的点云,跳出等待点云上传,而执行后面的程序,同时会给出错误码,在未达到超时时间前收到点云则会立即跳出,执行后面的程序 超时时间必须大于相机输出点云的时间
T
(
u
s
)
T(us)
T ( u s )
T
=
∑
i
=
1
M
(
t
i
∗
N
+
T
c
)
+
T
r
T = \sum_{i = 1}^{M}(t_i*N+T_c)+T_r
T = i = 1 ∑ M ( t i ∗ N + T c ) + T r 其中:
M
M
M 为曝光重数
t
i
t_i
t i 为每重曝光的曝光值,单位为us,当该值小于10000us时,按照10000us计算
N
N
N 为结构光照片数量,该值与具体型号有关,可联系我进行确认
T
c
T_c
T c 为点云计算时间,该值与具体型号有关,可联系我进行确认
T
r
T_r
T r 为数据传输时间,千兆网的典型值是88000us 如以上例程中,设置3重曝光,根据上式计算
T
<
1
s
T<1s
T < 1 s ,设置超时时间为
3
s
3s
3 s 如有问题,欢迎与我深入交流:微信号:liu_zhisensor