【青瞳视觉C++接入文档】

1. 简介

在这里插入图片描述

青瞳视觉提供了一套用于连接和操作其动捕系统(CMAvatar 和 CMTracker)的C++ SDK,允许用户获取实时的刚体、骨骼及手指数据。本接入文档旨在指导开发者如何使用该SDK进行开发,包括环境设置、API调用方法、示例代码以及故障排除。
源码地址:https://github.com/ChingMuVisionTech/ChingMuCppSDKs

2. 开始前准备

在开始之前,请确保您的开发环境满足以下条件:

  • 操作系统:Windows 10 或更高版本。
  • 编译器:Visual Studio 2019 或以上版本。
  • 依赖库:确保已安装 CMVrpn.dll 及其相关依赖项,可以从官方GitHub仓库下载最新版本。
2.1 安装SDK

从GitHub仓库下载最新的C++ SDK,并解压到一个合适的位置。将 ChingmuDLL 文件夹路径添加到系统的环境变量 PATH 中,以便能够加载动态链接库 CMVrpn.dll

2.2 打开软件服务器

启动CMTracker Server软件服务器
在这里插入图片描述
然后运行CMTracker软件,窗口查看网络地址:192.168.0.9 接下来需要运行代码的电脑也同时接入到这个服务器的路由器,进行VRPN通讯
在这里插入图片描述
此时手动添加4个动捕小球组合成一个刚体Body_0
在这里插入图片描述
打开下面接口配置,参考下图配置
在这里插入图片描述

3. 初始化与配置
3.1 加载动态库

在项目中包含 CMVrpn.h 头文件,并确保 CMVrpn.dll 在运行时可以被找到。通常情况下,您只需要确保 ChingmuDLL 文件夹位于可执行文件所在的目录或系统路径中。

#include "CMVrpn.h"
3.2 启动VRPN线程

为了开始接收数据,必须启动VRPN线程:

CMVrpnStartExtern();
3.3 启用日志记录

启用日志记录可以帮助调试和监控程序运行状态:

CMVrpnEnableLog(true);
4. 数据获取

根据需求,您可以选择获取不同类型的数据,例如刚体位置和旋转、人物姿态信息等。

4.1 获取刚体数据

要获取特定ID的刚体预测位姿信息,可以使用 CMTrackerExtern 函数:

void GetRigidBodyData(const char* address, int bodyID, int frameCount) {
    double bodyPos[3], bodyRot[4];
    
    for (int i = 0; i < 3; ++i) {
        bodyPos[i] = CMTrackerExtern(address, bodyID, i, frameCount);
    }
    
    for (int i = 0; i < 4; ++i) {
        bodyRot[i] = CMTrackerExtern(address, bodyID, i + 3, frameCount);
    }
    
    bool isDetected = CMTrackerExternIsDetected(address, bodyID, frameCount);
    
    if (isDetected) {
        printf("Body pos: %lf %lf %lf\n", bodyPos[0], bodyPos[1], bodyPos[2]);
        printf("Body quaternion: %lf %lf %lf %lf\n", bodyRot[0], bodyRot[1], bodyRot[2], bodyRot[3]);
    } else {
        printf("Rigid body %d not detected\n", bodyID);
    }
}
4.2 注册回调函数

为了处理层级结构更新和重置事件,可以注册相应的回调函数:

void CallbackUpdateHierarchy(void*, VrpnHierarchy b) {
    // 处理层级结构更新
    printf("name:%s id:%d parent id:%d\n", b.name, b.sensor, b.parent);
}

void CallbackResetHierarchy(void*, timeval t) {
    // 处理层级结构重置
    printf("reset hierarchy\n");
}

// 注册回调函数
std::unique_ptr<VrpnHierarchy> userData(new VrpnHierarchy);
bool ret = CMPluginRegisterUpdateHierarchy(address, userData.get(), CallbackUpdateHierarchy);
ret = CMPluginRegisterResetHierarchy(address, userData.get(), CallbackResetHierarchy);
5. 完整代码

为了持续获取数据,通常会在一个循环中调用上述函数,并控制采集频率。下面是一个完整的例子:

#include "CMVrpn.h"
#include <stdio.h>
#include <windows.h>
#include <memory>
#include <signal.h>

volatile sig_atomic_t stop;

void signalHandler(int signum) {
    stop = 1;
}

void CallbackUpdateHierarchy(void*, VrpnHierarchy b) {
    // hierarchy info
    printf("name:%s id:%d parent id:%d\n", b.name, b.sensor, b.parent);
}

void CallbackResetHierarchy(void*, timeval t) {
    // reset hierarchy
    printf("reset hierarchy\n");
}

int main() {
    signal(SIGINT, signalHandler); // 捕获 Ctrl+C 信号

    char *address = "MCServer@192.168.0.9";
    // start vrpn thread
    CMVrpnStartExtern();

    // enable write trace_log.txt
    CMVrpnEnableLog(true);

    std::unique_ptr<VrpnHierarchy> userData(new VrpnHierarchy);
    // register human model hierarchy
    bool ret = CMPluginRegisterUpdateHierarchy(address, userData.get(), CallbackUpdateHierarchy);

    // register human model reset hierarchy
    ret = CMPluginRegisterResetHierarchy(address, userData.get(), CallbackResetHierarchy);

    int frameCount = 0;

    while (!stop) {
        auto timecode = std::make_unique<VrpnTimeCode>();
        bool isHumanDetected, isBodyDetected;
        int segmentIsDetected[MAX_SEGMENT_NUM];
// Person ID displayed on the server
        int bodyID = 0;
        double bodyPos[3], bodyRot[4];

        // get body component 0:x, 1:y, 2:z, 3:rx, 4:ry, 5:rz, 6:rw with time predict
        bodyPos[0] = CMTrackerExtern(address, bodyID, 0, frameCount);
        bodyPos[1] = CMTrackerExtern(address, bodyID, 1, frameCount);
        bodyPos[2] = CMTrackerExtern(address, bodyID, 2, frameCount);

        bodyRot[0] = CMTrackerExtern(address, bodyID, 3, frameCount);
        bodyRot[1] = CMTrackerExtern(address, bodyID, 4, frameCount);
        bodyRot[2] = CMTrackerExtern(address, bodyID, 5, frameCount);
        bodyRot[3] = CMTrackerExtern(address, bodyID, 6, frameCount);

        // check body detected
        isBodyDetected = CMTrackerExternIsDetected(address, bodyID, frameCount);
        if (isBodyDetected) {
            printf("Body pos:%lf %lf %lf\n", bodyPos[0], bodyPos[1], bodyPos[2]);
            printf("Body quaternion:%lf %lf %lf %lf\n", bodyRot[0], bodyRot[1], bodyRot[2], bodyRot[3]);
        }

        // 其他相关代码略...

        frameCount++;
        Sleep(8);
    }

    // quit vrpn thread
    CMVrpnQuitExtern();
    return 0;
}

  1. 需要修改两处代码,首先是查看服务器地址,你采用CMAvatar CMTracker分别一一对应,我是 CMTracker采用MCServer@192.168.0.9
//set CMTracker server address
    char *address = "MCServer@192.168.0.9";
//set CMAvatar server address
	char *address = "MCAvatar@192.168.0.9";

根据按照动捕服务器可分为两种类型。

  1. 动捕服务器为 CMAvatar 时,vrpn 的地址为 MCAvatar@动捕服务器地址,默认的端口采用3883。其中,刚体数据的范围为 0~300,和动捕服务器中的刚体 id 一一对应。骨骼数据从 300开始,间隔为 150,即第一个人的第一个关节为 300,第二个人的第一个关节为 450,依次类推。重定向骨骼数据和非重定向的骨骼数据的定义一致,根据重定向发送的层级信息来确定骨骼 id与模型关节的对应关系。

  2. 动捕服务器为 CMTracker 时,tracker server 和 tracker client 均有 vrpn server 存在。MCServer@动捕服务器地址为 tracker server,而 MCServer@动捕服务器地址:3884 为 tracker client。其中,刚体数据的范围为 0-100,和动捕服务器中的刚体 id 一一对应。刚体上的 Marker 点的 id 范围为1300-6300,每个刚体预留 50 位,即第二个刚体的第一个 marker 的 id 从 1350 开始。骨骼的数据为 100 开始,3883 端口下,间隔为 23,3884 端口下,间隔为 150。骨骼上的 marker 点序号从6300 开始,每个人预留 100 位。未标记 marker 点的 id 序号是从 11300 开始。3883 端口仅支持发送非重定向数据。3884 端口可以通过界面勾选来发送非重定向数据或者非重定向数据。

  3. bodyID = 0对应刚体编号Body_0

在这里插入图片描述

// Person ID displayed on the server
    int bodyID = 0;

显示输出效果
在这里插入图片描述

Body pos:-1562.754311 -618.426219 39.156954
Body quaternion:-0.003409 0.016292 0.999808 0.010322
Body pos:-1562.223550 -618.217084 39.144874
Body quaternion:-0.003398 0.016289 0.999803 0.010853
Body pos:-1561.867860 -618.076987 39.136774
Body quaternion:-0.003388 0.016290 0.999799 0.011208
Body pos:-1562.230338 -618.219820 39.144930
Body quaternion:-0.003393 0.016293 0.999803 0.010846
Body pos:-1561.944678 -618.107239 39.138659
Body quaternion:-0.003387 0.016295 0.999800 0.011132
Body pos:-1561.680335 -618.003060 39.132796
Body quaternion:-0.003382 0.016295 0.999797 0.011396
Body pos:-1562.002715 -618.130056 39.140132
Body quaternion:-0.003387 0.016297 0.999800 0.011074
Body pos:-1561.635982 -617.985476 39.131813
Body quaternion:-0.003377 0.016296 0.999796 0.011440
Body pos:-1561.322893 -617.862171 39.124797
Body quaternion:-0.003360 0.016295 0.999792 0.011754
Body pos:-1561.344569 -617.870736 39.125332
Body quaternion:-0.003348 0.016295 0.999793 0.011733
Body pos:-1561.727363 -618.021565 39.134002
Body quaternion:-0.003349 0.016297 0.999797 0.011351
Body pos:-1562.268602 -618.234813 39.146238
Body quaternion:-0.003356 0.016300 0.999803 0.010811
Body pos:-1561.734440 -618.024409 39.134380
Body quaternion:-0.003334 0.016296 0.999797 0.011344
6. 常见问题解答
  • Q: 我遇到了 std::out_of_range 异常,如何解决?

    • A: 这个异常通常是由于尝试访问超出容器边界的位置引起的。请检查您的代码中对容器的访问是否正确,并确保在访问前进行了适当的边界检查。
  • Q: 如何确保我使用的 CMVrpn.dll 是最新版本?

    • A: 请定期检查 GitHub 仓库中的更新,并确保本地使用的 CMVrpn.dll 与 C++ SDK 的版本匹配。如果有新的版本发布,建议及时更新。
  • Q: 在多线程环境中使用SDK时需要注意什么?

    • A: 当在多线程环境中使用SDK时,确保每个线程独立地管理其资源,避免多个线程同时操作同一个对象或资源。此外,注意线程安全性和同步问题,以防止竞态条件。
7. 结论

通过本接入文档,您应该能够顺利地将青瞳视觉的C++ SDK集成到您的项目中,并开始获取和处理动捕数据。如果您遇到任何问题或有进一步的需求,请参考官方文档或联系技术支持团队获取帮助。

附录A: API参考

为了方便开发者查阅,以下是部分常用API的简要说明:

  • CMVrpnStartExtern(): 启动VRPN线程,开始接收数据。
  • CMVrpnEnableLog(bool enable): 启用或禁用日志记录。
  • CMTrackerExtern(const char* host, int bodyID, int component, int frameCount) -> double: 获取刚体的某个分量值(如位置或旋转)。
  • CMTrackerExternIsDetected(const char* host, int bodyID, int frameCount) -> bool: 检查刚体是否被检测到。
  • CMPluginRegisterUpdateHierarchy(const char* address, void* userData, void (*callback)(void*, VrpnHierarchy)) -> bool: 注册层级结构更新回调。
  • CMPluginRegisterResetHierarchy(const char* address, void* userData, void (*callback)(void*, timeval)) -> bool: 注册层级结构重置回调。
  • CMVrpnQuitExtern(): 退出VRPN线程,停止接收数据。

请注意,这些API的具体参数和返回值可能根据实际版本有所不同,建议结合官方文档进行开发。

从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣

  1. 我会持续更新对应专栏博客,非常期待你的三连!!!🎉🎉🎉
  2. 如果鹏鹏有哪里说的不妥,还请大佬多多评论指教!!!👍👍👍
  3. 下面有我的🐧🐧🐧群推广,欢迎志同道合的朋友们加入,期待与你的思维碰撞😘😘😘
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2345VOR

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值