前几天刚完成的线激光三角相机开发,简单实现了简单的线扫功能。
使用鲍威尔激光头(号称是可以产生极细激光线,结果感觉效果和40左右的激光没啥区别,凑合用吧),海康30万像素相机(取像满帧率200),镜头25mm,标定使用halcon标定,计算用c++,标定完成后不依赖halcon可直接运行。 生成单条纹点云图如下: 以下将通过取像,标定,查找激光线,计算单点四步进行讲解:
取像 刚开用了延时取像,结果抓取图像速度太慢(12ms一张图),使用回调函数取像正常帧率。但是这里就有了一个疑问,如果将回调函数封装成dll,当想要修改回调函数中数据处理过程时岂不是都要改源码?有没有很好一种方式,能有利于开发者直接修改回调函数中的程序,编程小白请求答疑。 标定 halcon标定: 1、标定相机内外参数 2、标定光平面 查找激光线 在找激光线的过程中仅使用了阈值分割,遍历每个像素值,找到图像每列上的像素点,未使用滤波、剔除异常点、膨胀等图形处理操作。 计算单点 通过内参校正当前像素点的畸变,通过外参找到此点在空间中的位置,通过投影得到世界坐标系中的位置,根据世界坐标系与光平面关系求得在光平面坐标系中的位置,输出结果,得到输出的点云图。
留了个坑,来填一下,经过研究发现,海康sdk自带回调函数,但是不能讲这个函数封装到类中,因此我想了其他方法,就是自己定义一个函数指针在相机类中,类外通过回调函数调用这个指针即可,贴一段代码。
//类外 typedef void (*ProcessCallback)(unsigned char*); //定义函数指针类型 ProcessCallback pProcessCallback = NULL; //初始化一个指针,做为桥梁接连回调函数和类中的回调函数 //海康相机提供的原始回调函数 void __stdcall ImageCallBackEx(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser) { if (pFrameInfo) { pProcessCallback(pData); } } //类内部, //首先定义外接接口和标志 bool bCallBack; // 是否注册回调函数,默认false ProcessCallback pUserProcessCallback = NULL; // 类中函数指针实例,供外部调用。回调需赋值,记得初始化 //由于海康sdk在开始取流前需要配置回调, //因此MV_CC_StartGrabbing(hDeviceHandle)这段代码要放在如下代码后, //否则无法生效。 if (bCallBack) { if (NULL == pUserProcessCallback) { printf("没有回调,记得关闭相机 \r\n"); } pProcessCallback = pUserProcessCallback; // ch:注册抓图回调 | en:Register image callback nRet = MV_CC_RegisterImageCallBackEx(hDeviceHandle, ImageCallBackEx, hDeviceHandle); }不过因为更新了数据结构,新增图像矩阵类,并实现泛型,因此也加上了膨胀操作,虽然改了上面的取像方式但是还是一如既往的慢。。