从0到1搭建一套属于你自己的高精度实时结构光3D相机(5):结构光3D相机SDK开发(C/C++)

1. 写在前面

在前面的博客中,介绍了如何通过 C/C++ 控制我们的2D相机和投影仪。在这篇博客中,博主将教给大家如何通过 C/C++ 开发我们的结构光3D相机SDK。完成本篇博客的学习内容后,你将收获如何编写自己的结构光3D相机的SDK开发经验。

本系列博客的完整项目代码皆位于博主的Github项目SLMaster👈

https://github.com/Practice3DVision/SLMaster

动动你的小指头给个Star⭐并follow博主吧!你的支持是博主不懈的动力!

2. 通过Json控制的结构光相机SDK开发

经过前两篇博客的内容,大家肯定都对简单工厂模式比较熟悉了。在结构光相机里,我们也使用这种模式,所以我们的UML图长成这样:

在这里插入图片描述

这样的话,我们就能在单目、双目、多目结构光3D相机中无缝切换了!

由于代码部分占篇幅比较长,所以博主就不再放代码了,而是讲解必要的代码片段,相信这种方式能让博客更简洁!同学们可以在我的Github上下载完整代码,别忘了给个⭐喔。

随之而来的问题是,我们如何去控制我们的结构光3D相机参数呢?我们知道算法可能具有很多的参数,如果在算法运行时逐一修改参数并试运行,那工作量有点大而且繁琐(你可不想每次调参都编译链接再运行一遍吧)。

我们可以通过外部文件来控制我们的相机。博主在这里使用的是Json文件,如果你有兴趣也可以使用.ini配置文件等等。

Json文件的后缀为 .json ,它其实也是一种文本文件。我们使用它来记录有关于我们结构光3D相机的所有参数,包括3D相机名称、开发者、3D相机性能参数、内部2D相机硬件配置、内部投影仪配置、算法控制参数等等。

如此一来,作为开发者,我们最了解我们开发的这款相机的参数配置,所以可以写出完整的Json配置文件用于描述我们的结构光3D相机;而作为使用者,我们可能对如何通过SDK调参不感兴趣,那我们就可以通过拿到Json配置文件获得这款结构光3D相机的所有信息,并仅需在该文件中修改相应参数即可完整整个结构光3D相机的参数更新,而不需要重新编译可执行文件等复杂操作。

博主在这里给出我们的三目结构光相机Json文件的部分代码:

{
   "camera" : {
      "algorithm" : [
       	{
            "data" : 1,
            "title" : "Gpu Accelerate",
            "type" : "bool"
         },
         {
            "data" : 3.0,
            "title" : "Phase Shift Times",
            "type" : "number"
         },
         {
            "data" : 3000.0,
            "title" : "Exposure Time",
            "type" : "number"
         },
         ...
       ],
      "device" : [
         {
            "data" : "Trinocular Camera",
            "title" : "Camera Name",
            "type" : "string"
         },
         ...
       ]
   }
}

是不是很明了,一眼就能知道该款结构光3D相机的类型和可供修改的算法参数等。

那如何实现这种需求呢?首先,我们通过jsoncpp库来实现 C++ 下的 json文件读取与写入。然后在我们的结构光相机类(如上述的TrinocularCamera)初始化时,就读入该配置,在类析构时将所有的参数重新写入json文件中(为什么不每次一更新就写入呢?磁盘写入操作耗时啊!)。

博主给出一些源代码看看:

TrinocularCamera::TrinocularCamera(IN const std::string jsonPath)
    : SLCamera(jsonPath), jsonPath_(jsonPath), isInitial_(false), isCaptureStop_(true) {
    if (loadParams(jsonPath, jsonVal_)) {
        if (booleanProperties_["Gpu Accelerate"]) {
#ifndef WITH_CUDASTRUCTUREDLIGHT_MODULE
            std::clog << "lib isn't build with cuda, we will disable it!" << std::endl;
            booleanProperties_["Gpu Accelerate"] = false;
#endif //!WITH_CUDASTRUCTUREDLIGHT_MODULE
        }

        isInitial_ = true;
    }
}
TrinocularCamera::~TrinocularCamera() {
    updateCamera();
}

逻辑还是很简单的吧!

接下来是我们的结构光3D相机类的具体实现了!我们知道结构光3D相机最主要的功能和2D相机类似,只不过数据结构变了,所以我们可以归纳为这么几个主要功能:

  • 相机在线状态查询
  • 相机连接与断开
  • 捕获(执行三维重建)
  • 相关的属性读取写入以及接口等

1)相机在线查询

我们在TrinocularCamera类中使用组合模式加入我们前两篇博客中所写的相机工厂类CameraFactory与投影仪工厂类ProjectorFactory。然后通过读取Json文件中的硬件描述,获得对应的2D相机指针和投影仪指针,并查询它们是否在线,如果在线,我们就返回结构光相机在线true(为了使用方便,我们还将深度2D相机的内参进行返回),否则,返回不在线false。源代码如下:

SLCameraInfo TrinocularCamera::getCameraInfo() {
    const device::camera::CameraFactory::CameraManufactor manufator =
        stringProperties_["2D Camera Manufactor"] == "Huaray"
            ? device::camera::CameraFactory::Huaray
            : device::camera::CameraFactory::Halcon;
    auto pLeftCamera = cameraFactory_.getCamera(
        stringProperties_["Left Camera Name"], manufator);
    auto pRightCamera = cameraFactory_.getCamera(
        stringProperties_["Right Camera Name"], manufator);
    auto pColorCamera = cameraFactory_.getCamera(
        stringProperties_["Color Camera Name"], manufator);
    auto leftCameraInfo = pLeftCamera->getCameraInfo();
    auto rightCameraInfo = pRightCamera->getCameraInfo();
    auto colorCameraInfo = pColorCamera->getCameraInfo();

    auto pProjector =
        projectorFactory_.getProjector(stringProperties_["DLP Evm"]);

    device::projector::ProjectorInfo projectorInfo = pProjector ? pProjector->getInfo() : device::projector::ProjectorInfo();
    if(!pProjector) {
        projectorInfo.isFind_ = false;
    }

    SLCameraInfo slCameraInfo;
    slCameraInfo.isFind_ = leftCameraInfo.isFind_ &&
                           rightCameraInfo.isFind_ && colorCameraInfo.isFind_ && projectorInfo.isFind_;
    slCameraInfo.cameraName_ =
        slCameraInfo.isFind_ ? stringProperties_["Camera Name"] : "NOT_FOUND";
    slCameraInfo.intrinsic_ = slCameraInfo.isFind_
                                  ? caliInfo_->info_.M1_
                                  : cv::Mat::zeros(3, 3, CV_32FC1);

    return slCameraInfo;
}

2)相机连接与断开

与上述类似,我们通过调用底层2D相机与投影仪接口实现结构光3D相机的连接与断开。断开连接的源码如下:

bool TrinocularCamera::disConnect() {
    const device::camera::CameraFactory::CameraManufactor manufator =
        stringProperties_["2D Camera Manufactor"] == "Huaray"
            ? device::camera::CameraFactory::Huaray
            : device::camera::CameraFactory::Halcon;
    const bool disConnectLeftCamera =
        cameraFactory_
            .getCamera(stringProperties_["Left Camera Name"], manufator)
            ->disConnect();
    const bool disConnectRightCamera =
        cameraFactory_
            .getCamera(stringProperties_["Right Camera Name"], manufator)
            ->disConnect();
    const bool disConnectColorCamera =
        cameraFactory_
            .getCamera(stringProperties_["Color Camera Name"], manufator)
            ->disConnect();
    const bool disConnectProjector =
        projectorFactory_.getProjector(stringProperties_["DLP Evm"])
            ->disConnect();
    return disConnectLeftCamera && disConnectRightCamera && disConnectColorCamera && disConnectProjector;
}

3)捕获(执行三维重建)

这一点就比较有意思了,我们知道我们的结构光3D相机是可以使用很多种算法的,比如,你可能在面对高反物体时,使用多次曝光算法进行三维重建;而在面对工况良好的场景下,使用相移互补格雷码解码算法,等等。所以,博主并不写死算法,而是创建一个纯虚基类Pattern作为算法基类,所有算法继承并实现其接口。然后在结构光3D相机类SLCamera中使用设计模式中的组合模式,组合一个Pattern*成员,并提供可供修改当前算法的公开接口(其实就是把具体选择什么算法延迟了)。部分源码如下:

    /**
     * @brief 设置条纹编解码方法
     * @param pattern_ 条纹编解码方法
     * @return
     */
    void setPattern(Pattern* pattern) { pattern_ = pattern; }

当我们进行三维重建时,我们仅需调用pattern_decode()接口即可。源码参考如下:

pattern_->decode(imgs, depthMap, booleanProperties_["Gpu Accelerate"]);

是不是很简洁明了呢?

3. 效果

我们来看看在软件中,这部分代码的具体效果体现在哪里。

编号图片
1在这里插入图片描述
2在这里插入图片描述
3在这里插入图片描述

4. 总结

在这篇博客中,博主介绍了如何使用 C/C++ 开发结构光3D相机的 SDK ,在下一小节中,博主将开始介绍算法与代码实现。

本系列文章将持续更新,如果有等不及想要获得代码的小伙伴,可访问博主Github中的SLMaster项目,动动你的小手指,follow and star⭐!你们的关注是博主持续的动力!

Github:https://github.com/Practice3DVision
QQ群:229441078

公众号:实战3D视觉

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值