zoukankan      html  css  js  c++  java
  • 海康抓拍机SDK开发

    前言

    项目采购的海康威视的抓拍机,需要首先获取抓拍图片,之后基于抓拍图片进行图像处理。本文基于海康SDK开发文档,按照开发步骤,咨询海康技术人员,现将开发过程记录如下。

    主要过程的c++代码:

    /************************************************************************
    * Copyright(c) 2016  ZRJ
    * All rights reserved.
    *
    * File:    snap.h
    * Brief: 抓拍机配置头文件
    * Version: 1.0
    * Author: ZRJ
    * Email: happyamyhope@163.com
    * Date:    2016/12/08
    * History:
    * 20161202: 添加布防级别与退出撤防功能;
    * 20161207: 设置抓拍等待时间等;添加系统时间;
    * 20161208: 添加复制文件夹操作;
    * 20161208: 添加启动程序初始化图片不保存;删除网络触发抓拍部分;
    * 20161209: 删除网络触发抓拍部分;
    * 20161220: 现场调试增加的功能;
    * 20170109: 删除FIFO队列数据;
    * 20170123: 添加创建文件夹功能,删除预览取流部分;
    
    ************************************************************************/
    //-------------------------------------------------------------------------
    //头文件
    #include <stdio.h>
    #include <iostream>
    #include "Windows.h"
    #include "HCNetSDK.h"
    //获取系统时间
    #include <time.h>
    
    //OPENCV库文件
    #include <opencv2/core/core.hpp>      
    #include <opencv2/highgui/highgui.hpp>     
    #include <opencv2opencv.hpp>    
    #include <opencv2imgprocimgproc.hpp>  
    using namespace cv;
    using namespace std;
    
    typedef HWND(WINAPI *PROCGETCONSOLEWINDOW)();
    PROCGETCONSOLEWINDOW Getconsolewindow;
    
    //-----------------------------------------------------------------------
    //调参
    int iNum = 1;//抓拍图片的数目初始化值
    int pic_number = 1001;//抓拍文件夹存图数目
    //int j = 1;//显示抓拍图片的数目
    //注册设备
    LONG IUserID;//摄像机设备
    char *sDVRIP = "10.0.10.3";//抓拍摄像机设备IP地址
    short wDVRPort = 8000;//设备端口号
    char* sUserName = "admin";//登录的用户名
    char* sPassword = "admin123";//用户密码
    //
    time_t t;
    char now[64];
    
    //
    int fifo_flag = 0;//队列标志;
    double interval_time;//当前抓拍图片与前一帧抓拍时间之差;单位是ms;
    double interval_time_thres = 40000;//前后两帧抓拍时间间隔阈值40s;单位是ms;
    double pre_time;//系统开始时间;前一次抓拍图片的时间点;
    double cur_time;
    
    //
    LONG IHandle = -1;//报警布防;
    bool snap_flag = false;//是否抓拍的标志位
    NET_DVR_DEVICEINFO_V30 struDeviceInfo;//设备信息
    
    
    //---------------------------------------------------------------------------------
    //函数声明
    BOOL SHDeleteFolder(LPCTSTR pstrFolder);//删除指定目录
    void CopyFolder(SHFILEOPSTRUCT fop);//抓拍图片文件夹操作
    void CreateFolder(char* filename);//不存在则创建文件夹;
    void Init();//初始化
    void Connect();//设置连接事件与重连时间
    bool Login(char *sDVRIP, short wDVRPort, char *sUserName, char *sPassword);//注册摄像机设备
    void CALLBACK MSesGCallback(LONG ICommand, NET_DVR_ALARMER *pAlarmer, char *pAlarmInfo, DWORD dwBufLen, void *pUser);//报警回调函数
    void SetMessageCallBack();//设置报警回调函数
    void SetupAlarm();//报警布防
    void CloseAlarm();//报警撤防
    void OnExit(void);//退出
    extern int snap();//抓拍
    
    //-----------------------------------------------------------------------------------------
    //函数定义
    
    //初始化
    void Init()
    {
        NET_DVR_Init();
    }
    //设置连接事件与重连时间
    void Connect()
    {
        NET_DVR_SetConnectTime(2000, 1);
        NET_DVR_SetReconnect(10000, true);
    }
    //注册摄像机设备
    bool Login(char *sDVRIP, short wDVRPort, char *sUserName, char *sPassword)
    {
        IUserID = NET_DVR_Login_V30(sDVRIP, wDVRPort, sUserName, sPassword, &struDeviceInfo);
    
        if (IUserID < 0)
        {
            std::cout << "Login Failed! Error number:" << NET_DVR_GetLastError() << std::endl;
            NET_DVR_Cleanup();
            return false;
        }
        else
        {
            std::cout << "Login Successfully!" << std::endl;
            return true;
        }
    
    }
    //报警回调函数
    void CALLBACK MSesGCallback(LONG ICommand, NET_DVR_ALARMER *pAlarmer, char *pAlarmInfo, DWORD dwBufLen, void *pUser)
    {
        //unsigned int i = 0;
        char filename[100];
        FILE *fSnapPic = NULL;
        //std::cout << "Callback MSesGCallback one time..." << std::endl;
        //std::cout << "ICommand:" << ICommand << std::endl;
        //以下代码仅供参考,实际应用中不建议在该回调函数中直接处理数据保存文件,
        //例如可以使用消息的方式(PostMessage)在消息响应函数里进行处理
    
        switch (ICommand)
        {
        case COMM_UPLOAD_PLATE_RESULT://交通抓拍结果(老报警消息)
        {
            NET_DVR_PLATE_RESULT struPlateResult = { 0 };
            memcpy(&struPlateResult, pAlarmInfo, sizeof(struPlateResult));
    
            //获取场景图
            if (struPlateResult.dwPicLen != 0 && struPlateResult.byResultType == 1)
            {
                snap_flag = true;
                //计时 
                cur_time = (double)getTickCount();//当前抓拍图片的时间点;
                t = time(NULL);//系统当前时间
                strftime(now, sizeof(now), "%Y%m%dT%H%M%S", localtime(&t));
                sprintf(filename, ".\pic\testpic%d_%s.jpg", iNum, now);
                fSnapPic = fopen(filename, "wb");
                fwrite(struPlateResult.pBuffer1, struPlateResult.dwPicLen, 1, fSnapPic);
    
                //前后两次抓拍图片的时间差
                if (fifo_flag == 0)//系统开始
                {
                    interval_time = 100;
                    fifo_flag = 1;
                }
                else
                {
                    interval_time = (cur_time - pre_time) * 1000 / (getTickFrequency());//单位是ms; 
                }
    
                //fifo标志位转换
                if (interval_time > interval_time_thres)
                {
                    if (fifo_flag == 1)
                    {
                        fifo_flag = 2;
                    }
                    else if (fifo_flag == 2)
                    {
                        fifo_flag = 1;
                    }
                }
                //std::cout << "fifo_flag:  " << fifo_flag << std::endl;
                //获取抓拍图片队列
                if (fifo_flag == 1)
                {
                    std::cout << "fifo1 push back one time..." << std::endl;
                }
                else if (fifo_flag == 2)
                {
                    std::cout << "fifo2 push back one time..." << std::endl;
                }
    
                iNum++;
                if (pic_number == iNum)
                {
                    iNum = 1;
                    CopyFolder(fop);//抓拍图片文件夹操作
                }
                else
                {
    
                }
                pre_time = cur_time;
                fclose(fSnapPic);
            }
            else
            {
                snap_flag = false;
            }
    
            //其他信息处理
            break;
    
        }
        case COMM_ITS_PLATE_RESULT://交通抓拍结果(新报警信息)
        {
            NET_ITS_PLATE_RESULT struITSPlateResult = { 0 };//识别结果结构体;dwPicNum 
            memcpy(&struITSPlateResult, pAlarmInfo, sizeof(struITSPlateResult));
            struITSPlateResult.dwPicNum = 1;//图片数量(与byGroupNum不同,代表本条信息附带的图片数量) 
            //保存场景图
            if ((struITSPlateResult.struPicInfo[0].dwDataLen != 0) && (struITSPlateResult.struPicInfo[0].byType == 1))
            {
                snap_flag = true;
                //计时 
                cur_time = (double)getTickCount();
                //系统当前时间
                t = time(NULL);
                strftime(now, sizeof(now), "%Y%m%dT%H%M%S", localtime(&t));
                sprintf(filename, ".\pic\testITSpic%d_%s.jpg", iNum, now);
                fSnapPic = fopen(filename, "wb");
                fwrite(struITSPlateResult.struPicInfo[0].pBuffer, struITSPlateResult.struPicInfo[0].dwDataLen, 1, fSnapPic);
    
                //前后两次抓拍图片的时间差
                if (fifo_flag == 0)//系统开始
                {
                    interval_time = 100;
                    fifo_flag = 1;
                }
                else
                {
                    interval_time = (cur_time - pre_time) * 1000 / (getTickFrequency());//单位是ms; 
                }
                //std::cout << "interval_time:  " << interval_time << std::endl;
    
                //fifo标志位转换
                if (interval_time > interval_time_thres)
                {
                    if (fifo_flag == 1)
                    {
                        fifo_flag = 2;
                    }
                    else if (fifo_flag == 2)
                    {
                        fifo_flag = 1;
                    }
                }
                //std::cout << "fifo_flag:  " << fifo_flag << std::endl;
                //获取抓拍图片队列
                if (fifo_flag == 1)
                {
                    std::cout << "fifo1 push back one time..." << std::endl;
                }
                else if (fifo_flag == 2)
                {
                    std::cout << "fifo2 push back one time..." << std::endl;
                }
    
                iNum++;
                if (pic_number == iNum)
                {
                    iNum = 1;
                    CopyFolder(fop);//抓拍图片文件夹操作
                }
                else
                {
    
                }
                pre_time = cur_time;
                //std::cout << "pre_time:  " << pre_time << std::endl;
    
                fclose(fSnapPic);
            }
            else
            {
                snap_flag = false;
            }
            //其他处理信息......
            break;
        }
    
        default:
            break;
    
        }
    
    
        return;
    }
    //设置报警回调函数
    void SetMessageCallBack()
    {
        NET_DVR_SetDVRMessageCallBack_V30(MSesGCallback, NULL);
    }
    //报警布防
    void SetupAlarm()
    {
        //启动布防
        NET_DVR_SETUPALARM_PARAM struSetupParam = { 0 };
        struSetupParam.dwSize = sizeof(NET_DVR_SETUPALARM_PARAM);
    
        //上传报警信息类型:0-老报警信息(NET_DVR_PLATE_RESULT), 1-新报警信息(NET_ITS_PLATE_RESULT)
        struSetupParam.byAlarmInfoType = 1;
        struSetupParam.byLevel = 1;//布防优先级:0- 一等级(高),1- 二等级(中),2- 三等级(低)
        //bySupport 按位表示,值:0 - 上传,1 - 不上传;  bit0 - 表示二级布防是否上传图片;
    
    
        IHandle = NET_DVR_SetupAlarmChan_V41(IUserID, &struSetupParam);//建立报警上传通道,获取报警等信息。
        if (IHandle < 0)
        {
            std::cout << "NET_DVR_SetupAlarmChan_V41 Failed! Error number:" << NET_DVR_GetLastError() << std::endl;
            NET_DVR_Logout(IUserID);
            NET_DVR_Cleanup();
            return;
        }
        std::cout << "
    " << endl;
    
    }
    //报警撤防
    void CloseAlarm()
    {
        //撤销布防上传通道
        if (!NET_DVR_CloseAlarmChan_V30(IHandle))//布防句柄IHandle
        {
            std::cout << "NET_DVR_CloseAlarmChan_V30 Failed! Error number:" << NET_DVR_GetLastError() << std::endl;
            NET_DVR_Logout(IUserID);
            NET_DVR_Cleanup();
            return;
        }
        IHandle = -1;//布防句柄;
    }
    
    void OnExit(void)
    {
        std::cout << "Begin exit..." << std::endl;
    
        //报警撤防
        CloseAlarm();
    
        //释放相机
        NET_DVR_Logout(IUserID);//注销用户
        NET_DVR_Cleanup();//释放SDK资源
    }
    //抓拍
    extern int snap()
    {
        atexit(OnExit);
        int CycleCount = 10;
        bool LoginSuccess = false;
    
        //获取控制台窗口句柄
        HMODULE hKernel32 = GetModuleHandle("kernel32");
        Getconsolewindow = (PROCGETCONSOLEWINDOW)GetProcAddress(hKernel32, "GetConsoleWindow");
    
        CreateFolder(picfile);//不存在则创建文件夹;
        CreateFolder(savepicfile);//不存在则创建文件夹;
        Init();//初始化
        Connect();//设置连接事件与重连时间
        //注册设备
        if (Login(sDVRIP, wDVRPort, sUserName, sPassword))
        {
            LoginSuccess = true;
            SetMessageCallBack();//设置报警回调函数
            SetupAlarm();//报警布防        
            return 0;
        }
        else
        {
            for (int i = 0; i < CycleCount; i++)
            {
                std::cout << "Begin to Login again......" << std::endl;
                if (Login(sDVRIP, wDVRPort, sUserName, sPassword))
                {
                    LoginSuccess = true;
                    SetMessageCallBack();//设置报警回调函数
                    SetupAlarm();//报警布防        
                    break;
                }
            }
            if (!LoginSuccess)
            {
                std::cout << "Failed! The application has tried 10 times to login. But still can not login! Press any key to exit......" << std::endl;
            }
        }
        return -1;
    
    }
    
    int main()
    {
        atexit(OnExit);
        snap();
        getchar();
    
    }
    View Code

    注意:

    1.第一步需要配置SDK和opencv相关文件;

    2.熟悉抓拍机SDk的开发流程,可参见开发文档;

    3.布防成功之后,需要添加退出撤防功能;

    4.保存图片可能需要用到相关文件夹操作;

    5.预览取流部分可以根据需要选择,为了实时性本文没有使用;

    6.为了之后的图像处理过程,将图片数据存在FIFO队列中,但一定要记得及时删除相应的队列,否则会造成内存泄漏,从而导致系统崩溃(宝宝就不小心犯了这样的低级错误,以此为戒!!!);

    7.布防级别的设置,这个一定要问清楚技术支持,因为你根本就查不到,反正宝宝没有查到!!!宝宝委屈但宝宝不说~~~

    体会

    第一次接触SDk开发,期间真是各种心酸,说多了都是泪~~~不过,整个过程首先你需要知道大致的框架和流程,认真研读需要部分的开发文档,一般也会有代码示例可以参考,按照文档的思路走你就一定会成功的,相信自己!!!中间过程如果遇到任何问题可以及时咨询技术支持,最好邮件联系,那段时间海康的技术支持可能都记着宝宝啦~~另外,第一次做某件事情担心害怕也是正常的,但是你一定要相信自己,静下心去做,只有真正去实践了,才会遇到问题,遇到问题也不要怕更不要急躁,可以查资料,可以问大神,可以问技术支持,总会解决的!!!无论做什么事情都要一步步去做,在实践的过程中所有问题和答案就会越来越清晰了~~

  • 相关阅读:
    列表,字典,元组,集合内置方法
    数据类型内置方法(1)
    if判断与while、for循环语句
    与用户交互、格式化输出、基本运算符
    执行python程序的两种方式
    # 操作系统与编程语言分类
    drf框架2-序列化与反序列化
    drf框架1
    前端-vue路由传参、axios前后台交互、cookie设置
    前端-vue的配置和使用
  • 原文地址:https://www.cnblogs.com/happyamyhope/p/6594117.html
Copyright © 2011-2022 走看看