大华相机SDK调用——主动采图、外触发、参数

目录

  • 前言
  • 正文
    • 编程环境
    • 获取相机的一些基本信息
    • 主动抓图
    • 触发抓图
    • 参数的获取
  • 参考

前言

由于工作的需要,又完成了一款相机的SDK的调用。通过这一款相机的调用,还是学习到了很多调用一款相机的SDK在细节上的一些东西。本篇文章基本只会讲关于调用过程中的一些重难点。其他,通过SDK的Demo就基本能够完成。但整体的流程,我还是会按照我标题写的那样逐步写下来的。希望能帮你少走一些弯路。

正文

编程环境

我的工作环境是:Win10+Qt5.15+MSVC VS2019
大华的SDK使用的是:Ver2.3.1。基本上大华的SDK就都在这里面了。注意,我使用的这款SDK是没有C++的接口的,只有C#和C。并且还有一个很多的缺陷,这个版本没有一个可以获取所有参数的统一的接口。据说Vver2.2.5这款是有C++的接口的。我也没详细去看,仅供参考,有需要还是要自己下载下来,看一下对应版本的SDK的区别。再决定开发的版本。

获取相机的一些基本信息

一开始,我们要先获取一下该相机的基本信息,这基本是所有操作SDK最开始的操作:
我选取核心的这个函数展示一下:

bool MDeviceDahuaG3UCInfo::SearchDeviceInfos(QStringList &lInfo)
{
    int ret = IMV_OK;
#ifdef WIN_DAHUA_G3U
    IMV_DeviceInfo* pDevInfo = NULL;
    // 发现设备
    // discover camera
    IMV_DeviceList deviceInfoList;
    ret = IMV_EnumDevices(&deviceInfoList, interfaceTypeAll);
    if (IMV_OK != ret)
    {
        qDebug()<<"Enum Device fail"<<ret;
        return false;
    }
    if (deviceInfoList.nDevNum < 1)
    {
        qDebug()<<"--> no camera";
        return false;
    }
    for (uint32_t i = 0; i < deviceInfoList.nDevNum; i++)
    {
        pDevInfo = &deviceInfoList.pDevInfo[i];

        QString ModelName = pDevInfo->modelName;
        QString CameraVendor = pDevInfo->vendorName;
        QString DeviceVersion = pDevInfo->deviceVersion;
        QString manufacetureInfo = pDevInfo->manufactureInfo;
        QString DeviceSN = pDevInfo->serialNumber;
        QString DeviceKey = pDevInfo->cameraKey;
        QString DeviceUserID = pDevInfo->cameraName;
        bool bUsed = isDeviceOpen(DeviceKey);
        QString devInfo;
        devInfo += QString("%1:%2;").arg(XML_TLAYER_TYPE)      //传输协议
                .arg(XML_TLAYER_GEV);
        devInfo += QString("%1:%2;").arg(XML_DRIVER_TYPE)      //驱动类型
                .arg(m_cCameraType);
        devInfo += QString("%1:%2;").arg(XML_DEVICE_MODEL_NAME)//设备型号
                .arg(ModelName);
        devInfo += QString("%1:%2;").arg(XML_DEVICE_USER_DEFINE)//自定义名称
                .arg(DeviceUserID);
        devInfo += QString("%1:%2;").arg(XML_DEVICE_ID)         //序列号
                .arg(DeviceSN);
        devInfo += QString("%1:%2;").arg(XML_DEVICE_ID)         //序列号
                .arg(DeviceSN);
        devInfo += QString("%1:%2;").arg(XML_DEVICE_VENDOR)     //生产厂家
                .arg(CameraVendor);
        devInfo += QString("%1:%2;").arg(XML_DEVICE_VERSION)    //设备版本
                .arg(DeviceVersion);
        devInfo += QString("%1:%2;").arg(XML_DEVICE_STATUS)     //设备状态
                                            .arg(bUsed);
        qDebug()<<"=>GetDeviceDaHuaG3U:"<<devInfo;
        lInfo << devInfo;
        ret = true;
    }
#endif
    return ret;
}

里面大部分内容应该都是很简单的。里面有一个isDeviceOpen这个函数可以暂时先不用管它,等后面,我会重点讲一下这部分的内容。
这里基本上就是发现设备,调用第几个设备的接口。从而获取对应设备的信息。

主动抓图

主动抓图的话,也是比较简单地,核心就是弄个线程不断的调用下面这个函数就可以了。你们可以做个参考,如果语言是Qt的。关于这部分还是建议去看大华SDK本身的demo.qt的写的也不错。

qint32 MDeviceDahuaG3UC::CaptureImageEx(QImage *img, MFrameInfo *info)
{
    qint32 ret = RETURN_FAIL;
    try {
        if(m_bLoaded&&m_cTriggerMode=="Off")
        {
            IMV_Frame frame;
            unsigned char* pRGBbuffer = NULL;
            ret = IMV_GetFrame(m_devHandle, &frame, 1000);
            if (IMV_OK != ret)
            {
                return ret;
            }

            m_iHeight = (qint32)frame.frameInfo.height;
            m_iWidth = (qint32)frame.frameInfo.width;
            QImage::Format format = QImage::Format_Indexed8;
            if(m_cPixelFormat.compare("Mono8")!=0)
                format = QImage::Format_RGB888;
            if((img->width() !=m_iWidth) ||
                    (img->height() !=m_iHeight) ||
                    (img->format() !=format) )
            {
                qDebug()<<"--> DahuaG3V:CaptureImageEx reset image memory! ";
                *img = QImage(m_iWidth,m_iHeight,format);

                if(format == QImage::Format_Indexed8)
                    img->setColorTable(m_vColorTabel);
            }
            if(m_cPixelFormat.compare("Mono8")!=0)//注意点1
            {
                int nRgbBufferSize = 0;
                nRgbBufferSize = frame.frameInfo.width *frame.frameInfo.height*3;
                pRGBbuffer = (unsigned char*)malloc(nRgbBufferSize);
                if (pRGBbuffer == NULL)
                {
                    // 释放内存
                    // release memory
                    free(frame.pData);
                    printf("RGBbuffer malloc failed.\n");
                }
                IMV_PixelConvertParam stPixelConvertParam;
                stPixelConvertParam.nWidth = frame.frameInfo.width;
                stPixelConvertParam.nHeight = frame.frameInfo.height;
                stPixelConvertParam.ePixelFormat = frame.frameInfo.pixelFormat;
                stPixelConvertParam.pSrcData = frame.pData;
                stPixelConvertParam.nSrcDataLen = frame.frameInfo.size;
                stPixelConvertParam.nPaddingX = frame.frameInfo.paddingX;
                stPixelConvertParam.nPaddingY = frame.frameInfo.paddingY;
                stPixelConvertParam.eBayerDemosaic = demosaicNearestNeighbor;
                stPixelConvertParam.eDstPixelFormat = gvspPixelRGB8;
                stPixelConvertParam.pDstBuf = pRGBbuffer;
                stPixelConvertParam.nDstBufSize = nRgbBufferSize;
                int ret = IMV_PixelConvert(m_devHandle, &stPixelConvertParam);
                if (IMV_OK != ret)
                {
                    // 释放内存
                    // release memory
                    qDebug()<<"image convert to RGB failed! ErrorCode"<<ret;
                    if(pRGBbuffer&&frame.pData)//注意点2
                    {
                        free(frame.pData);
                        free(pRGBbuffer);
                    }

                    return false;
                }
            }

            void *pbit = nullptr;
            int size =0;
            if(m_cPixelFormat.compare("Mono8")!=0)
            {
                pbit = pRGBbuffer;
                size = qMin((int)frame.frameInfo.size*3,img->byteCount());//注意点3
            }
            else
            {
                pbit = frame.pData;
                size = qMin((int)frame.frameInfo.size,img->byteCount());//这个操作是为了防止复制操作会导致数据溢出
            }
            if(size)
                memcpy(img->bits(),pbit,size);
            info->nWidth  = (qint32)frame.frameInfo.width;
            info->nHeight = (qint32)frame.frameInfo.height;
            info->nFramerLen = (qint32)frame.frameInfo.size;

            quint64 nformat = (qint32)frame.frameInfo.pixelFormat;
            //info->cFormat = nformat;
            info->cFormat = "RGB888";
            info->fFrameRate = m_fFrameRate;
            if(m_cPixelFormat.compare("Mono8")!=0&&pRGBbuffer!=nullptr)//注意点4
            {
                free(pRGBbuffer);
            }
            ret = IMV_ReleaseFrame(m_devHandle, &frame);//注意点5
            if (IMV_OK != ret)
            {
                printf("Release frame failed! ErrorCode[%d]\n", ret);
            }

            ret = RETURN_OK;
        }
    } catch (...) {
        qDebug()<<"MDeviceDahuaG3UC::CaptureImageEx has some nullPtr";
        return false;
    }

    return ret;
}

有几个需要注意的点,我这里提一下,对应的注意点在程序中都已经标出,可以对应着过去那边看一看:
注意点1:首先,我在这个程序里面,不管当前相机采集出的格式是什么(除了Mon8),我都会调用它的转换函数,转换成RGB888.这也是其demo提供出的方法。
注意点2:这里最好做一个判断,再去释放,万一分配不成功,你还强行去释放,程序容易崩溃。
注意点3:拷贝数据的时候,注意,这里要拷贝3倍的mono8格式数据的大小。
注意点4:转换完后,要及时把申请的内存给释放了。不然,你程序很快就会变缓慢,然后卡顿崩溃。因为内存都会分配完了。
注意点5:注意,结束的时候,要调用IMV_ReleaseFrame的这个帧。

触发抓图

关于这部分,还是建议去看其SDK的demo,因为我这边会写的比较割裂,也就是步骤都是比较分开的,不太适宜观看,但为了文章结构的完整性,还是贴上来,进行讲解。
1、首先,要先注册一下回调函数,这是触发前的准备工作:
code

qint32  MDeviceDahuaG3UC::GrabThreadStart()
{
    qint32 ret = RETURN_FAIL;
    if(m_bLoaded)
    {
        try {

            IMV_ClearFrameBuffer(m_devHandle);//注意点1
            ret = IMV_AttachGrabbing(m_devHandle, (IMV_FrameCallBack)onGetFrame, this);//注意点2
            if (IMV_OK != ret)
            {
                printf("Attach grabbing failed! ErrorCode[%d]\n", ret);
            }
            else
            {
                ret = RETURN_OK;
            }

        }
        catch (...) {
            qDebug()<<"MDeviceDahuaG3UC::GrabThreadStart has nullptr";
        }
    }
    return ret;
}

注意点

  1. 注意点1:注意,最好在开始注册之前,清空一下相机的帧缓存,不然,有可能会出现开始注册的时候,由于相机有图片,自动调用了注册函数了。
  2. 注意点2:ret = IMV_AttachGrabbing(m_devHandle, (IMV_FrameCallBack)onGetFrame, this);//注意点2
    这个就是注册函数了,注意,中间的回调函数要进行强制类型转换。

2、这个函数就是回调函数,首先,这个函数要是静态函数,将,传入的对象进行强制类型转换。
code

static void onGetFrame(IMV_Frame* pFrame, const void* pUser)
{
    const MDeviceDahuaG3UC* pDev=static_cast<const MDeviceDahuaG3UC*>(pUser);
    if(pDev)
    {
        pDev->triggerEvent(pFrame);
    }

}

3、 接下来是调用的传帧的函数
code

void   MDeviceDahuaG3UC::triggerEvent(IMV_Frame* pFrame)const
{
#ifdef WIN_DAHUA_G3U
    int ret = IMV_OK;
    if(m_bStopWork)
    {
        qDebug()<<"triggerEvent m_bStopWork is true";
        return;
    }
    if(m_fGrabCallbackEx)
    {
        MFrameInfo info;

        unsigned char* pRGBbuffer = NULL;
        if(m_cPixelFormat.compare("Mono8")!=0)//注意点1
        {
            int nRgbBufferSize = 0;
            nRgbBufferSize = pFrame->frameInfo.width *pFrame->frameInfo.height * 3;//注意点2
            pRGBbuffer = (unsigned char*)malloc(nRgbBufferSize);
            if (pRGBbuffer == NULL)
            {
                // 释放内存
                // release memory
                free(pFrame->pData);
                printf("RGBbuffer malloc failed.\n");
            }
            IMV_PixelConvertParam stPixelConvertParam;
            stPixelConvertParam.nWidth = pFrame->frameInfo.width;
            stPixelConvertParam.nHeight = pFrame->frameInfo.height;
            stPixelConvertParam.ePixelFormat = pFrame->frameInfo.pixelFormat;
            stPixelConvertParam.pSrcData = pFrame->pData;
            stPixelConvertParam.nSrcDataLen = pFrame->frameInfo.size;
            stPixelConvertParam.nPaddingX = pFrame->frameInfo.paddingX;
            stPixelConvertParam.nPaddingY = pFrame->frameInfo.paddingY;
            stPixelConvertParam.eBayerDemosaic = demosaicNearestNeighbor;
            stPixelConvertParam.eDstPixelFormat = gvspPixelRGB8;
            stPixelConvertParam.pDstBuf = pRGBbuffer;
            stPixelConvertParam.nDstBufSize = nRgbBufferSize;
            ret = IMV_PixelConvert(m_devHandle, &stPixelConvertParam);
            if (IMV_OK != ret)
            {
                // 释放内存
                // release memory
                qDebug()<<"image convert to RGB failed! ErrorCode\n";

                free(pFrame->pData);
                free(pRGBbuffer);
                return ;
            }
        }

        uchar *pbit = nullptr;
        if(m_cPixelFormat.compare("Mono8")!=0)
        {
            pbit = pRGBbuffer;
            info.nFramerLen = pFrame->frameInfo.size*3;//注意点3
            info.cFormat = "RGB888";
        }
        else
        {
            pbit = pFrame->pData;
            info.nFramerLen = pFrame->frameInfo.size;
            info.cFormat = "Mono8";
        }
        info.nWidth  = pFrame->frameInfo.width;
        info.nHeight = pFrame->frameInfo.height;

        m_fGrabCallbackEx(m_pCallUser,pbit,&info);
        if(m_cPixelFormat.compare("Mono8")!=0&&pRGBbuffer!=NULL)//注意点4
        {
            free(pRGBbuffer);
        }
        ret = IMV_ReleaseFrame(m_devHandle, pFrame);//注意点5
        if (IMV_OK != ret)
        {
            qDebug()<<"Release frame failed!";
        }
    }
#endif
}

注意点
注意点1:注意,非Mono8格式的帧要进行格式转换。
注意点2:开辟的内存空间,要是宽高的三倍。
注意点3:往上传递的帧信息的大小也要是宽
高的3倍。
注意点4:如果是非Mono8的格式的要对申请的缓存进行释放
注意点5:要释放帧。

参数的获取

关于这个SDK的缺点就在于这了,没有一个接口可以获取所有的参数名称,让我能够进行统一获取,然后,批量化显示,所以,我这里只能使用xml文件进行固定的一些参数进行显示。
我这里就直接举例几个获取与设置参数的函数。
曝光的获取:

double MDeviceDahuaG3UC::GetExposureTime()
{
    double ExposureTime = 0;
    int ret = IMV_OK;
#ifdef WIN_DAHUA_G3U
    if(m_devHandle)
    {
        ret = IMV_GetDoubleFeatureValue(m_devHandle,"ExposureTime",&ExposureTime);
        if (IMV_OK != ret)
        {
            qDebug()<<"--> GetExposureTime fail"<<ExposureTime;
        }
        else
        {
            m_fExposureTime = ExposureTime/1000;
        }
    }
#endif
    return m_fExposureTime;
}

曝光的设置

void MDeviceDahuaG3UC::SetExposureTime(double time)
{
    int ret = IMV_OK;
#ifdef WIN_DAHUA_G3U
    if(m_devHandle)
    {
        ret = IMV_SetDoubleFeatureValue(m_devHandle,"ExposureTime",time*1000);
        if (IMV_OK != ret)
        {
            qDebug()<<"--> SetExposureTime fail"<<time;
        }
        else
        {
            m_fExposureTime = time;
        }
    }
#endif
}

参考

你可能感兴趣的:(Work,大华)