海康RGBD相机使用C++和Opencv采集图像记录
RGBD相机型号:MV-EB435i
配置:1.Vs2019 2.Opencv4.6
一、安装客户端
1.下载链接
2.官方Samples
安装后,在帮助-development中,可以看到一些samples,但是这些样例都是使用较老的版本编辑的。比如Opencv是使用opencv2.4编辑的,里面有些函数太老了,需要替换。
二、修改代码
打开Samples中的opencv调用样例
将样例拷贝出来,到别的本地文件夹再继续进行修改,其中只需要修改main.cpp文件
main.cpp是在官方版本上进行的修改,主要是替换了一些函数
cpp
#include "common/common.hpp" // 包含项目中通用的头文件,定义了一些常用的宏和函数。
#include <opencv2/opencv.hpp> // 包含OpenCV库的主要头文件,提供图像处理功能。
#include <vector> // 包含C++标准库中的vector容器,用于管理动态数组。
#include <string> // 包含C++标准库中的string类,用于字符串操作。
// 假设MV3D_RGBD_*函数在其他地方定义。这些应该被来自MV3D_RGBD库的实际函数调用所替换。
#define MAX_IMAGE_COUNT 10 // 定义一个宏,表示最多保存的图像数量为10张。
bool ConvertRGB8Planner2BGR8Packed(const unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData) {
if (!pSrcData || !pDstData) return false; // 如果源数据或目标数据为空,则返回错误。
int nImageStep = nWidth * nHeight; // 计算单通道图像的像素总数。
for (int i = 0; i < nImageStep; ++i) { // 遍历每个像素。
pDstData[i * 3 + 0] = pSrcData[i + nImageStep * 2]; // 将红色通道的数据放到目标缓冲区的蓝色位置。
pDstData[i * 3 + 1] = pSrcData[i + nImageStep * 1]; // 将绿色通道的数据放到目标缓冲区的绿色位置。
pDstData[i * 3 + 2] = pSrcData[i + nImageStep * 0]; // 将蓝色通道的数据放到目标缓冲区的红色位置。
}
return true; // 成功转换后返回true。
}
int main(int argc, char** argv) {
LOGD("Initialize"); // 日志记录:初始化程序开始。
ASSERT_OK(MV3D_RGBD_Initialize()); // 调用MV3D_RGBD库的初始化函数,并检查其是否成功。
MV3D_RGBD_VERSION_INFO stVersion; // 创建一个结构体变量来存储SDK版本信息。
ASSERT_OK(MV3D_RGBD_GetSDKVersion(&stVersion)); // 获取并记录SDK的版本信息。
LOGD("dll version: %d.%d.%d", stVersion.nMajor, stVersion.nMinor, stVersion.nRevision); // 打印版本号。
unsigned int nDevNum = 0; // 定义一个变量来存储设备的数量。
ASSERT_OK(MV3D_RGBD_GetDeviceNumber(DeviceType_Ethernet | DeviceType_USB, &nDevNum)); // 获取连接到系统的设备数量。
LOGD("MV3D_RGBD_GetDeviceNumber success! nDevNum:%d.", nDevNum); // 记录获取设备数量的结果。
ASSERT(nDevNum > 0); // 确保至少有一个设备可用。
std::vector<MV3D_RGBD_DEVICE_INFO> devs(nDevNum); // 创建一个向量来存储所有设备的信息。
ASSERT_OK(MV3D_RGBD_GetDeviceList(DeviceType_Ethernet | DeviceType_USB, &devs[0], nDevNum, &nDevNum)); // 获取所有设备的列表。
for (unsigned int i = 0; i < nDevNum; i++) { // 遍历所有找到的设备。
if (DeviceType_Ethernet == devs[i].enDeviceType) // 如果是网络设备。
LOG("Index[%d]. SerialNum[%s] IP[%s] Name[%s].\r\n", i, devs[i].chSerialNumber, devs[i].SpecialInfo.stNetInfo.chCurrentIp, devs[i].chModelName); // 打印设备信息。
else if (DeviceType_USB == devs[i].enDeviceType) // 如果是USB设备。
LOG("Index[%d]. SerialNum[%s] UsbProtocol[%d] Name[%s].\r\n", i, devs[i].chSerialNumber, devs[i].SpecialInfo.stUsbInfo.enUsbProtocol, devs[i].chModelName); // 打印设备信息。
}
LOG("---------------------------------------------------------------"); // 分割线,用于日志输出分隔。
unsigned int nIndex = 0; // 定义一个变量来存储用户选择的设备索引。
while (true) { // 进入无限循环,直到用户输入有效索引。
LOG("Please enter the index of the camera to be connected:\n"); // 提示用户输入要连接的相机索引。
std::cin >> nIndex; // 读取用户输入的索引。
LOG("Connected camera index:%d \r\n", nIndex); // 打印用户选择的索引。
if ((nDevNum <= nIndex) || (0 > nIndex)) { // 检查输入的索引是否有效。
LOG("enter error!\r\n"); // 如果无效,提示用户重新输入。
}
else break; // 如果有效,退出循环。
}
LOG("---------------------------------------------------------------\r\n"); // 分割线,用于日志输出分隔。
void* handle = nullptr; // 定义一个指针来存储打开设备后的句柄。
ASSERT_OK(MV3D_RGBD_OpenDevice(&handle, &devs[nIndex])); // 打开选定的设备。
LOGD("OpenDevice success."); // 如果成功打开设备,记录此信息。
ASSERT_OK(MV3D_RGBD_Start(handle)); // 开始从设备采集数据。
LOGD("Start work success."); // 如果成功启动设备,记录此信息。
bool bExit_Main = false; // 定义一个布尔值来控制主循环的退出条件。
MV3D_RGBD_FRAME_DATA stFrameData = { 0 }; // 创建一个结构体变量来存储帧数据。
int nDepthImgSaveCount = 0; // 定义一个计数器来跟踪已保存的深度图像数量。
int nRGBDImgSaveCount = 0; // 定义一个计数器来跟踪已保存的RGB图像数量。
unsigned char* g_pRgbData = nullptr; // 定义一个指针来存储转换后的RGB图像数据。
while (!bExit_Main) { // 主循环,持续运行直到满足退出条件。
int nRet = MV3D_RGBD_FetchFrame(handle, &stFrameData, 5000); // 尝试从设备抓取一帧数据,超时时间为5秒。
if (MV3D_RGBD_OK == nRet) { // 如果成功抓取到帧数据。
for (int i = 0; i < stFrameData.nImageCount; i++) { // 遍历该帧中的所有图像。
LOGD("MV3D_RGBD_FetchFrame Success: framenum (%d)(%d) height(%d) width(%d) len (%d)!", i, stFrameData.stImageData[i].nFrameNum,
stFrameData.stImageData[i].nHeight, stFrameData.stImageData[i].nWidth, stFrameData.stImageData[i].nDataLen); // 记录抓取到的帧信息。
if (ImageType_Depth == stFrameData.stImageData[i].enImageType) { // 如果当前图像是深度图像。
cv::Mat mCvmat(stFrameData.stImageData[i].nHeight, stFrameData.stImageData[i].nWidth, CV_16UC1, stFrameData.stImageData[i].pData); // 使用OpenCV创建一个Mat对象来表示深度图像。
std::string chFileName = "Depth_nFrameNum[" + std::to_string(stFrameData.stImageData[i].nFrameNum) + "].png"; // 构造文件名。
if (MAX_IMAGE_COUNT > nDepthImgSaveCount) { // 如果尚未达到最大保存数量。
cv::imwrite(chFileName, mCvmat); // 将深度图像保存为PNG文件。
nDepthImgSaveCount++; // 增加已保存的深度图像计数。
}
}
if (ImageType_YUV422 == stFrameData.stImageData[i].enImageType)
{
LOGD("The imgage tyoe is ImageType_YUV422");
cv::Mat mRGBMat(stFrameData.stImageData[i].nHeight, stFrameData.stImageData[i].nWidth, CV_8UC3);
cv::cvtColor(cv::Mat(stFrameData.stImageData[i].nHeight, stFrameData.stImageData[i].nWidth, CV_8UC2, stFrameData.stImageData[i].pData), mRGBMat, cv::COLOR_YUV2BGR_YUYV);
std::string rgbFileName = "RGB_nFrameNum[" + std::to_string(stFrameData.stImageData[i].nFrameNum) + "].png";
cv::imwrite(rgbFileName, mRGBMat);
}
if (ImageType_RGB8_Planar == stFrameData.stImageData[i].enImageType) { // 如果当前图像是RGB8平面图像。
if (!g_pRgbData) { // 如果还没有分配内存给g_pRgbData。
size_t dataLen = stFrameData.stImageData[i].nDataLen; // 获取图像数据长度。
g_pRgbData = new unsigned char[dataLen]; // 动态分配内存来存储转换后的图像数据。
if (!g_pRgbData) { // 如果分配失败。
LOGD("MV3D_RGBD_FetchFrame: g_pRgbData malloc failed!"); // 记录分配失败的信息。
bExit_Main = true; // 设置退出标志以终止主循环。
continue; // 跳过后续代码,继续下一次循环。
}
memset(g_pRgbData, 0, dataLen); // 初始化分配的内存为零。
}
ConvertRGB8Planner2BGR8Packed(stFrameData.stImageData[i].pData, stFrameData.stImageData[i].nWidth, stFrameData.stImageData[i].nHeight, g_pRgbData); // 转换RGB8平面图像为BGR8打包格式。
cv::Mat mCvmat(stFrameData.stImageData[i].nHeight, stFrameData.stImageData[i].nWidth, CV_8UC3, g_pRgbData); // 使用OpenCV创建一个Mat对象来表示转换后的图像。
std::string chFileName = "RGB_nFrameNum[" + std::to_string(stFrameData.stImageData[i].nFrameNum) + "].png"; // 构造文件名。
if (MAX_IMAGE_COUNT > nRGBDImgSaveCount) { // 如果尚未达到最大保存数量。
cv::imwrite(chFileName, mCvmat); // 将RGB图像保存为PNG文件。
nRGBDImgSaveCount++; // 增加已保存的RGB图像计数。
}
}
}
}
// 按任意键退出
if (_kbhit()) { // 如果有按键事件发生。
bExit_Main = true; // 设置退出标志以终止主循环。
}
}
ASSERT_OK(MV3D_RGBD_Stop(handle)); // 停止从设备采集数据。
ASSERT_OK(MV3D_RGBD_CloseDevice(&handle)); // 关闭设备。
ASSERT_OK(MV3D_RGBD_Release()); // 释放与设备相关的资源。
LOGD("Main done!"); // 日志记录:主程序完成。
delete[] g_pRgbData; // 释放之前分配的用于存储RGB图像数据的内存。
return 0; // 返回0,表示程序正常结束。
}
运行结束后,会获取一张深度图和一张RGB彩色图像