海康RGBD相机使用C++和Opencv采集图像记录

海康RGBD相机使用C++和Opencv采集图像记录

RGBD相机型号:MV-EB435i
配置:1.Vs2019 2.Opencv4.6

一、安装客户端

1.下载链接

HiViewer

在这里插入图片描述

2.官方Samples

安装后,在帮助-development中,可以看到一些samples,但是这些样例都是使用较老的版本编辑的。比如Opencv是使用opencv2.4编辑的,里面有些函数太老了,需要替换。
在这里插入图片描述
在这里插入图片描述

二、修改代码

打开Samples中的opencv调用样例
在这里插入图片描述
将样例拷贝出来,到别的本地文件夹再继续进行修改,其中只需要修改main.cpp文件
main.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彩色图像
在这里插入图片描述

三、部署到自己的项目环境

上述一、二章只是跑通demo,还需要进一步部署到自己的环境中。以新建一个项目为例。
1.新建common.h文件
在新建的项目中新建一个common.h文件,并复制common/common.hpp文件中的内容到该文件中,其内容如下:

#pragma once
#ifndef SAMPLE_COMMON_COMMON_HPP_
#define SAMPLE_COMMON_COMMON_HPP_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <fstream>
#include <iterator>
#include <conio.h>
#include <process.h>

#include "Mv3dRgbdApi.h"
#include "Mv3dRgbdDefine.h"
#include "Mv3dRgbdImgProc.h"

#ifndef ASSERT
#define ASSERT(x)   do{ \
                if(!(x)) { \
                    LOGE("Assert failed at %s:%d", __FILE__, __LINE__); \
                    LOGE("Source Code: " #x ); \
                    system("pause"); \
                    exit(0); \
                                } \
                        }while(0)
#endif

#ifndef ASSERT_OK
#define ASSERT_OK(x)    do{ \
                int err = (x); \
                if(err != MV3D_RGBD_OK) { \
                LOGE("Assert failed: error %#x at %s:%d", err, __FILE__, __LINE__); \
                    LOGE("Source Code: " #x ); \
                    system("pause"); \
                    exit(0); \
                                } \
                        }while(0)
#endif


#ifdef _WIN32
# include <windows.h>
# include <time.h>
static inline char* getLocalTime()
{
    static char local[26] = { 0 };
    SYSTEMTIME wtm;
    struct tm tm;
    GetLocalTime(&wtm);
    tm.tm_year = wtm.wYear - 1900;
    tm.tm_mon = wtm.wMonth - 1;
    tm.tm_mday = wtm.wDay;
    tm.tm_hour = wtm.wHour;
    tm.tm_min = wtm.wMinute;
    tm.tm_sec = wtm.wSecond;
    tm.tm_isdst = -1;

    strftime(local, 26, "%Y-%m-%d %H:%M:%S", &tm);

    return local;
}

#else
# include <sys/time.h>
# include <unistd.h>
static inline char* getLocalTime()
{
    static char local[26] = { 0 };
    time_t time;

    struct timeval tv;
    gettimeofday(&tv, NULL);

    time = tv.tv_sec;
    struct tm* p_time = localtime(&time);
    strftime(local, 26, "%Y-%m-%d %H:%M:%S", p_time);

    return local;
}
#endif

#define LOG(fmt,...)   printf(fmt "\n", ##__VA_ARGS__)
#define LOGD(fmt,...)  printf("(%s) " fmt "\n", getLocalTime(), ##__VA_ARGS__)
#define LOGE(fmt,...)  printf("(%s) Error: " fmt "\n", getLocalTime(), ##__VA_ARGS__)


#endif

2.增加附加包含目录
向属性----->C/C+±---->常规------->附加包含目录中写入:

$(MV3DRGBD_DEV_ENV)\Includes

在这里插入图片描述
3.拷贝Mv3dRgbd.lib文件
将C:\Program Files (x86)\HiViewer\Development\Libraries\win64目录下的Mv3dRgbd.lib拷贝到项目路径下
在这里插入图片描述
4.配置opencv环境
这一段参考:vs2015配置opencv记录
5.配置pcl环境
这一段参考:win10下安装pcl+vs2019记录
至此,基础环境搭建完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小俊俊的博客

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

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

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

打赏作者

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

抵扣说明:

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

余额充值