1. 程式人生 > >海康威視攝像頭+OpenCV+VS2017 影象處理小結(二)

海康威視攝像頭+OpenCV+VS2017 影象處理小結(二)

第二篇
先介紹海康威視SDK的配置;
接著介紹並提取OpenCV庫的標頭檔案以及庫檔案供工程使用,期間還演示瞭如何配置屬性表;
最後將海康威視的SDK進行封裝,封裝成HK_camera類,並在主函式中生成並呼叫這個類的例項。

目錄

一、海康威視SDK下載以及VS工程配置:

1. 下載海康威視SDK:

海康威視SDK下載地址(32位或者64位根據各自工程需求下載,博主此處下載的是64位)

海康威視SDK下載

2. 新建控制檯工程:

將工程模式調至Release|X64模式
這裡寫圖片描述
在工程目錄下新建一個命名為3rd_x64的資料夾存放三方庫,再在此資料夾中新建一個名為HC_vision_SDK_x64

庫資料夾,並新建include資料夾和lib資料夾(如下圖所示),其中的檔案分別來自於我們下載的64位SDK中的標頭檔案(CH-HCNetSDK(Windows64)V5.3.1.22_build20170909\標頭檔案\)以及庫資料夾下檔案(CH-HCNetSDK(Windows64)V5.3.1.22_build20170909\庫檔案\)。
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

3. 配置屬性表:

(1)為了方便之後重新建立的工程使用這次專案的配置,需要新建一個屬性表,下次新建工程需要配置的時候只要匯入此屬性表就好,到屬性管理器中的Release|64模式下右擊新建屬性表,命名為HC_x64_release.prosp

,雙擊新建好的屬性表,新增include檔案目錄與lib檔案目錄。為了工程的通用性,此處配置為相對路徑。
具體配置如下
(2)標頭檔案

../3rd_x64/HC_vision_SDK_x64/include

這裡寫圖片描述
(3)庫檔案

../3rd_x64/HC_vision_SDK_x64/lib/HCCore.lib
../3rd_x64/HC_vision_SDK_x64/lib/HCNetSDK.lib
../3rd_x64/HC_vision_SDK_x64/lib/PlayCtrl.lib
../3rd_x64/HC_vision_SDK_x64/lib/GdiPlus.lib
../3rd_x64/HC_vision_SDK_x64/lib/HCNetSDKCom/HCAlarm.lib
../3rd_x64/HC_vision_SDK_x64/lib/HCNetSDKCom/HCGeneralCfgMgr.lib
../3rd_x64/HC_vision_SDK_x64/lib/HCNetSDKCom/HCPreview.lib

這裡寫圖片描述

二、OpenCV下載以及屬性表的新增:

1. 原始檔下載、安裝以及庫檔案和標頭檔案的提取:

(1)下載。

OpenCV 2.4.13下載地址(不一定是2.4.13,可以根據自己的VS版本選擇合適的版本)

(2)安裝以及相關資料夾說明。此處為了建立的專案能夠通用一些,會將opencv相應函式的實現程式碼的標頭檔案和庫檔案提取出來,而不是直接使用1.25 GB 的原opencv安裝檔案。下載了安裝包後安裝至自定義的相應路徑(opencv其實本質是一個有很多原始碼和相應的編譯檔案的SDK包,說是安裝,其實就是把這個包解壓至相應路徑),博主是解壓至G盤,具體路徑是G:\Program\opencv目錄。

此處說明一下,解壓出來後可以看到opencv資料夾下有兩個資料夾,一個是原始碼sources資料夾,它裡面存放了opencv所有的源程式以及依賴庫的源程式),另一個是Opencv替我們編譯好的build資料夾,待會我們就要將此資料夾下的一些檔案拷貝出來以便工程中使用opencv庫。

進入G:\Program\opencv\build\x64資料夾下可以看到vc14這個資料夾,vc14資料夾名的含義主要是指opencv編譯出的庫檔案所對應的VC編譯器版本,它是根據各個不同版本的VisualStudio而編譯的檔案,其中各個版本的VS對應的VC編譯器版本如下

Visual Studio版本 vc版本
Visual Studio 2008 vc9
Visual Studio 2010 vc10
Visual Studio 2012 vc11
Visual Studio 2013 vc12
Visual Studio 2015 vc14
Visual Studio 2017 vc15

,博主是下載的VC14版本的Opencv 2.4.13(最好自己的Visual Studio版本要和Oencv此處的編譯版本一致,如果不一致可以到我剛剛給出的Opencv的下載地址的上一級目錄檢視適配版本下載)。

(3)提取庫檔案。進入G:\Program\opencv\build\x64\vc14資料夾下可以看到三個個資料夾:bin資料夾,lib資料夾和staticlib資料夾。其中bin資料夾和lib資料夾下的檔案是動態連結opencv庫時需要的檔案,而staticlib資料夾下的檔案是靜態連結opencv庫時需要的檔案(其中動態連結與靜態連結的相關概念可以參照如下連結:.h標頭檔案、 .lib庫檔案、 .dll動態連結庫檔案的關係),因為我們此處採用的是動態連結,所以只需要bin資料夾和lib資料夾拷貝出來即可。先在C:\Users\yp\Desktop\03_海康威視攝像頭\海康威視_demo\3rd_x64(此處使用的是博主的海康威視專案的路徑)下新建一個名為opencv-x64的庫,並在這個資料夾下新建一個lib資料夾,將剛剛bin資料夾和lib資料夾拷貝至此lib資料夾下。

(4)提取標頭檔案。G:\Program\opencv\build下的include資料夾拷貝出來,再複製到剛剛新建的opencv-x64資料夾下。
至此,opencv的提取工作完畢,接下來配置opencv的屬性表。

2.補充屬性表內容:

和剛剛新建海康威視SDK的屬性表一樣,不過此處我們直接在剛剛新新增HC_x64_release.prosp屬性表中新增opencv的相關配置,並將屬性表改名為HC_OpenCV_x64_release.prosp
(1)標頭檔案

../3rd_x64/opencv-x64/include
../3rd_x64/opencv-x64/include/opencv
../3rd_x64/opencv-x64/include/opencv2

這裡寫圖片描述
(2)庫檔案

../3rd_x64/opencv-x64/lib/release/opencv_ml2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_objdetect2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_ts2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_video2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_nonfree2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_ocl2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_photo2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_stitching2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_superres2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_videostab2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_calib3d2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_contrib2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_core2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_features2d2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_flann2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_gpu2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_highgui2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_imgproc2413.lib
../3rd_x64/opencv-x64/lib/release/opencv_legacy2413.lib
kernel32.lib
user32.lib
gdi32.lib
winspool.lib
comdlg32.lib
advapi32.lib
shell32.lib
ole32.lib
oleaut32.lib
uuid.lib
odbc32.lib
odbccp32.lib

這裡寫圖片描述

三、海康攝像頭碼流轉碼並同通過OpenCV顯示:

1.程式碼:

(1)新建一個頭檔案HK_camera.h:定義了一個相機類

#ifndef _HK_CAMERA_H_ 
#define _HK_CAMERA_H_

#include<HCNetSDK.h>
#include<plaympeg4.h>
#include<PlayM4.h>    //此標頭檔案需要按照下面第二步除錯Bug中的方法去新增
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace cv;
using namespace std;

class HK_camera
{
public:
    HK_camera(void);
    ~HK_camera(void);

public:
    bool Init();                  //初始化
    bool Login(char* sDeviceAddress, char* sUserName, char* sPassword, WORD wPort);            //登陸
    //bool Login(const char* sDeviceAddress,const char* sUserName,const char* sPassword, WORD wPort);            //登陸(VS2017版本)
    void show();                  //顯示影象

private:
    LONG lUserID;
};
#endif;

(2)新建一個HK_camera.cpp

//#include "stdafx.h" //VS2017中需要新增此預編譯標頭檔案
#include"HK_camera.h"
#include <iostream>

//全域性變數
LONG g_nPort;
Mat g_BGRImage;

//資料解碼回撥函式,
//功能:將YV_12格式的視訊資料流轉碼為可供opencv處理的BGR型別的圖片資料,並實時顯示。
void CALLBACK DecCBFun(long nPort, char* pBuf, long nSize, FRAME_INFO* pFrameInfo, long nUser, long nReserved2)
{
    if (pFrameInfo->nType == T_YV12)
    {
        std::cout << "the frame infomation is T_YV12" << std::endl;
        if (g_BGRImage.empty())
        {
            g_BGRImage.create(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC3);
        }
        Mat YUVImage(pFrameInfo->nHeight + pFrameInfo->nHeight / 2, pFrameInfo->nWidth, CV_8UC1, (unsigned char*)pBuf);

        cvtColor(YUVImage, g_BGRImage, COLOR_YUV2BGR_YV12);
        imshow("RGBImage1", g_BGRImage);
        waitKey(15);

        YUVImage.~Mat();
    }
}

//實時視訊碼流資料獲取 回撥函式
void CALLBACK g_RealDataCallBack_V30(LONG lPlayHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void* pUser)
{
    if (dwDataType == NET_DVR_STREAMDATA)//碼流資料
    {
        if (dwBufSize > 0 && g_nPort != -1)
        {
            if (!PlayM4_InputData(g_nPort, pBuffer, dwBufSize))
            {
                std::cout << "fail input data" << std::endl;
            }
            else
            {
                std::cout << "success input data" << std::endl;
            }

        }
    }
}
//建構函式
HK_camera::HK_camera(void)
{

}
//解構函式
HK_camera::~HK_camera(void)
{
}
//初始化函式,用作初始化狀態檢測
bool HK_camera::Init()
{
    if (NET_DVR_Init())
    {
        return true;
    }
    else
    {
        return false;
    }
}

//登入函式,用作攝像頭id以及密碼輸入登入
bool HK_camera::Login(char* sDeviceAddress, char* sUserName, char* sPassword, WORD wPort)
//bool HK_camera::Login(const char* sDeviceAddress,const char* sUserName,const char* sPassword, WORD wPort);        //登陸(VS2017版本)
{
    NET_DVR_USER_LOGIN_INFO pLoginInfo = { 0 };
    NET_DVR_DEVICEINFO_V40 lpDeviceInfo = { 0 };

    pLoginInfo.bUseAsynLogin = 0;     //同步登入方式
    strcpy_s(pLoginInfo.sDeviceAddress, sDeviceAddress);
    strcpy_s(pLoginInfo.sUserName, sUserName);
    strcpy_s(pLoginInfo.sPassword, sPassword);
    pLoginInfo.wPort = wPort;

    lUserID = NET_DVR_Login_V40(&pLoginInfo, &lpDeviceInfo);

    if (lUserID < 0)
    {
        return false;
    }
    else
    {
        return true;
    }
}

//視訊流顯示函式
void HK_camera::show()
{
    if (PlayM4_GetPort(&g_nPort))            //獲取播放庫通道號
    {
        if (PlayM4_SetStreamOpenMode(g_nPort, STREAME_REALTIME))      //設定流模式
        {
            if (PlayM4_OpenStream(g_nPort, NULL, 0, 1024 * 1024))         //開啟流
            {
                if (PlayM4_SetDecCallBackExMend(g_nPort, DecCBFun, NULL, 0, NULL))
                {
                    if (PlayM4_Play(g_nPort, NULL))
                    {
                        std::cout << "success to set play mode" << std::endl;
                    }
                    else
                    {
                        std::cout << "fail to set play mode" << std::endl;
                    }
                }
                else
                {
                    std::cout << "fail to set dec callback " << std::endl;
                }
            }
            else
            {
                std::cout << "fail to open stream" << std::endl;
            }
        }
        else
        {
            std::cout << "fail to set stream open mode" << std::endl;
        }
    }
    else
    {
        std::cout << "fail to get port" << std::endl;
    }
    //啟動預覽並設定回撥資料流
    NET_DVR_PREVIEWINFO struPlayInfo = { 0 };
    struPlayInfo.hPlayWnd = NULL; //視窗為空,裝置SDK不解碼只取流
    struPlayInfo.lChannel = 1; //Channel number 裝置通道
    struPlayInfo.dwStreamType = 0;// 碼流型別,0-主碼流,1-子碼流,2-碼流3,3-碼流4, 4-碼流5,5-碼流6,7-碼流7,8-碼流8,9-碼流9,10-碼流10
    struPlayInfo.dwLinkMode = 0;// 0:TCP方式,1:UDP方式,2:多播方式,3 - RTP方式,4-RTP/RTSP,5-RSTP/HTTP 
    struPlayInfo.bBlocked = 1; //0-非阻塞取流, 1-阻塞取流, 如果阻塞SDK內部connect失敗將會有5s的超時才能夠返回,不適合於輪詢取流操作.

    if (NET_DVR_RealPlay_V40(lUserID, &struPlayInfo, g_RealDataCallBack_V30, NULL))
    {
        namedWindow("RGBImage2");
    }
}

(3)新建一個main.cpp

//#include "stdafx.h" //VS2017中需要新增此預編譯標頭檔案
#include"HK_camera.h"
#include <iostream>
#include <Windows.h>

using namespace std;

int main()
{
    HK_camera camera;
    if (camera.Init())
    {
        cout << "init success" << endl;
        if (camera.Login("192.168.1.64", "admin", "sjtu2322", 8000))//使用者名稱以及密碼,根據此係列部落格一中的方法檢視或設定
        {
            cout << "login successfully" << endl;
            camera.show();
        }
        else
        {
            cout << "login fail" << endl;
        }
    }
    else
    {
        cout << "init fail" << endl;
    }

    while (1)
    {

    }
    return 0;
}

2.Bug除錯

  1. 提示bug:E1696無法開啟原始檔 "PlayM4.h",解決辦法:到\CH-HCNetSDK(Windows64)V5.3.1.22_build20170909\Demo示例\2- MFC分功能示例\2- 實時流回調解碼獲取YUV\資料夾下找到PlayM4.h檔案,新增到\海康威視_demo\3rd_x64\HC_vision_SDK_x64\include 資料夾下
    這裡寫圖片描述

  2. 因為我此處使用的是VS2017,會報錯 C2664 無法將引數 1 從“const char [13]”轉換為“char *”,參照部落格 無法將引數1從“const char [6]”轉換為“char *”的解決方法中所說,將上述程式碼中的報錯的幾處改動一下即可(在上述程式碼中都有註釋)。主要是

(1)將HK_camera.h中函式bool Login(char* sDeviceAddress, char* sUserName, char* sPassword, WORD wPort);改為函式bool Login(const char* sDeviceAddress,const char* sUserName,const char* sPassword, WORD wPort);

(2)將 HK_camera.cpp中函式bool HK_camera::Login(char* sDeviceAddress, char* sUserName, char* sPassword, WORD wPort) 改為函式bool HK_camera::Login(const char* sDeviceAddress,const char* sUserName,const char* sPassword, WORD wPort);

並且因為VS版本問題,需要在所有.cpp檔案的頭部新增預編譯頭#include "stdafx.h" ,這個已經在上面程式碼中註明,如果是VS2015或其他版本,則無此問題。

3.程式執行效果:

這裡寫圖片描述

四、小結:

本篇部落格中我們介紹了用海康威視SDK和OpeCV庫將海康威視攝像頭封裝為一個攝像機類,並且在此基礎上在主函式中建立了這個類的例項並呼叫它的函式顯示影象。接下來下一篇部落格我們將在此基礎上封裝人臉檢測的演算法,完成一個基於海康威視攝像頭的人臉檢測的小測試工程的建立。