Azure Kinect:如何关联Windows设备ID与设备序列号?
解决Azure Kinect设备ID与序列号的匹配问题
我之前处理过多台Azure Kinect的多设备识别场景,刚好碰到过和你一样的问题,给你两个实用的解决方案:
方案一:在C++程序中同时输出序列号和Windows设备ID
既然你的C程序负责和Kinect硬件交互,可以直接在C里把每个设备的序列号和对应的Windows设备ID关联起来,一起输出到文件中,这样C#程序就能直接一一对应了。
要在C++中获取Kinect对应的Windows设备ID,可以借助Windows的SetupAPI函数来遍历USB设备:
- 首先用
k4a_device_get_installed_count()获取已连接的Kinect数量 - 遍历每个设备,用
k4a_device_open()打开,再用k4a_device_get_serialnum()获取序列号 - 同时调用SetupAPI相关函数(
SetupDiGetClassDevs、SetupDiEnumDeviceInterfaces、SetupDiGetDeviceInterfaceDetail),筛选出VID为045E、PID为097C的USB设备,提取其设备实例ID(就是你在C#里拿到的那种格式) - 把每个设备的序列号和设备ID配对后写入输出文件
这里给你一段简化的代码片段参考:
#include <k4a/k4a.h> #include <windows.h> #include <setupapi.h> #include <initguid.h> #include <usbiodef.h> // 遍历USB设备,匹配Kinect的VID/PID,获取设备ID std::string get_kinect_device_id(const std::string& serial_num) { HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo == INVALID_HANDLE_VALUE) { return ""; } SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0}; deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, i, &deviceInterfaceData); i++) { // 获取设备详情 DWORD requiredSize = 0; SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, NULL, 0, &requiredSize, NULL); std::vector<BYTE> detailData(requiredSize); PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(detailData.data()); pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); SP_DEVINFO_DATA devInfoData = {0}; devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, pDetailData, requiredSize, NULL, &devInfoData)) { // 获取硬件ID char hardwareId[256]; if (SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_HARDWAREID, NULL, reinterpret_cast<PBYTE>(hardwareId), sizeof(hardwareId), NULL)) { // 检查是否包含Kinect的VID/PID,以及序列号 std::string hwId(hardwareId); if (hwId.find("VID_045E&PID_097C") != std::string::npos && hwId.find(serial_num) != std::string::npos) { // 返回设备实例ID char deviceId[256]; if (SetupDiGetDeviceInstanceId(hDevInfo, &devInfoData, deviceId, sizeof(deviceId), NULL)) { SetupDiDestroyDeviceInfoList(hDevInfo); return std::string(deviceId); } } } } } SetupDiDestroyDeviceInfoList(hDevInfo); return ""; } // 主逻辑中配对序列号和设备ID int main() { int deviceCount = k4a_device_get_installed_count(); for (int i = 0; i < deviceCount; i++) { k4a_device_t device = NULL; if (k4a_device_open(i, &device) == K4A_RESULT_SUCCEEDED) { char serial[K4A_SERIAL_NUMBER_SIZE]; k4a_device_get_serialnum(device, serial, sizeof(serial)); std::string deviceId = get_kinect_device_id(serial); // 将serial和deviceId写入输出文件 printf("Serial: %s, Device ID: %s\n", serial, deviceId.c_str()); k4a_device_close(device); } } return 0; }
方案二:在C#中直接从设备ID提取序列号
这个方案更简单,不需要修改你的C++代码——仔细看你拿到的Windows设备ID:\\.\\USB#VID_045E&PID_097C#001007692912#{A5DCBF10-6530-11D2-901F-00C04FB951ED}
其中#VID_045E&PID_097C#后面、下一个#前面的001007692912就是Kinect的序列号!
所以你只需要在C#里写个字符串处理逻辑,提取这部分内容即可。比如用正则表达式或者字符串分割:
用正则表达式提取的C#代码示例:
using System.Text.RegularExpressions; public string ExtractKinectSerialFromDeviceId(string deviceId) { // 匹配VID/PID之后的序列号部分 var match = Regex.Match(deviceId, @"VID_045E&PID_097C#([^#]+)#"); if (match.Success) { return match.Groups[1].Value; } return string.Empty; }
用字符串分割的C#代码示例:
public string ExtractKinectSerialFromDeviceId(string deviceId) { var parts = deviceId.Split('#'); // 设备ID格式固定的话,parts[2]就是序列号 if (parts.Length >= 3) { return parts[2]; } return string.Empty; }
提取出序列号后,直接和C++程序输出的序列号做匹配,就能对应上每台设备了。
我个人更推荐方案二,不需要改动现有C代码,几分钟就能搞定匹配逻辑。如果方案二因为设备ID格式特殊不生效,再考虑方案一的C代码改造。
内容的提问来源于stack exchange,提问作者guidout
相关产品推荐
相关产品推荐

