学习笔记 c++ (LINUX 下C++大华sdk 抓图)

这段代码展示了如何初始化Dahua网络SDK,登录设备,设置断线重连和抓图回调函数。在回调函数中,接收到图像数据后将其保存为JPEG格式的图片。整个过程涉及到了OpenCV库和Dahua的SDK接口,用于从远程设备获取和处理视频流。
摘要由CSDN通过智能技术生成
#include <ros/ros.h>

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <iomanip>
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>

#include "std_msgs/Int32.h"
#include <vector>
#include <std_msgs/String.h>
#include "dhnetsdk.h"
#include "dhconfigsdk.h"
#include <stdio.h>

using namespace cv;
using namespace std;


static BOOL g_bNetSDKInitFlag = FALSE;
static LLONG g_lLoginHandle = 0L;
//static char g_szDevIp[32] = "";
static char g_szDevIp[32] = "192.168.1.4";
static WORD g_nPort = 37777; // tcp 连接端口,需与期望登录设备页面 tcp 端口配置一致
static char g_szUserName[64] = "admin";
static char g_szPasswd[64] = "111111111";
static short g_nCmdSerial = 0; // 抓图序列号

//*********************************************************************************
// 常用回调集合声明
// 设备断线回调函数
// 不建议在该回调函数中调用 SDK 接口
// 通过 CLIENT_Init 设置该回调函数,当设备出现断线时,SDK 会调用该函数。
void CALLBACK DisConnectFunc(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, DWORD dwUser);
//void CALL_METHOD Disconnect(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, LDWORD dwUser)
//{
//	cout << "Receive disconnect message, where ip:" << pchDVRIP << " and port:" 
//		 << nDVRPort << " and login handle:" << lLoginID << endl; 
//}
// 断线重连成功回调函数
// 不建议在该回调函数中调用 SDK 接口
// 通过 CLIENT_SetAutoReconnect 设置该回调函数,当已断线的设备重连成功时,SDK 会调用该函数。
void CALLBACK HaveReConnect(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, LDWORD dwUser);
// 抓图回调函数
// 不建议在该回调函数中调用 SDK 接口
// 通过 CLIENT_SetSnapRevCallBack 设置该回调函数,当前端设备有抓图数据发送过来时,SDK 会调用该函数
void CALLBACK SnapRev(LLONG lLoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, DWORD CmdSerial, LDWORD dwUser);
//*********************************************************************************
// 常用函数声明

// 获取输入的整形
int GetIntInput(char *szPromt, int& nError);
// 获取输入的字符串
void GetStringInput(const char *szPromt , char *szBuffer);
//*********************************************************************************
void InitTest()
{
    // 初始化 SDK
    g_bNetSDKInitFlag = CLIENT_Init((fDisConnect)DisConnectFunc, (LDWORD)0);
    //g_bNetSDKInitFlag =CLIENT_Init(Disconnect, NULL);
    if (FALSE == g_bNetSDKInitFlag)
    {
        printf("Initialize client SDK fail; \n");
        return;
    }
    else
    {
        printf("Initialize client SDK done; \n");
    }
    // 获取 SDK 版本信息
    // 此操作为可选操作
    DWORD dwNetSdkVersion = CLIENT_GetSDKVersion();
    printf("NetSDK version is [%d]\n", dwNetSdkVersion);
    // 设置断线重连回调接口,设置过断线重连成功回调函数后,当设备出现断线情况,SDK内部会自动进行重连操作
    // 此操作为可选操作,但建议用户进行设置
    CLIENT_SetAutoReconnect(&HaveReConnect, 0);
    // 设置登录超时时间和尝试次数
    // 此操作为可选操作
    int nWaitTime = 5000;
    // 登录请求响应超时时间设置为 5s
    int nTryTimes = 3;
    // 登录时尝试建立链接 3 次
    CLIENT_SetConnectTime(nWaitTime, nTryTimes);
    // 设 置 更 多 网 络 参 数 , NET_PARAM 的 nWaittime , nConnectTryNum 成 员 与CLIENT_SetConnectTime 接口设置的登录设备超时时间和尝试次数意义相同
    // 此操作为可选操作
    NET_PARAM stuNetParm = {0};
    stuNetParm.nConnectTime = 3000; // 登录时尝试建立链接的超时时间
    CLIENT_SetNetworkParam(&stuNetParm);
    NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY stInparam;
    NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY stOutparam;
    memset(&stInparam, 0, sizeof(stInparam));

    stInparam.dwSize = sizeof(stInparam);
    strncpy(stInparam.szIP, g_szDevIp, sizeof(stInparam.szIP) - 1);
    strncpy(stInparam.szPassword, g_szPasswd, sizeof(stInparam.szPassword) - 1);
    strncpy(stInparam.szUserName, g_szUserName, sizeof(stInparam.szUserName) - 1);
    stInparam.nPort = g_nPort;
    stInparam.emSpecCap = EM_LOGIN_SPEC_CAP_TCP;
    //while(0 == g_lLoginHandle)
    //{
        // 登录设备
        g_lLoginHandle = CLIENT_LoginWithHighLevelSecurity(&stInparam, &stOutparam);
        if(0 == g_lLoginHandle)
        {
            // 根据错误码,可以在 dhnetsdk.h 中找到相应的解释,此处打印的是 16 进制,头文件中是十进制,其中的转换需注意
            // 例如:
            // #define NET_NOT_SUPPORTED_EC(23) // 当前 SDK 未支持该功能,对应的错误码为 0x80000017, 23 对应的 16 进制为 0x17
            printf("CLIENT_LoginWithHighLevelSecurity %s[%d]Failed!Last Error[%x]\n" ,g_szDevIp , g_nPort , CLIENT_GetLastError());
        }
        else
        {
            printf("CLIENT_LoginWithHighLevelSecurity %s[%d] Success\n" , g_szDevIp ,g_nPort);
        }
        // 用户初次登录设备,需要初始化一些数据才能正常实现业务功能,建议登录后等待一小段时间,具体等待时间因设备而异。
        usleep(1*1000);
        printf("\n");
    //}
}

void RunTest()
{
    if (FALSE == g_bNetSDKInitFlag)
    {
        return;
    }
    if (0 == g_lLoginHandle)
    {
        return;
    }
    // 设置抓图回调函数
    CLIENT_SetSnapRevCallBack(SnapRev, NULL);
    char szUserChoose[1];
    do
    {
        //事例中默认通道 ID 为 0、抓图模式为抓一幅图,用户可根据实际情况自行选择
        int nChannelId = 0;
        int nSnapType = 0;// 抓图模式;-1:表示停止抓图, 0:表示请求一帧, 1:表示定时发送请求, 2:表示连续请求
        // 发送抓图命令给前端设备
        SNAP_PARAMS stuSnapParams;
        stuSnapParams.Channel = nChannelId;
        stuSnapParams.mode = nSnapType;
        stuSnapParams.CmdSerial = ++g_nCmdSerial; // 请求序列号,有效值范围 0~65535,超过范围会被截断为 unsigned short
        if (FALSE == CLIENT_SnapPictureEx(g_lLoginHandle, &stuSnapParams))
        {
            printf("CLIENT_SnapPictureExFailed!LastError[%x]\n", CLIENT_GetLastError());
            return;
        }
        else
        {
            printf("CLIENT_SnapPictureEx succ\n");
        }
        GetStringInput("'q': 退出; 'c': 继续\n", szUserChoose);
    }while('q' != szUserChoose[0]);
    return;
}

void EndTest()
{
    printf("input any key to quit!\n");
    getchar();
    // 退出设备
    if (0 != g_lLoginHandle)
    {
        if(FALSE == CLIENT_Logout(g_lLoginHandle))
        {
            printf("CLIENT_Logout Failed!Last Error[%x]\n", CLIENT_GetLastError());
        }
        else
        {
            g_lLoginHandle = 0;
        }
    }
    // 清理初始化资源
    if (TRUE == g_bNetSDKInitFlag)
    {
        CLIENT_Cleanup();
        g_bNetSDKInitFlag = FALSE;
    }
    exit(0);
}

//*********************************************************************************
// 常用回调集合定义
void CALL_METHOD DisConnectFunc(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, DWORD dwUser)
{
    printf("Call DisConnectFunc\n");
    printf("lLoginID[0x%x]", lLoginID);
    if (NULL != pchDVRIP)
    {
        printf("pchDVRIP[%s]\n", pchDVRIP);
    }
    printf("nDVRPort[%d]\n", nDVRPort);
    printf("dwUser[%p]\n", dwUser);
    printf("\n");
}

void CALLBACK HaveReConnect(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, LDWORD dwUser)
{
    printf("Call HaveReConnect\n");
    printf("lLoginID[0x%x]", lLoginID);
    if (NULL != pchDVRIP)
    {
        printf("pchDVRIP[%s]\n", pchDVRIP);
    }
    printf("nDVRPort[%d]\n", nDVRPort);
    printf("dwUser[%p]\n", dwUser);
    printf("\n");
}

void CALLBACK SnapRev(LLONG lLoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, DWORD CmdSerial, LDWORD dwUser)
{
    printf("[SnapRev] -- receive data!\n");
    if(lLoginID == g_lLoginHandle)
    {
        if (NULL != pBuf && RevLen > 0)
        {
            char szPicturePath[256] = "";
            time_t stuTime;
            time(&stuTime);
            char szTmpTime[128] = "";
            
            strftime(szTmpTime,sizeof(szTmpTime) - 1, "%y%m%d_%H%M%S", gmtime(&stuTime));
            snprintf(szPicturePath, sizeof(szPicturePath)-1, "%d_%s.jpg", CmdSerial, szTmpTime);
            //保存图片数据方式一(方式一和方式二都可以用,根据需求选择一个即可)
            //直接写入文件中并保持
            printf("szPicturePath: %s\n", szPicturePath);
            FILE* pFile = fopen(szPicturePath, "wb");
            if (NULL == pFile)
            {
                return;
            }
            int nWrite = 0;
            while(nWrite != RevLen)
            {
                nWrite += fwrite(pBuf + nWrite, 1, RevLen - nWrite, pFile);
            }
            fclose(pFile);

            //保存图片数据方式二(方式一和方式二都可以用,根据需求选择一个即可)
            //转换到opencv图片格式并保持图片
            Mat hik_image;
            std::vector<char> data;
            for(int i = 0; i < RevLen; i++)
            {
                data.push_back(pBuf[i]);
            }
            hik_image = imdecode(Mat(data),1);
            std::string image_name = szPicturePath;
            std::string path = "/tmp/dahua" + image_name;
            cv::imwrite(path.c_str(), hik_image);
            data.clear();
            hik_image.release();
        }
    }
}
//*********************************************************************************
// 常用函数定义
int GetIntInput(char *szPromt, int& nError)
{
    long int nGet = 0;
    char* pError = NULL;
    printf(szPromt);
    char szUserInput[32] = "";
    gets(szUserInput);
    nGet = strtol(szUserInput, &pError, 10);
    if ('\0' != *pError)
    {
        // 入参有误
        nError = -1;
    }
    else
    {
        nError = 0;
    }
    return nGet;
}

void GetStringInput(const char *szPromt , char *szBuffer)
{
    printf(szPromt);
    gets(szBuffer);
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "test_carema");
    ros::NodeHandle nh;
    ros::Rate loop_rate(1.0);
    ROS_INFO_STREAM("Hello, ROS!");

    InitTest();
    RunTest();
    EndTest();

    ros::MultiThreadedSpinner spinner(0);
    spinner.spin();

    return 0;
}

结果:

 

要调用大华SDK进行抓图,首先需要安装大华SDK,并且需要安装Python的SDK封装。以下是一个简单的示例代码: ```python import ctypes # 加载SDK库 dhnetsdk = ctypes.cdll.LoadLibrary("dhnetsdk.dll") # 登录设备 login_info = dhnetsdk.LPNET_DEVICEINFO_Ex() login_info.szIP = "192.168.1.100".encode('utf-8') # 设备IP地址 login_info.szUserName = "admin".encode('utf-8') # 登录用户名 login_info.szPassword = "12345".encode('utf-8') # 登录密码 login_info.nPort = 37777 # 设备端口号 login_info.nProto = 2 # 网络协议类型,0表示TCP,1表示UDP,2表示多播 login_info.nType = 0 # 设备类型,0表示DVR,1表示NVMS login_info.bUseAsynLogin = False # 是否异步登录 login_info.byReserved = None # 保留字段 login_info.pCapParam = None # 能力集参数 login_id = dhnetsdk.CLIENT_LoginEx2(login_info, None) # 设置抓图回调函数 def capture_callback(lLoginID, pBuf, RevLen, EncodeType, CmdSerial, dwUser): print("Capture success!") capture_fn = ctypes.CFUNCTYPE(None, ctypes.c_long, ctypes.POINTER(ctypes.c_ubyte), ctypes.c_ulong, ctypes.c_ulonglong, ctypes.c_ulong, ctypes.c_void_p) capture_cb = capture_fn(capture_callback) dhnetsdk.CLIENT_SetSnapRevCallBack(login_id, capture_cb, None) # 发送抓图命令 snap_cfg = dhnetsdk.NET_SNAP_PARAMS() snap_cfg.Channel = 0 # 摄像头通道号 snap_cfg.Quality = 3 # 图片质量,0表示最好,3表示最差 snap_cfg.ImageSize = 2 # 图片大小,0表示最大,1表示640*480,2表示320*240 snap_cfg.mode = 0 # 抓图模式,0表示实时抓图,1表示定时抓图 snap_cfg.InterSnap = 0 # 抓图间隔时间,单位为秒 snap_cfg.CmdSerial = 0 # 命令序列号 snap_info = dhnetsdk.LPNET_SNAP_CFG() snap_info.dwSize = ctypes.sizeof(snap_cfg) snap_info.pSnapCfg = ctypes.pointer(snap_cfg) dhnetsdk.CLIENT_SnapPictureEx(login_id, snap_info, None) # 退出登录 dhnetsdk.CLIENT_Logout(login_id) ``` 需要注意的是,大华SDK的函数都是C语言编写的,所以在Python中调用时需要进行一些类型转换。在上面的代码中,我们使用了ctypes库来进行类型转换和调用大华SDK的函数。另外,抓图回调函数需要传入一个指针类型的参数,这里我们传入了None。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值