1、发现设备
std::string uri = cx::discoverAndChooseDevice()->deviceURI;
std::cout << "Open Device:" << uri.c_str() << endl;
连接相机
auto cam = cx::DeviceFactory::openDevice(uri);
可视化框架
cx::viz::Viz3d viz("Point Cloud");
cx::Variant val;
cam->getParam("DeviceScanType")
if(std::string(val)!="Linescan3D")
{
cerr << "Current sensor devicemode is not 'Linescan3D',we activate it.." << endl;
cam->setParam("DeviceScanType","Linescan")
if (std::string(val) != "Linescan3D")
{
cerr << "Current sensor devicemode is not 'Linescan3D',we activate it..."
<< endl;
//向某个输出器输出
cam->setParam("DeviceScanType","Linescan3D");
//setParam是cam这个结构体中的成员变量,这是对这个变量进行赋值
/*void setParam(const std::string& prm,const cx::Variant& val)
{
cx::checkOk("cx_setParam",cx_setParam(m_hDevice,prm.c_str(),val));
}
*/
}
}
typedef cv::viz::Color Color;
2、从相机或文件加载3D校准
cx::c3d::Calib calib;
从给定文件加载校准
if (argc > 1)
{
calib.load(argv[1]);
}
从传感器加载校准,可能的来源是“用户数据”、“校准”、“校准用户”
else
{
cx::downloadCalib(cam->getHandle(),calib);
}
3、在校准中设置相关采集参数,我们假设只有一个aoi激活
cx::updateCalib(cam->getHandle(),calib,1);
设置轮廓步长缩放
calib.get(CX_3D_PARAM_SY,val);
std::out << "enter profile distance,current value=" << (double)val << ",new value:";
std::string userInput;
cin >> userInput;
if (!=userInput.empty())
{
double dy = std::stod(userInput);
calib.set(CX_3D_PARAM_SY,dy);
//CX_3D_PARAM_SY:从一个外形到下一个外形的距离乘以给定的y坐标
}
打印用于计算点云的更新校准
cx::printInfo(calib.getHandle());
为所有为0的范围图值设置将在点云中使用的无效值
可以是任何数字,例如-10.0f,如果使用NAN,则在showPointCloud中自动抑制点
float ivd = NAN;
calib.set(CX_3D_PARAM_METRIC_IDV,ivd)
//CX_3D_PARAM_METRIC_IDV:用于标记无效数据点的数据值无效,只有Z坐标用此值标记。如果pixel_格式为整数,则必须舍入为整数。
触发缓存更新,当使用参数>0调用时,内部缓存将更新。
这将防止在第一次调用度量函数cx_3d_range2calibratedABC
calib.set(CX_3D_PARAM_METRIC_CACHE_MODE,int(1));
/*
set的函数定义
void set(cx_3d_calib_param_t,param, const cx::Variant& val)
{
cx::checkOk("cx_3d_calib_set",cx_3d_calib_set(m_hCalib, param, &val));
}
checkOk的函数定义
@overload
@param func name of function that returned the status s.
@param s status,see \ref CX_STATUS_ENUM for possible values.
inline cx_status_t checkOk(const char* func, cx_status_t s)
{
if (s != CX_STATUS_OK)
{
throw(RuntimeError)
}
}
*/
int(1):强制转换成整数,int型
4、分配和排队内部采集缓冲区
allocate and queue internal acquisition buffers
cam->allocAndQueueBuffers();
/*
void allocAndQueueBuffers(int numBuffers=3)
{
cx::checkOk("cx_allocAndQueueBuffers",cx_allocAndQueueBuffers(m_hDevice,numBuffers));
}
*/
5、启动图像采集
cam->startAcquisition();
6、抓取采集缓冲区,等待具有可选超时的有效缓冲区,超时以毫秒为单位。
grab acquisition buffer,wait for valid buffer with optional timeout.Timeout is given in ms.
cx::DeviceBuffer buffer = cam->waitForBuffer(10000);
7、从缓冲区获取图像数据并对图像数据进行一些处理(或获取一个副本供以后使用)
注意img保存了对DeviceBuffer中的图像数据的引用,如果您需要cx_queueBuffer之后的图像数据,则需要克隆映像!
auto rangeImg = buffer.getImage();
可选地将范围图像保存到文件
if (argc > 2)
rangeImg->save(argv[2]);
cout << "rangeImg height" << rangeImg->height() << endl; //100
cout << "rangeImg width" << rangeImg->width() << endl;//1280
8、计算点云
cx::c3d::PointCloud pc(rangeImg->height(),rangeImg->width());
cx::c3d::calculatePointCloud(calib,*rangeImg,pc);
获取 xyz 坐标
clock_t start_time = clock();
vector<cx::Point3f> tpour; //图像坐标轮廓
vector<cv::Point2i>CenterlaserPoint; //扫描点轮廓
cv::Point2i point;
for(unsigned x = 0; x < pc.points.width();x++)
//cx::Image points 仅在计算或从文件加载后有效。注:为了使用vtk(WCloud)可视化,必须使用//CX_PF_COORD3D_ABC32f(CV_32FC3)类型。
{
cx::Point3f dx = pc.points.at<cx::Point3f>(4,x); //(x,y,z相机坐标系下坐标)
if(dx.z < 200 && dx.z > -200) //去除无效点
point.x = x;
point.y = (int)(10 * (dx.z)); //扩大z值,便于图像显示
tpour.push_back(dx); //相机坐标系坐标
CenterlaserPoint.push_back(point); //深度坐标,求特征点
//在末端插入元件,提供强有力的保证
/*
void push_back(const _Ty& _val)
{
emplace_back(_val);
}
//push_back是vector的一个方法,表示将一个元素存储到容器的末尾。
*/
}
cv::Mat midimage(1024, 1280,CV_8UC1, cv::Scalar::all(0));
//CV_8UC1 8表示8位,UC表示unsigned char,1表示1个通道, Scalar表示向量长度,要与通道数目一致
int size_num = CenterlaserPoint.size(); //扫描点轮廓的尺寸?
if (size_num < 1)
{
return 0;
}
for (int i = 0;i < size_num; i++)
{
midimage.at<uchar>(CenterlaserPoint[i].y + 512,CenterlaserPoint[i].x) = 255;
}
//求左边轮廓点位置
int Laserleft = 0;
for (int i = 20;i < size_num - 20; i++)
{
if ((abs(CenterlaserPoint[i].y - CenterlaserPoint[i + 1].y) > 3) &&
(abs(CenterlaserPoint[i].y - CenterlaserPoint[i + 2].y) > 5) &&
(abs(CenterlaserPoint[i].y - CenterlaserPoint[i + 3].y) > 10))
{
Laserleft = i-2;
break;
}
}
if (Laserleft == 0)
{
cout << "find point error" << endl;
return 0;
}
cv::Point2f Leftpoint;
Leftpoint.x = CenterlaserPoint[Laserleft].x;
Leftpoint.y = CenterlaserPoint[Laserleft].y + 512;
cv::circle(midimage,Leftpoint,8,cv::Scalar(180,0,0),-1);
//求右边特征点位置
int Laserright = 0;
for (int i = 20;i < size_num - 20; i--)
{
if ((abs(CenterlaserPoint[i].y - CenterlaserPoint[i + 1].y) > 3) &&
(abs(CenterlaserPoint[i].y - CenterlaserPoint[i + 2].y) > 5) &&
(abs(CenterlaserPoint[i].y - CenterlaserPoint[i + 3].y) > 10))
{
Laserleft = i+2;
break;
}
}
if (Laserleft == 0)
{
cout << "find point error" << endl;
return 0;
}
cv::Point2f Rightpoint;
Rightpoint.x = CenterlaserPoint[Laserright].x;
Rightpoint.y = CenterlaserPoint[Laserright].y + 512;
cv::circle(midimage,Leftpoint,8,cv::Scalar(180,0,0),-1);
//求底部特征点位置
int Laserbottom = 0;
int point_bottom = CenterlaserPoint[Laserleft].y;
for (int i = Laserleft + 1;i < Laserright; i++)
{
int point_bottom_new = CenterlaserPoint[i].y;
if (point_bottom_new < point_bottom)
{
point_bottom = point_bottom_new;
Laserbottom = i;
}
}