Qt+OpenCV calls Hikvision camera SDK to collect images (C++)

Configuration Environment:

  Qt5.12.5

  OpenCV3.4.9

  Hikvision MVS3.1.0

Development tools: QT Creator-4.11.0

1. Development steps:

1) Create a QT project and add the camera reference file in the pro file

1.1) Add Hikvision’s library:

Copy the Hikvision SDK libraries MVS\Development\Includes and MVS\Development\Libraries\win64 to your own project directory.

Then add the library to the .pro file

After clicking Next, the following code will appear in the .pro file

Then add the following code after this to add dependencies

1 INCLUDEPATH += $$PWD/includes/
2 INCLUDEPATH += $$PWD/includes/GenICam/
3 
4 DEPENDPATH += $$PWD/includes/
5 DEPENDPATH += $$PWD/includes/GenICam/

1.2) Configure OpenCV

The same as the above steps to configure HKSDK, the library file directory is the OpenCV installation directory D:/OpenCV/opencv/build/x64/vc14/lib/opencv_world349d.lib

The configuration will be completed. The following code appears in the pro file

You need to add the following code behind

 INCLUDEPATH += D:\OpenCV\opencv\build\include \
                 D:\OpenCV\opencv\build\include\opencv \
                 D:\OpenCV\opencv\build\include\opencv2
 DEPENDPATH += D:\OpenCV\opencv\build\include \
                 D:\OpenCV\opencv\build\include\opencv \
                 D:\OpenCV\opencv\build\include\opencv2

In this way, the Hikvision SDK and OpenCV libraries are configured, and their header files can be introduced into the project.

2. Development steps:

Create a new class: mycanera.h and mycaner.cpp to generate these two files (ps: I typed the wrong camera when creating the file, ^_^)

Mycanera.h file refers to the code:

#ifndef MYCANERA_H
#define MYCANERA_H
#include "MvCameraControl.h"
#pragma execution_character_set("utf-8")   //设置当前文件为UTF-8编码
#pragma warning( disable : 4819 )    //解决SDK中包含中文问题;忽略C4819错误
#include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <string>
#include <QDebug>

using namespace std;
using namespace cv;
class MyCanera
{
public:
    MyCanera();
   ~MyCanera();
    //声明相关变量及函数等
    //枚举相机设备列表
  static int EnumDevices(MV_CC_DEVICE_INFO_LIST* pstDevList);

  // ch:连接相机
  int connectCamera(string id);

  //设置相机触发模式
  int setTriggerMode(unsigned int TriggerModeNum);

  //开启相机采集
  int startCamera();

  //发送软触发
  int softTrigger();

  //读取buffer
  int ReadBuffer(Mat &image);

  //设置心跳时间
  int setHeartBeatTime(unsigned int time);

  //设置曝光时间
  int setExposureTime(float ExposureTimeNum);
//关闭相机
  int closeCamera();
private: void* m_hDevHandle; public: unsigned char* m_pBufForSaveImage; // 用于保存图像的缓存 unsigned int m_nBufSizeForSaveImage; unsigned char* m_pBufForDriver; // 用于从驱动获取图像的缓存 unsigned int m_nBufSizeForDriver; MV_CC_DEVICE_INFO_LIST m_stDevList; // ch:设备信息列表结构体变量,用来存储设备列表 MV_CC_DEVICE_INFO *m_Device = NULL; //设备对象 }; #endif // MYCANERA_H

Mycanera.cpp file refers to the code:

#include "mycanera.h"
#include <QDebug>
MyCanera::MyCanera()
{
    m_hDevHandle    = NULL;
}

MyCanera::~MyCanera()
{
    if (m_hDevHandle)
    {
        MV_CC_DestroyHandle(m_hDevHandle);
        m_hDevHandle    = NULL;
    }
}

//查询设备列表
int MyCanera::EnumDevices(MV_CC_DEVICE_INFO_LIST* pstDevList)
{
    int temp= MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, pstDevList);
    if (MV_OK != temp)
    {
        return -1;
    }
    return 0;
}

//连接相机
//id:自定义相机名称
int  MyCanera::connectCamera(string id)
{
    int temp= EnumDevices(&m_stDevList);
    if(temp!=0)
        //设备更新成功接收命令的返回值为0,返回值不为0则为异常
        return -1;
    if(m_stDevList.nDeviceNum==0)
        //未找到任何相机
        return 2;
    for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++)
    {
        MV_CC_DEVICE_INFO* pDeviceInfo = m_stDevList.pDeviceInfo[i];
        if (NULL == pDeviceInfo)
        {
            continue;
        }
        //qDebug() << (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chUserDefinedName;//自定义相机名称
        //qDebug() << (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chSerialNumber;//相机序列号
        if(id == (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chUserDefinedName||id == (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chSerialNumber)
        {
            m_Device= m_stDevList.pDeviceInfo[i];
            break;
        }else
        {
            continue;
        }
    }
    if(m_Device==NULL)
    {
        //未找到指定名称的相机
        qDebug() << "未找到指定名称的相机";
        return 3;
    }
    temp  = MV_CC_CreateHandle(&m_hDevHandle, m_Device);//创建句柄
    if(temp  !=0)
        return -1;

    temp  = MV_CC_OpenDevice(m_hDevHandle);//打开设备
    if (temp  !=0)
    {
        MV_CC_DestroyHandle(m_hDevHandle);
        m_hDevHandle = NULL;
        return -1;
    }else
    {
        setTriggerMode(1);//设置触发模式:1-打开触发模式 0-关闭触发模式
        return 0;
    }
    if (m_Device->nTLayerType == MV_GIGE_DEVICE)//设备类型为网络接口
    {
       //std::cout<<"Gige Camera"<<std::endl;
    }
}
//设置相机是否开启触发模式
int MyCanera::setTriggerMode(unsigned int TriggerModeNum)
{
    int nRet = MV_CC_SetTriggerMode(m_hDevHandle,TriggerModeNum);
    if (MV_OK != nRet)
    {
        return -1;
    }

}
//启动相机采集
int MyCanera::startCamera()
{
    int temp=MV_CC_StartGrabbing(m_hDevHandle);
    if(temp!=0)
    {
        qDebug() << "抓图失败";
        return -1;
    }else
    {
        qDebug() << "抓图成功";
        return 0;
    }
}
//发送软触发
int MyCanera::softTrigger()
{
    int enumValue = MV_CC_SetEnumValue(m_hDevHandle,"TriggerSource",MV_TRIGGER_SOURCE_SOFTWARE);
    if(enumValue != 0){
        qDebug() << "设置软触发失败";
        return -1;
    }else {
        qDebug() << "设置软触发";
    }
    int comdValue= MV_CC_SetCommandValue(m_hDevHandle, "TriggerSoftware");
    if(comdValue!=0)
    {
        qDebug() << "软触发失败";
        return -1;
    }else
    {
        qDebug() << "软触发一次";
        return 0;
    }
}
//读取相机中的图像
int MyCanera::ReadBuffer(Mat &image)
{
    unsigned int nBufSize = 0;//缓存大小
    MVCC_INTVALUE stIntvalue; //获取一帧数据的大小
    memset(&stIntvalue, 0, sizeof(MVCC_INTVALUE));
    int tempValue = MV_CC_GetIntValue(m_hDevHandle, "PayloadSize", &stIntvalue);
    if (tempValue != 0)
    {
        qDebug() << "GetIntValue失败";
        return -1;
    }else{qDebug() << "GetIntValue成功";}
    nBufSize = stIntvalue.nCurValue;
    m_pBufForDriver = (unsigned char *)malloc(nBufSize);
    MV_FRAME_OUT_INFO_EX stImageInfo;
    memset(&stImageInfo,0,sizeof(MV_FRAME_OUT_INFO));
    qDebug() << MV_CC_StartGrabbing(m_hDevHandle);
    int timeout= MV_CC_GetOneFrameTimeout(m_hDevHandle, m_pBufForDriver, nBufSize, &stImageInfo, 1000);
    if(timeout!=0)
    {
        qDebug() << "GetOneFrameTimeout失败";
        return -1;
    }
    m_nBufSizeForSaveImage = stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
    m_pBufForSaveImage = (unsigned char*)malloc(m_nBufSizeForSaveImage); //向系统申请M_nBufSizeForSaveImage内存空间

    bool isMono;//判断是否为黑白图像
    switch (stImageInfo.enPixelType) //像素格式
    {
    case PixelType_Gvsp_Mono8:
    case PixelType_Gvsp_Mono10:
    case PixelType_Gvsp_Mono10_Packed:
    case PixelType_Gvsp_Mono12:
    case PixelType_Gvsp_Mono12_Packed:
        isMono=true;
        break;
    default:
        isMono=false;
        break;
    }

    if(isMono)
    {
        image=Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC1,m_pBufForDriver);
    }
    else
    {
        //转换图像格式为BGR8
        MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {0};
        memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));
        stConvertParam.nWidth = stImageInfo.nWidth;                 //ch:图像宽 | en:image width
        stConvertParam.nHeight = stImageInfo.nHeight;               //ch:图像高 | en:image height
        stConvertParam.pSrcData = m_pBufForDriver;                  //ch:输入数据缓存 | en:input data buffer
        stConvertParam.nSrcDataLen = stImageInfo.nFrameLen;         //ch:输入数据大小 | en:input data size
        stConvertParam.enSrcPixelType = stImageInfo.enPixelType;    //ch:输入像素格式 | en:input pixel format
        //stConvertParam.enDstPixelType = PixelType_Gvsp_BGR8_Packed; //ch:输出像素格式 | en:output pixel format  适用于OPENCV的图像格式
        stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed; //ch:输出像素格式 | en:output pixel format
        stConvertParam.pDstBuffer = m_pBufForSaveImage;                    //ch:输出数据缓存 | en:output data buffer
        stConvertParam.nDstBufferSize = m_nBufSizeForSaveImage;            //ch:输出缓存大小 | en:output buffer size
        MV_CC_ConvertPixelType(m_hDevHandle, &stConvertParam);
        image=Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC3,m_pBufForSaveImage);
    }
    return 0;
}
//设置心跳时间
int MyCanera::setHeartBeatTime(unsigned int time)
{
    //心跳时间最小为500ms
    if(time<500)
        time=500;
    int temp=MV_CC_SetIntValue(m_hDevHandle, "GevHeartbeatTimeout", time);
    if(temp!=0)
    {
        return -1;
    }
    else
    {
        return 0;
    }
}
//设置曝光时间
int MyCanera::setExposureTime(float ExposureTimeNum)
{
    int temp= MV_CC_SetFloatValue(m_hDevHandle, "ExposureTime",ExposureTimeNum );
    if(temp!=0)
        return -1;
    return 0;
}
//关闭相机
int MyCanera::closeCamera()
{
    int nRet = MV_OK;
    if (NULL == m_hDevHandle)
    {
        qDebug() << "没有句柄,不用关闭";
        return -1;
    }
    MV_CC_CloseDevice(m_hDevHandle);
    nRet = MV_CC_DestroyHandle(m_hDevHandle);
    m_hDevHandle = NULL;
    return nRet;
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "mycanera.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    MyCanera *m_pcMycamera;
    MV_CC_DEVICE_INFO_LIST m_stDevList;//设备列表
    string cameraName; //相机名称
    Mat imageMat; //使用OpenCV接受采集图像
    QImage cvMat2QImage(const cv::Mat& mat);
    QImage image;


private slots:
    void on_pushButton_link_clicked();

    void on_pushButton_close_clicked();

    void on_pushButton_caiji_clicked();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

minwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mycanera.h"
#include <QDebug>
#include <QImage>
#include <QImageReader>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    m_pcMycamera = new MyCanera;
    int neRt = m_pcMycamera->EnumDevices(&m_stDevList);
    qDebug() << neRt;
    qDebug() << m_stDevList.pDeviceInfo[0]->nTLayerType;
    //获取相机的IP地址
    if(1 == m_stDevList.pDeviceInfo[0]->nTLayerType){
        int nIp1,nIp2,nIp3,nIp4;
        nIp1 = ((m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);
        nIp2 = ((m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);
        nIp3 = ((m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);
        nIp4 = (m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);
        QString nIp = QString("%1.%2.%3.%4").arg(nIp1).arg(nIp2).arg(nIp3).arg(nIp4);
        qDebug() << nIp;
    }    
}

MainWindow::~MainWindow()
{
    delete ui;
}

//连接相机
void MainWindow::on_pushButton_link_clicked()
{
    cameraName = (char *)m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.chUserDefinedName;
    qDebug() << QString::fromStdString(cameraName);
    int linkCamera = m_pcMycamera->connectCamera(cameraName);
    qDebug() << linkCamera;
    if(linkCamera == 0){
        qDebug() << "连接相机成功";
    }else {
        qDebug() << "连接相机失败";
    }

    //开启抓图
    int satrtCamera = m_pcMycamera->startCamera();
    if(satrtCamera != 0){
        qDebug() << "启动相机采集失败";
    }else {
        qDebug() << "正在启动相机采集信息";
    }

}

//关闭设备
void MainWindow::on_pushButton_close_clicked()
{
    //关闭设备,释放资源
    int close = m_pcMycamera->closeCamera();
    if(close != 0){
        qDebug() << "相机关闭失败";
    }
}
//采集单张图像按钮
void MainWindow::on_pushButton_caiji_clicked()
{
    //设置相机软触发
    int softTrigger = m_pcMycamera->softTrigger();//发送软触发
    if(softTrigger != 0){
        qDebug() << "失败";
    }else {
        qDebug() << "成功触发一次";
    }

    //读取相机中的图像
    int readInt = m_pcMycamera->ReadBuffer(imageMat);
    if(readInt != 0){
        qDebug() << "读取图像失败";
    }
    image = cvMat2QImage(imageMat);
    ui->label_image->setPixmap(QPixmap::fromImage(image));

}

//Mat转QImage函数
QImage MainWindow::cvMat2QImage(const cv::Mat& mat)
{
    // 8-bits unsigned, NO. OF CHANNELS = 1
    if(mat.type() == CV_8UC1)
    {
        QImage qimage(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)
        qimage.setColorCount(256);
        for(int i = 0; i < 256; i++)
        {
            qimage.setColor(i, qRgb(i, i, i));
        }
        // Copy input Mat
        uchar *pSrc = mat.data;
        for(int row = 0; row < mat.rows; row ++)
        {
            uchar *pDest = qimage.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return qimage;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3
    else if(mat.type() == CV_8UC3)
    {
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if(mat.type() == CV_8UC4)
    {
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
        return QImage();
    }
}

Running results: (ps: stopping collection is useless)

Guess you like

Origin blog.csdn.net/QtCompany/article/details/130691610