(二)Qt多线程实现海康工业相机图像实时采集

news2024/11/17 3:42:14

系列文章目录

提示:这里是该系列文章的所有文章的目录
第一章: (一)Qt+OpenCV调用海康工业相机SDK示例开发
第二章: (二)Qt多线程实现海康工业相机图像实时采集


文章目录

  • 系列文章目录
  • 前言
  • 一、项目结构
  • 二、初始化相机
  • 三、图像保存
  • 四、示例完整代码
  • 五、下载链接
  • 总结


前言

本文主要讲述了使用Qt多线程实现海康工业相机图像的采集,并在界面上将两个相机采集到的图像信息同时显示出来,在本系列文章中的第一篇的基础上,优化了保存图片的功能,这里将示例展示出来,以便大家学习,如有错误之处,欢迎大家批评指正。

项目效果
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、项目结构

下面是我的示例的源代码文件目录,为了让项目结构看起来更整洁,在这里使用了pri子模块的方式,
请添加图片描述
MyCamera2.pro中增加了下列内容

#包含子模块
include (./HikSdk/HikSdk.pri)   #海康SDK

(这是一个小记录:如果将Qt的MinGW项目转为MSVC项目,需要进行字符的设置)

#设置字符
QMAKE_CXXFLAGS += -execution-charset:utf-8
QMAKE_CXXFLAGS += -source-charset:utf-8
QMAKE_CXXFLAGS_WARN_ON += -wd4819

二、初始化相机

我的示例是在构造函数中进行了相机的初始化,完成了相机的打开工作,这样可以避免在开始采集时出现卡顿(相机打开比较耗时,少量相机打开可能体会不到,如果相机数增多,会有很明显的等待时长),另外本示例中使用的两个相机型号是一样的,所以不能通过这个来区分,而是在初始化时进行了相机号的设置,获取相机型号的代码可见第一篇文章中的代码。

//初始化相机
memset(&m_stDevList,0,sizeof(MV_CC_DEVICE_INFO_LIST));
//枚举子网内所有设备
int nRet = CMvCamera::EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE,&m_stDevList);
if(MV_OK != nRet)
{
    return;
}
m_deviceNum = m_stDevList.nDeviceNum;
if(m_deviceNum != 2)
{
    QMessageBox::warning(this,"警告","请检查相机是否正常连接!");
    return;
}
for(int i=0;i<m_deviceNum;i++)
{
    MV_CC_DEVICE_INFO *pDeviceInfo = m_stDevList.pDeviceInfo[i];
    int nRet = m_pcMyCamera[i]->Open(pDeviceInfo);   //打开相机
    if(MV_OK != nRet)
    {
        delete m_pcMyCamera[i];
        m_pcMyCamera[i] = NULL;
        QMessageBox::warning(this,"警告","打开设备失败!");
        return;
    }
    m_pcMyCamera[i]->SetEnumValue("TriggerMode",1);        //设置为触发模式
    m_pcMyCamera[i]->SetEnumValue("TriggerSource",7);      //设置触发源为软触发
    m_pcMyCamera[i]->SetFloatValue("ExposureTime",5000);   //设置曝光时间
    m_cameraThread[i]->setCameraPtr(m_pcMyCamera[i]);
    m_cameraThread[i]->setImagePtr(m_myImage[i]);
    m_cameraThread[i]->setCameraIndex(i);
}

三、图像保存

在第一篇文章中,图像保存使用了qt中的QPixmap方法,但是如果需要实时进行图像的保存,使用这种方法会出现界面卡顿的情况,所以在本文中对保存图像的方式进行了改进,使用的是海康sdk中的保存函数,并且在线程中进行实现,完整代码见后文:

//这里进行了保存图像名的组装,并readBuffer中将保存标志置为true
//format: .bmp .tif .png .jpg
QString saveNameOne = m_cameraOnePath + "Grab_" + curTime + "." + format;
m_pcMyCamera[0]->CommandExecute("TriggerSoftware");
int readFlag = m_pcMyCamera[0]->ReadBuffer(image,true,saveNameOne.toUtf8());

//读取相机中的图像
//将saveFlag置为true,并提供保存图像名,即可实现图像的保存
int CMvCamera::ReadBuffer(cv::Mat &image,bool saveFlag,QByteArray imageName)
{
    unsigned int nRecvBufSize = 0;
    MVCC_INTVALUE stParam;
    memset(&stParam, 0, sizeof(MVCC_INTVALUE));
    int tempValue = MV_CC_GetIntValue(m_hDevHandle, "PayloadSize", &stParam);
    if (tempValue != 0)
    {
        return -1;
    }
    nRecvBufSize = stParam.nCurValue;
    unsigned char* pDate;
    pDate=(unsigned char *)malloc(nRecvBufSize);

    MV_FRAME_OUT_INFO_EX stImageInfo;
    memset(&stImageInfo,0,sizeof(MV_FRAME_OUT_INFO));
    tempValue= MV_CC_GetOneFrameTimeout(m_hDevHandle, pDate, nRecvBufSize, &stImageInfo, 700);
    if(tempValue!=0)
    {
        return -1;
    }
    m_nBufSizeForSaveImage = stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
    unsigned char* m_pBufForSaveImage;
    m_pBufForSaveImage = (unsigned char*)malloc(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;
    }

    cv::Mat getImage;
    if(isMono)
    {
        getImage = cv::Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC1,pDate);
        if(saveFlag)
        {
            MV_SAVE_IMG_TO_FILE_PARAM stSaveFileParam;
            memset(&stSaveFileParam, 0, sizeof(MV_SAVE_IMG_TO_FILE_PARAM));
            stSaveFileParam.enImageType = MV_Image_Bmp; // ch:需要保存的图像类型 | en:Image format to save
            stSaveFileParam.enPixelType = stImageInfo.enPixelType;  // ch:相机对应的像素格式 | en:Camera pixel type
            stSaveFileParam.nWidth      = stImageInfo.nWidth;         // ch:相机对应的宽 | en:Width
            stSaveFileParam.nHeight     = stImageInfo.nHeight;          // ch:相机对应的高 | en:Height
            stSaveFileParam.nDataLen    = stImageInfo.nFrameLen;
            stSaveFileParam.pData       = pDate;
            stSaveFileParam.iMethodValue = 0;

            sprintf_s(stSaveFileParam.pImagePath,256,imageName.data());
            //qDebug()<<"pImagePath:"<<stSaveFileParam.pImagePath;
            int nRet = SaveImageToFile(&stSaveFileParam);
            if(MV_OK != nRet)
            {
                //qDebug()<<"nRet:"<<nRet;
            }
        }
    }

    getImage.copyTo(image);
    getImage.release();
    free(pDate);
    free(m_pBufForSaveImage);
    return 0;
}

四、示例完整代码

1.MyCamera2.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

DEFINES += QT_DEPRECATED_WARNINGS

#设置字符
QMAKE_CXXFLAGS += -execution-charset:utf-8
QMAKE_CXXFLAGS += -source-charset:utf-8
QMAKE_CXXFLAGS_WARN_ON += -wd4819

#包含子模块
include (./HikSdk/HikSdk.pri)   #海康SDK

SOURCES += \
    main.cpp \
    mainwindow.cpp \

HEADERS += \
    mainwindow.h \

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

2.HikSdk.pri

HEADERS += \
    $$PWD/camerathread.h \
    $$PWD/cmvcamera.h

SOURCES += \
    $$PWD/camerathread.cpp \
    $$PWD/cmvcamera.cpp

msvc:
{
    #OpenCV
    LIBS += -L$$PWD/OpenCV/OpenCV_Msvc/lib/ -lopencv_world451d
    INCLUDEPATH += $$PWD/OpenCV/OpenCV_Msvc/Includes
    DEPENDPATH += $$PWD/OpenCV/OpenCV_Msvc/Includes

    #SDK
    LIBS += -L$$PWD/SDK/Lib/ -lMvCameraControl
    INCLUDEPATH += $$PWD/SDK/Includes
    DEPENDPATH += $$PWD/SDK/Includes
}

#mingw:
#{
#    #OpenCV
#    LIBS += -L $$PWD/OpenCV/OpenCV_MinGw/Lib/libopencv_*.a
#    INCLUDEPATH += $$PWD/OpenCV/OpenCV_MinGw/Includes
#
#    #SDK
#    LIBS += -L$$PWD/SDK/Lib/MvCameraControl.lib
#    INCLUDEPATH += $$PWD/SDK/Includes
#    DEPENDPATH += $$PWD/SDK/Includes
#}

3.cmvcamera.h(直接从海康提供的SDK中复制,此处进行了修改)

/************************************************************************/
/* 以C++接口为基础,对常用函数进行二次封装,方便用户使用                */
/************************************************************************/

#ifndef _MV_CAMERA_H_
#define _MV_CAMERA_H_

#include <string.h>
#include "MvCameraControl.h"
#include "opencv2/opencv.hpp"
#include <QDebug>

//会跟系统函数定义冲突
//using namespace cv;

#ifndef MV_NULL
#define MV_NULL    0
#endif

class CMvCamera
{
public:
    CMvCamera();
    ~CMvCamera();

    // ch:获取SDK版本号 | en:Get SDK Version
    static int GetSDKVersion();

    // ch:枚举设备 | en:Enumerate Device
    static int EnumDevices(unsigned int nTLayerType, MV_CC_DEVICE_INFO_LIST* pstDevList);

    // ch:判断设备是否可达 | en:Is the device accessible
    static bool IsDeviceAccessible(MV_CC_DEVICE_INFO* pstDevInfo, unsigned int nAccessMode);

    // ch:打开设备 | en:Open Device
    int Open(MV_CC_DEVICE_INFO* pstDeviceInfo);

    // ch:关闭设备 | en:Close Device
    int Close();

    // ch:判断相机是否处于连接状态 | en:Is The Device Connected
    bool IsDeviceConnected();

    // ch:注册图像数据回调 | en:Register Image Data CallBack
    int RegisterImageCallBack(void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser), void* pUser);

    // ch:开启抓图 | en:Start Grabbing
    int StartGrabbing();

    // ch:停止抓图 | en:Stop Grabbing
    int StopGrabbing();

    // ch:主动获取一帧图像数据 | en:Get one frame initiatively
    int GetImageBuffer(MV_FRAME_OUT* pFrame, int nMsec);

    // ch:释放图像缓存 | en:Free image buffer
    int FreeImageBuffer(MV_FRAME_OUT* pFrame);

    // ch:显示一帧图像 | en:Display one frame image
    int DisplayOneFrame(MV_DISPLAY_FRAME_INFO* pDisplayInfo);

    // ch:设置SDK内部图像缓存节点个数 | en:Set the number of the internal image cache nodes in SDK
    int SetImageNodeNum(unsigned int nNum);

    // ch:获取设备信息 | en:Get device information
    int GetDeviceInfo(MV_CC_DEVICE_INFO* pstDevInfo);

    // ch:获取GEV相机的统计信息 | en:Get detect info of GEV camera
    int GetGevAllMatchInfo(MV_MATCH_INFO_NET_DETECT* pMatchInfoNetDetect);

    // ch:获取U3V相机的统计信息 | en:Get detect info of U3V camera
    int GetU3VAllMatchInfo(MV_MATCH_INFO_USB_DETECT* pMatchInfoUSBDetect);

    // ch:获取和设置Int型参数,如 Width和Height,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
    // en:Get Int type parameters, such as Width and Height, for details please refer to MvCameraNode.xlsx file under SDK installation directory
    int GetIntValue(IN const char* strKey, OUT MVCC_INTVALUE_EX *pIntValue);
    int SetIntValue(IN const char* strKey, IN int64_t nValue);

    // ch:获取和设置Enum型参数,如 PixelFormat,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
    // en:Get Enum type parameters, such as PixelFormat, for details please refer to MvCameraNode.xlsx file under SDK installation directory
    int GetEnumValue(IN const char* strKey, OUT MVCC_ENUMVALUE *pEnumValue);
    int SetEnumValue(IN const char* strKey, IN unsigned int nValue);
    int SetEnumValueByString(IN const char* strKey, IN const char* sValue);
    int GetEnumEntrySymbolic(IN const char* strKey, IN MVCC_ENUMENTRY* pstEnumEntry);

    // ch:获取和设置Float型参数,如 ExposureTime和Gain,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
    // en:Get Float type parameters, such as ExposureTime and Gain, for details please refer to MvCameraNode.xlsx file under SDK installation directory
    int GetFloatValue(IN const char* strKey, OUT MVCC_FLOATVALUE *pFloatValue);
    int SetFloatValue(IN const char* strKey, IN float fValue);

    // ch:获取和设置Bool型参数,如 ReverseX,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
    // en:Get Bool type parameters, such as ReverseX, for details please refer to MvCameraNode.xlsx file under SDK installation directory
    int GetBoolValue(IN const char* strKey, OUT bool *pbValue);
    int SetBoolValue(IN const char* strKey, IN bool bValue);

    // ch:获取和设置String型参数,如 DeviceUserID,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件UserSetSave
    // en:Get String type parameters, such as DeviceUserID, for details please refer to MvCameraNode.xlsx file under SDK installation directory
    int GetStringValue(IN const char* strKey, MVCC_STRINGVALUE *pStringValue);
    int SetStringValue(IN const char* strKey, IN const char * strValue);

    // ch:执行一次Command型命令,如 UserSetSave,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
    // en:Execute Command once, such as UserSetSave, for details please refer to MvCameraNode.xlsx file under SDK installation directory
    int CommandExecute(IN const char* strKey);

    // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
    int GetOptimalPacketSize(unsigned int* pOptimalPacketSize);

    // ch:注册消息异常回调 | en:Register Message Exception CallBack
    int RegisterExceptionCallBack(void(__stdcall* cbException)(unsigned int nMsgType, void* pUser), void* pUser);

    // ch:注册单个事件回调 | en:Register Event CallBack
    int RegisterEventCallBack(const char* pEventName, void(__stdcall* cbEvent)(MV_EVENT_OUT_INFO * pEventInfo, void* pUser), void* pUser);

    // ch:强制IP | en:Force IP
    int ForceIp(unsigned int nIP, unsigned int nSubNetMask, unsigned int nDefaultGateWay);

    // ch:配置IP方式 | en:IP configuration method
    int SetIpConfig(unsigned int nType);

    // ch:设置网络传输模式 | en:Set Net Transfer Mode
    int SetNetTransMode(unsigned int nType);

    // ch:像素格式转换 | en:Pixel format conversion
    int ConvertPixelType(MV_CC_PIXEL_CONVERT_PARAM* pstCvtParam);

    // ch:保存图片 | en:save image
    int SaveImage(MV_SAVE_IMAGE_PARAM_EX* pstParam);

    // ch:保存图片为文件 | en:Save the image as a file
    int SaveImageToFile(MV_SAVE_IMG_TO_FILE_PARAM* pstParam);

    // ch:绘制圆形辅助线 | en:Draw circle auxiliary line
    int DrawCircle(MVCC_CIRCLE_INFO* pCircleInfo);

    // ch:绘制线形辅助线 | en:Draw lines auxiliary line
    int DrawLines(MVCC_LINES_INFO* pLinesInfo);

    //读取buffer
    int ReadBuffer(cv::Mat &image,bool saveFlag,QByteArray imageName);

private:

    void *m_hDevHandle;

    //用于保存图像的缓存
    unsigned int m_nBufSizeForSaveImage;

};

#endif//_MV_CAMERA_H_

4.cmvcamera.cpp

#include "cmvcamera.h"

CMvCamera::CMvCamera()
{
    m_hDevHandle = MV_NULL;
}

CMvCamera::~CMvCamera()
{
    if (m_hDevHandle)
    {
        MV_CC_DestroyHandle(m_hDevHandle);
        m_hDevHandle = MV_NULL;
    }
}

// ch:获取SDK版本号 | en:Get SDK Version
int CMvCamera::GetSDKVersion()
{
    return MV_CC_GetSDKVersion();
}

// ch:枚举设备 | en:Enumerate Device
int CMvCamera::EnumDevices(unsigned int nTLayerType, MV_CC_DEVICE_INFO_LIST* pstDevList)
{
    return MV_CC_EnumDevices(nTLayerType, pstDevList);
}

// ch:判断设备是否可达 | en:Is the device accessible
bool CMvCamera::IsDeviceAccessible(MV_CC_DEVICE_INFO* pstDevInfo, unsigned int nAccessMode)
{
    return MV_CC_IsDeviceAccessible(pstDevInfo, nAccessMode);
}

// ch:打开设备 | en:Open Device
int CMvCamera::Open(MV_CC_DEVICE_INFO* pstDeviceInfo)
{
    if (MV_NULL == pstDeviceInfo)
    {
        return MV_E_PARAMETER;
    }

    if (m_hDevHandle)
    {
        return MV_E_CALLORDER;
    }

    int nRet  = MV_CC_CreateHandle(&m_hDevHandle, pstDeviceInfo);
    if (MV_OK != nRet)
    {
        return nRet;
    }

    nRet = MV_CC_OpenDevice(m_hDevHandle);
    if (MV_OK != nRet)
    {
        MV_CC_DestroyHandle(m_hDevHandle);
        m_hDevHandle = MV_NULL;
    }

    return nRet;
}

// ch:关闭设备 | en:Close Device
int CMvCamera::Close()
{
    if (MV_NULL == m_hDevHandle)
    {
        return MV_E_HANDLE;
    }

    MV_CC_CloseDevice(m_hDevHandle);

    int nRet = MV_CC_DestroyHandle(m_hDevHandle);
    m_hDevHandle = MV_NULL;

    return nRet;
}

// ch:判断相机是否处于连接状态 | en:Is The Device Connected
bool CMvCamera::IsDeviceConnected()
{
    return MV_CC_IsDeviceConnected(m_hDevHandle);
}

// ch:注册图像数据回调 | en:Register Image Data CallBack
int CMvCamera::RegisterImageCallBack(void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser), void* pUser)
{
    return MV_CC_RegisterImageCallBackEx(m_hDevHandle, cbOutput, pUser);
}

// ch:开启抓图 | en:Start Grabbing
int CMvCamera::StartGrabbing()
{
    return MV_CC_StartGrabbing(m_hDevHandle);
}

// ch:停止抓图 | en:Stop Grabbing
int CMvCamera::StopGrabbing()
{
    return MV_CC_StopGrabbing(m_hDevHandle);
}

// ch:主动获取一帧图像数据 | en:Get one frame initiatively
int CMvCamera::GetImageBuffer(MV_FRAME_OUT* pFrame, int nMsec)
{
    return MV_CC_GetImageBuffer(m_hDevHandle, pFrame, nMsec);
}

// ch:释放图像缓存 | en:Free image buffer
int CMvCamera::FreeImageBuffer(MV_FRAME_OUT* pFrame)
{
    return MV_CC_FreeImageBuffer(m_hDevHandle, pFrame);
}

// ch:设置显示窗口句柄 | en:Set Display Window Handle
int CMvCamera::DisplayOneFrame(MV_DISPLAY_FRAME_INFO* pDisplayInfo)
{
    return MV_CC_DisplayOneFrame(m_hDevHandle, pDisplayInfo);
}

// ch:设置SDK内部图像缓存节点个数 | en:Set the number of the internal image cache nodes in SDK
int CMvCamera::SetImageNodeNum(unsigned int nNum)
{
    return MV_CC_SetImageNodeNum(m_hDevHandle, nNum);
}

// ch:获取设备信息 | en:Get device information
int CMvCamera::GetDeviceInfo(MV_CC_DEVICE_INFO* pstDevInfo)
{
    return MV_CC_GetDeviceInfo(m_hDevHandle, pstDevInfo);
}

// ch:获取GEV相机的统计信息 | en:Get detect info of GEV camera
int CMvCamera::GetGevAllMatchInfo(MV_MATCH_INFO_NET_DETECT* pMatchInfoNetDetect)
{
    if (MV_NULL == pMatchInfoNetDetect)
    {
        return MV_E_PARAMETER;
    }

    MV_CC_DEVICE_INFO stDevInfo = {0};
    GetDeviceInfo(&stDevInfo);
    if (stDevInfo.nTLayerType != MV_GIGE_DEVICE)
    {
        return MV_E_SUPPORT;
    }

    MV_ALL_MATCH_INFO struMatchInfo = {0};

    struMatchInfo.nType = MV_MATCH_TYPE_NET_DETECT;
    struMatchInfo.pInfo = pMatchInfoNetDetect;
    struMatchInfo.nInfoSize = sizeof(MV_MATCH_INFO_NET_DETECT);
    memset(struMatchInfo.pInfo, 0, sizeof(MV_MATCH_INFO_NET_DETECT));

    return MV_CC_GetAllMatchInfo(m_hDevHandle, &struMatchInfo);
}

// ch:获取U3V相机的统计信息 | en:Get detect info of U3V camera
int CMvCamera::GetU3VAllMatchInfo(MV_MATCH_INFO_USB_DETECT* pMatchInfoUSBDetect)
{
    if (MV_NULL == pMatchInfoUSBDetect)
    {
        return MV_E_PARAMETER;
    }

    MV_CC_DEVICE_INFO stDevInfo = {0};
    GetDeviceInfo(&stDevInfo);
    if (stDevInfo.nTLayerType != MV_USB_DEVICE)
    {
        return MV_E_SUPPORT;
    }

    MV_ALL_MATCH_INFO struMatchInfo = {0};

    struMatchInfo.nType = MV_MATCH_TYPE_USB_DETECT;
    struMatchInfo.pInfo = pMatchInfoUSBDetect;
    struMatchInfo.nInfoSize = sizeof(MV_MATCH_INFO_USB_DETECT);
    memset(struMatchInfo.pInfo, 0, sizeof(MV_MATCH_INFO_USB_DETECT));

    return MV_CC_GetAllMatchInfo(m_hDevHandle, &struMatchInfo);
}

// ch:获取和设置Int型参数,如 Width和Height,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
// en:Get Int type parameters, such as Width and Height, for details please refer to MvCameraNode.xlsx file under SDK installation directory
int CMvCamera::GetIntValue(IN const char* strKey, OUT MVCC_INTVALUE_EX *pIntValue)
{
    return MV_CC_GetIntValueEx(m_hDevHandle, strKey, pIntValue);
}

int CMvCamera::SetIntValue(IN const char* strKey, IN int64_t nValue)
{
    return MV_CC_SetIntValueEx(m_hDevHandle, strKey, nValue);
}

// ch:获取和设置Enum型参数,如 PixelFormat,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
// en:Get Enum type parameters, such as PixelFormat, for details please refer to MvCameraNode.xlsx file under SDK installation directory
int CMvCamera::GetEnumValue(IN const char* strKey, OUT MVCC_ENUMVALUE *pEnumValue)
{
    return MV_CC_GetEnumValue(m_hDevHandle, strKey, pEnumValue);
}

int CMvCamera::SetEnumValue(IN const char* strKey, IN unsigned int nValue)
{
    return MV_CC_SetEnumValue(m_hDevHandle, strKey, nValue);
}

int CMvCamera::SetEnumValueByString(IN const char* strKey, IN const char* sValue)
{
    return MV_CC_SetEnumValueByString(m_hDevHandle, strKey, sValue);
}

int CMvCamera::GetEnumEntrySymbolic(IN const char* strKey, IN MVCC_ENUMENTRY* pstEnumEntry)
{
    return MV_CC_GetEnumEntrySymbolic(m_hDevHandle, strKey, pstEnumEntry);
}

// ch:获取和设置Float型参数,如 ExposureTime和Gain,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
// en:Get Float type parameters, such as ExposureTime and Gain, for details please refer to MvCameraNode.xlsx file under SDK installation directory
int CMvCamera::GetFloatValue(IN const char* strKey, OUT MVCC_FLOATVALUE *pFloatValue)
{
    return MV_CC_GetFloatValue(m_hDevHandle, strKey, pFloatValue);
}

int CMvCamera::SetFloatValue(IN const char* strKey, IN float fValue)
{
    return MV_CC_SetFloatValue(m_hDevHandle, strKey, fValue);
}

// ch:获取和设置Bool型参数,如 ReverseX,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
// en:Get Bool type parameters, such as ReverseX, for details please refer to MvCameraNode.xlsx file under SDK installation directory
int CMvCamera::GetBoolValue(IN const char* strKey, OUT bool *pbValue)
{
    return MV_CC_GetBoolValue(m_hDevHandle, strKey, pbValue);
}

int CMvCamera::SetBoolValue(IN const char* strKey, IN bool bValue)
{
    return MV_CC_SetBoolValue(m_hDevHandle, strKey, bValue);
}

// ch:获取和设置String型参数,如 DeviceUserID,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件UserSetSave
// en:Get String type parameters, such as DeviceUserID, for details please refer to MvCameraNode.xlsx file under SDK installation directory
int CMvCamera::GetStringValue(IN const char* strKey, MVCC_STRINGVALUE *pStringValue)
{
    return MV_CC_GetStringValue(m_hDevHandle, strKey, pStringValue);
}

int CMvCamera::SetStringValue(IN const char* strKey, IN const char* strValue)
{
    return MV_CC_SetStringValue(m_hDevHandle, strKey, strValue);
}

// ch:执行一次Command型命令,如 UserSetSave,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
// en:Execute Command once, such as UserSetSave, for details please refer to MvCameraNode.xlsx file under SDK installation directory
int CMvCamera::CommandExecute(IN const char* strKey)
{
    return MV_CC_SetCommandValue(m_hDevHandle, strKey);
}

// ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
int CMvCamera::GetOptimalPacketSize(unsigned int* pOptimalPacketSize)
{
    if (MV_NULL == pOptimalPacketSize)
    {
        return MV_E_PARAMETER;
    }

    int nRet = MV_CC_GetOptimalPacketSize(m_hDevHandle);
    if (nRet < MV_OK)
    {
        return nRet;
    }

    *pOptimalPacketSize = (unsigned int)nRet;

    return MV_OK;
}

// ch:注册消息异常回调 | en:Register Message Exception CallBack
int CMvCamera::RegisterExceptionCallBack(void(__stdcall* cbException)(unsigned int nMsgType, void* pUser),void* pUser)
{
    return MV_CC_RegisterExceptionCallBack(m_hDevHandle, cbException, pUser);
}

// ch:注册单个事件回调 | en:Register Event CallBack
int CMvCamera::RegisterEventCallBack(const char* pEventName, void(__stdcall* cbEvent)(MV_EVENT_OUT_INFO * pEventInfo, void* pUser), void* pUser)
{
    return MV_CC_RegisterEventCallBackEx(m_hDevHandle, pEventName, cbEvent, pUser);
}

// ch:强制IP | en:Force IP
int CMvCamera::ForceIp(unsigned int nIP, unsigned int nSubNetMask, unsigned int nDefaultGateWay)
{
    return MV_GIGE_ForceIpEx(m_hDevHandle, nIP, nSubNetMask, nDefaultGateWay);
}

// ch:配置IP方式 | en:IP configuration method
int CMvCamera::SetIpConfig(unsigned int nType)
{
    return MV_GIGE_SetIpConfig(m_hDevHandle, nType);
}

// ch:设置网络传输模式 | en:Set Net Transfer Mode
int CMvCamera::SetNetTransMode(unsigned int nType)
{
    return MV_GIGE_SetNetTransMode(m_hDevHandle, nType);
}

// ch:像素格式转换 | en:Pixel format conversion
int CMvCamera::ConvertPixelType(MV_CC_PIXEL_CONVERT_PARAM* pstCvtParam)
{
    return MV_CC_ConvertPixelType(m_hDevHandle, pstCvtParam);
}

// ch:保存图片 | en:save image
int CMvCamera::SaveImage(MV_SAVE_IMAGE_PARAM_EX* pstParam)
{
    return MV_CC_SaveImageEx2(m_hDevHandle, pstParam);
}

// ch:保存图片为文件 | en:Save the image as a file
int CMvCamera::SaveImageToFile(MV_SAVE_IMG_TO_FILE_PARAM* pstSaveFileParam)
{
    return MV_CC_SaveImageToFile(m_hDevHandle, pstSaveFileParam);
}

// ch:绘制圆形辅助线 | en:Draw circle auxiliary line
int CMvCamera::DrawCircle(MVCC_CIRCLE_INFO* pCircleInfo)
{
    return MV_CC_DrawCircle(m_hDevHandle, pCircleInfo);
}

// ch:绘制线形辅助线 | en:Draw lines auxiliary line
int CMvCamera::DrawLines(MVCC_LINES_INFO* pLinesInfo)
{
    return MV_CC_DrawLines(m_hDevHandle, pLinesInfo);
}

//读取相机中的图像
int CMvCamera::ReadBuffer(cv::Mat &image,bool saveFlag,QByteArray imageName)
{
    unsigned int nRecvBufSize = 0;
    MVCC_INTVALUE stParam;
    memset(&stParam, 0, sizeof(MVCC_INTVALUE));
    int tempValue = MV_CC_GetIntValue(m_hDevHandle, "PayloadSize", &stParam);
    if (tempValue != 0)
    {
        return -1;
    }
    nRecvBufSize = stParam.nCurValue;
    unsigned char* pDate;
    pDate=(unsigned char *)malloc(nRecvBufSize);

    MV_FRAME_OUT_INFO_EX stImageInfo;
    memset(&stImageInfo,0,sizeof(MV_FRAME_OUT_INFO));
    tempValue= MV_CC_GetOneFrameTimeout(m_hDevHandle, pDate, nRecvBufSize, &stImageInfo, 700);
    if(tempValue!=0)
    {
        return -1;
    }
    m_nBufSizeForSaveImage = stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
    unsigned char* m_pBufForSaveImage;
    m_pBufForSaveImage = (unsigned char*)malloc(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;
    }

    cv::Mat getImage;
    if(isMono)
    {
        getImage = cv::Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC1,pDate);
        if(saveFlag)
        {
            MV_SAVE_IMG_TO_FILE_PARAM stSaveFileParam;
            memset(&stSaveFileParam, 0, sizeof(MV_SAVE_IMG_TO_FILE_PARAM));
            stSaveFileParam.enImageType = MV_Image_Bmp; // ch:需要保存的图像类型 | en:Image format to save
            stSaveFileParam.enPixelType = stImageInfo.enPixelType;  // ch:相机对应的像素格式 | en:Camera pixel type
            stSaveFileParam.nWidth      = stImageInfo.nWidth;         // ch:相机对应的宽 | en:Width
            stSaveFileParam.nHeight     = stImageInfo.nHeight;          // ch:相机对应的高 | en:Height
            stSaveFileParam.nDataLen    = stImageInfo.nFrameLen;
            stSaveFileParam.pData       = pDate;
            stSaveFileParam.iMethodValue = 0;

            sprintf_s(stSaveFileParam.pImagePath,256,imageName.data());
            //qDebug()<<"pImagePath:"<<stSaveFileParam.pImagePath;
            int nRet = SaveImageToFile(&stSaveFileParam);
            if(MV_OK != nRet)
            {
                //qDebug()<<"nRet:"<<nRet;
            }
        }
    }

    getImage.copyTo(image);
    getImage.release();
    free(pDate);
    free(m_pBufForSaveImage);
    return 0;
}

5.camerathread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QThread>
#include <QImage>
#include <QDebug>
#include "cmvcamera.h"

class CameraThread : public QThread
{
    Q_OBJECT

public:
    explicit CameraThread(QObject *parent = nullptr);
     ~CameraThread();

    void initThread();
    void setCameraPtr(CMvCamera *camera);
    void setImagePtr(cv::Mat *image);
    void setCameraIndex(int index);
    void setSwitchFlag(bool switchFlag);

    void run();

signals:
    void signal_messImage(QImage myImage,int index);

private:
    bool startFlag;
    int m_cameraIndex = 0;

    CMvCamera *cameraPtr = NULL;
    cv::Mat *imagePtr = NULL;
    QImage *myImage = NULL;

};

#endif // MYTHREAD_H

6.camerathread.cpp

#include "camerathread.h"

CameraThread::CameraThread(QObject *parent)
    : QThread{parent}
{
    this->initThread();
}

CameraThread::~CameraThread()
{
    delete myImage;
    if(cameraPtr == NULL)
    {
        delete cameraPtr;
    }
    if(imagePtr == NULL)
    {
        delete imagePtr;
    }
}

void CameraThread::initThread()
{
    startFlag = false;
    myImage = new QImage();
}

void CameraThread::setCameraPtr(CMvCamera *camera)
{
    cameraPtr = camera;
}

void CameraThread::setImagePtr(cv::Mat *image)
{
    imagePtr = image;
}

void CameraThread::setCameraIndex(int index)
{
    m_cameraIndex = index;
}

void CameraThread::setSwitchFlag(bool switchFlag)
{
    startFlag = switchFlag;
}

void CameraThread::run()
{
    if(cameraPtr == NULL)
    {
        return;
    }
    if(imagePtr == NULL)
    {
        return;
    }

    while(startFlag)
    {
        cameraPtr->CommandExecute("TriggerSoftware");
        cameraPtr->ReadBuffer(*imagePtr,false,"");

        //先处理好再发送
        if(imagePtr->channels()>1)
        {
            *myImage = QImage((const unsigned char*)(imagePtr->data),imagePtr->cols,imagePtr->rows,QImage::Format_RGB888);
        }
        else
        {
            *myImage = QImage((const unsigned char*)(imagePtr->data),imagePtr->cols,imagePtr->rows,QImage::Format_Indexed8);
        }
        emit signal_messImage(*myImage,m_cameraIndex);
    }
}

7.mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDate>
#include <QDir>
#include <QMessageBox>
#include "HikSdk/cmvcamera.h"
#include "HikSdk/camerathread.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    void initWidget();
    void saveImage(QString format,int index);

private slots:
    void slot_displayImage(QImage myImage,int index);

    void on_pb_start_clicked();
    void on_pb_stop_clicked();
    void on_pb_saveOne_clicked();
    void on_pb_saveTwo_clicked();

private:
    Ui::MainWindow *ui;

    int m_deviceNum;
    bool m_bOpenDevice;
    QString m_savePath;
    QString m_cameraOnePath;
    QString m_cameraTwoPath;

    MV_CC_DEVICE_INFO_LIST m_stDevList;   //设备信息列表结构体变量,用来存储设备列表
    MV_CC_DEVICE_INFO *m_DeviceInfo[2];
    CMvCamera *m_pcMyCamera[2];           //相机指针对象
    cv::Mat *m_myImage[2];                //用于保存相机图像的图像指针对象
    CameraThread *m_cameraThread[2];      //相机线程对象

};
#endif // MAINWINDOW_H

8.mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->initWidget();
}

MainWindow::~MainWindow()
{
    for(int i=0;i<2;i++)
    {
        delete m_myImage[i];
        if(m_pcMyCamera[i])
        {
            m_pcMyCamera[i]->Close();
            delete m_pcMyCamera[i];
            m_pcMyCamera[i] = NULL;
        }
    }
}

void MainWindow::initWidget()
{
    //初始化变量
    m_deviceNum = 0;
    m_bOpenDevice = false;
    m_savePath = "";
    m_cameraOnePath = "";
    m_cameraTwoPath = "";

    //生成保存图片的文件夹
    QString curDate = QDate::currentDate().toString("yyyy-MM-dd");
    m_savePath = QDir::currentPath() + "/SaveImages/" + curDate + "/";
    QDir saveDir(m_savePath);
    if(!saveDir.exists())
    {
        if(!saveDir.mkpath(m_savePath))
        {
            qDebug()<<"创建文件夹失败!";
            //return;
        }
    }

    for(int i=0;i<2;i++)
    {
        //相机对象
        m_pcMyCamera[i] = new CMvCamera;

        //图像指针对象
        m_myImage[i] = new cv::Mat();

        //线程对象实例化
        m_cameraThread[i] = new CameraThread();
        connect(m_cameraThread[i],SIGNAL(signal_messImage(QImage,int)),this,SLOT(slot_displayImage(QImage,int)),Qt::BlockingQueuedConnection);
    }

    //初始化相机
    memset(&m_stDevList,0,sizeof(MV_CC_DEVICE_INFO_LIST));
    //枚举子网内所有设备
    int nRet = CMvCamera::EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE,&m_stDevList);
    if(MV_OK != nRet)
    {
        return;
    }
    m_deviceNum = m_stDevList.nDeviceNum;
    if(m_deviceNum != 2)
    {
        QMessageBox::warning(this,"警告","请检查相机是否正常连接!");
        return;
    }
    for(int i=0;i<m_deviceNum;i++)
    {
        MV_CC_DEVICE_INFO *pDeviceInfo = m_stDevList.pDeviceInfo[i];
        int nRet = m_pcMyCamera[i]->Open(pDeviceInfo);   //打开相机
        if(MV_OK != nRet)
        {
            delete m_pcMyCamera[i];
            m_pcMyCamera[i] = NULL;
            QMessageBox::warning(this,"警告","打开设备失败!");
            return;
        }
        m_pcMyCamera[i]->SetEnumValue("TriggerMode",1);        //设置为触发模式
        m_pcMyCamera[i]->SetEnumValue("TriggerSource",7);      //设置触发源为软触发
        m_pcMyCamera[i]->SetFloatValue("ExposureTime",5000);   //设置曝光时间
        m_cameraThread[i]->setCameraPtr(m_pcMyCamera[i]);
        m_cameraThread[i]->setImagePtr(m_myImage[i]);
        m_cameraThread[i]->setCameraIndex(i);
    }
}

void MainWindow::saveImage(QString format,int index)
{
    cv::Mat image;
    //当前时间
    QString curTime = QTime::currentTime().toString("hhmmss");
    if(index == 1)
    {
        //format: .bmp .tif .png .jpg
        QString saveNameOne = m_cameraOnePath + "Grab_" + curTime + "." + format;
        m_pcMyCamera[0]->CommandExecute("TriggerSoftware");
        int readFlag = m_pcMyCamera[0]->ReadBuffer(image,true,saveNameOne.toUtf8());
        if(MV_OK == readFlag)
        {
            qDebug()<<"相机一图像保存成功!";
        }
        else
        {
            qDebug()<<"相机一图像保存失败!";
        }
    }
    else if(index == 2)
    {
        QString saveNameTwo = m_cameraTwoPath + "Grab_" + curTime + "." + format;
        m_pcMyCamera[1]->CommandExecute("TriggerSoftware");
        int readFlag = m_pcMyCamera[1]->ReadBuffer(image,true,saveNameTwo.toUtf8());
        if(MV_OK == readFlag)
        {
            qDebug()<<"相机二图像保存成功!";
        }
        else
        {
            qDebug()<<"相机二图像保存失败!";
        }
    }
}

void MainWindow::slot_displayImage(QImage myImage,int index)
{
    if(myImage.isNull())
    {
        //qDebug()<<"Image is a null image!";
        return;
    }
    //显示图像
    QPixmap myPixmap = QPixmap::fromImage(myImage).scaled(QSize(400,400),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
    if(index == 0)
    {
        ui->lb_imageOne->setPixmap(myPixmap);
    }
    if(index == 1)
    {
        ui->lb_imageTwo->setPixmap(myPixmap);
    }
}

void MainWindow::on_pb_start_clicked()
{
    if(!m_bOpenDevice)
    {
        m_bOpenDevice = true;
    }
    for(int i=0;i<2;i++)
    {
        if(m_pcMyCamera[i]->IsDeviceConnected())
        {
            m_pcMyCamera[i]->StartGrabbing();   //开启相机采集
            if(!m_cameraThread[i]->isRunning())
            {
                m_cameraThread[i]->setSwitchFlag(true);
                m_cameraThread[i]->start();
            }
        }
    }
}

void MainWindow::on_pb_stop_clicked()
{
    if(m_bOpenDevice)
    {
        m_bOpenDevice = false;
    }
    for(int i=0;i<2;i++)
    {
        m_pcMyCamera[i]->StopGrabbing();   //关闭相机采集
        if(!m_cameraThread[i]->isRunning())
        {
            m_cameraThread[i]->setSwitchFlag(false);
        }
    }
}

void MainWindow::on_pb_saveOne_clicked()
{
    if(!m_bOpenDevice)
    {
        QMessageBox::warning(this,"警告","请开启相机采集!");
    }
    m_cameraOnePath = m_savePath + "Camera1/";
    QDir dstDir(m_cameraOnePath);
    if(!dstDir.exists())
    {
        if(!dstDir.mkpath(m_cameraOnePath))
        {
            qDebug()<<"创建Camera1文件夹失败!";
            //return;
        }
    }
    saveImage("bmp",1);
}

void MainWindow::on_pb_saveTwo_clicked()
{
    if(!m_bOpenDevice)
    {
        QMessageBox::warning(this,"警告","请开启相机采集!");
    }
    m_cameraTwoPath = m_savePath + "Camera2/";
    QDir dstDir(m_cameraTwoPath);
    if(!dstDir.exists())
    {
        if(!dstDir.mkpath(m_cameraTwoPath))
        {
            qDebug()<<"创建Camera2文件夹失败!";
            //return;
        }
    }
    saveImage("bmp",2);
}

9.mainwindow.ui
请添加图片描述

五、下载链接

我的示例百度网盘链接:https://pan.baidu.com/s/12z0t66qWDpoDUhSufXJwjw
提取码:xxcj


总结

本文使用了重写QThread的run函数来实现多线程,并通过设置标志位来控制图像采集的开始与停止,也是比较简单的方式。示例中实现了两个相机的图像采集,使用该方式也是没有出现卡顿等问题,但是在更多个相机的情况下(我同时连接过12个相机),会出现界面卡顿,我的解决方法是在线程run函数中的while循环内增加了一个10ms的延时(QThread::msleep(10);),也算暂时解决了该问题,但是如果有更好的方式,也希望得到大家的解答~


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/130282.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言中指针常见问题集

1. 我想声明一个指针并为它分配一些空间,但却不行。这些代码有什么问题&#xff1f; char *p; *p malloc(10);答&#xff1a;你所声明的指针是p, 而不是*p, 当你操作指针本身时你只需要使用指针的名字即可:cp malloc(10);当你操作指针指向的内存时,你才需要使用*作为间接操…

坚果的2022年终总结

人生天地之间&#xff0c;若白驹过隙&#xff0c;转眼间&#xff0c;这一年又快要过去了&#xff0c;按照惯例还是写一篇年终总结&#xff0c;同时也看一下自己是否又成长&#xff0c;是否有哪些事情没做好&#xff0c;给自己做一个复盘。一、缘起OpenHarmony我是从去年开始参加…

Webpack 钩子介绍、手写 Webpack Plugin

目录 1. Plugin 用作和工作原理 1.1 Plugin 的作用 1.2 Plugin 的工作原理 2. Webpack 底层逻辑和钩子介绍 2.1 Webpack 内部执行流程 2.2 Webpack 内部钩子 2.2.1 钩子是什么 2.2.2 Tapable —— 为 Webpack 提供 Plugin 钩子 数据类型接口 定义 2.2.3 Compiler Hook…

C#,图像二值化(08)——灰度图像二值化,全局算法,全局阈值优化算法及其源代码

1、全局阈值算法 基于灰度直方图的优化迭代算法之一。 Iterative Scheduler and Modified Iterative Water-Filling In the downlink, the inter-cell interference is only function of the power levels and is independent of the user scheduling decisions. This suggest…

俺的2022年

年末将至&#xff0c;还是要写点总结性的内容&#xff0c;以回顾过去一年做的各种事情。工作之外从客观数据上看&#xff0c;今年的收入水平略差于去年&#xff0c;主要是工作外的收入有所减少&#xff0c;其核心原因是没有录制新的课程内容进行变现&#xff0c;原本的计划是&a…

【自学Python】Python介绍

Python教程 什么是编程语言 编程语言&#xff08;programming language&#xff09;&#xff0c;是用来定义计算机程序的形式语言。它是一种被标准化的交流技巧&#xff0c;用来向计算机发出指令。 也可以说&#xff0c;计算机语言让程序员能够准确地定义计算机所需要使用的…

拓展交流空间,分享开发精彩 | 开发者说·DTalk 鉴赏

日月其迈&#xff0c;岁律更新&#xff0c;时间的洗礼让开发者们更加坚韧&#xff0c;持续探索&#xff0c;不断追求&#xff0c;同样也激励着我们为开发者提供更多的帮助与支持。不断迭代的技术产品是开发者们的趁手工具&#xff0c;定期更新的政策助力打造安全可靠的生态&…

基础数学(4)——线性回归复习

文章目录课程回顾基础知识回归模型的建模过程一元线性回归模型线性回顾进行极大似然估计&#xff08;例题&#xff08;必考&#xff09;&#xff09;极大似然估计极大似然估计的性质线性性无偏性最优性&#xff08;记住即可&#xff0c;没有推导&#xff09;方差计算一元线性回…

智能制造 | AIRIOT智慧工厂管理解决方案

工厂生产运转中&#xff0c;设备数量多&#xff0c;环境复杂、企业往往需要承担很高的维修、保养、备件和人力成本。传统的工厂改革遇到了诸多前所未有的挑战&#xff1a; 1、管理系统较多&#xff0c;数据隔离&#xff0c;系统集成困难重重&#xff1b; 2、大量老旧设备无法联…

QT使用log4cpp日志库

文章目录QT使用log4cpp日志库1. 从官网下载log4cpp源码2. 编译项目3. 在QT中使用log4cpp4. log4cpp4.1. Category4.2. Appender4.3. Layout4.4. Priority4.5. 使用宏定义为日志加上文件名 函数名 行号等QT使用log4cpp日志库 1. 从官网下载log4cpp源码 log4cpp官方网址 下载后…

MyBatisPlus ---- 常用注解

MyBatisPlus ---- 常用注解1. TableNamea>问题b>通过TableName解决问题c>通过全局配置解决问题2. Tablelda>问题b>通过TableId解决问题c>TableId的value属性d>TableId的type属性e>雪花算法3. TableFielda>情况1b>情况24. TableLogica>逻辑删除…

LeetCodeday03

203.移除链表元素 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5] 示例 2&#xff1…

基于springboot+mybatis+mysql+html实现医院预约挂号管理系统

基于springbootmybatismysqlhtml实现医院预约挂号管理系统一、系统简介二、系统主要功能界面2.1登陆2.2首页&#xff08;留言板、我的预约&#xff09;--用户2.3就诊预约--用户2.4我的预约--用户2.5我参与的评介--用户2.6我的预约日程--医生2.7对我的评介--医生2.8医生管理--管…

一文探索“预训练”的奥秘!

Datawhale干货 作者&#xff1a;王奥迪&#xff0c;单位&#xff1a;中国移动云能力中心2022年下半年开始&#xff0c;涌现出一大批“大模型”的优秀应用&#xff0c;其中比较出圈的当属AI作画与ChatGPT&#xff0c;刷爆了各类社交平台&#xff0c;其让人惊艳的效果&#xff0c…

[思维模式-19]:《复盘》-7- “积”篇 - 操作复盘- 如何做好复盘

目录 一、联想&#xff1a;复盘的五个误区与七个关键成功要素 1.1 五个误区 1.2 七个关键成功要素 二、复盘的25个“坑”及对策建议 2.1 回顾、评估阶段 2.2 分析、反思阶段 2.3 萃取、提炼阶段 2.4 转化、应用阶段 2.5 复盘引导阶段 三、有效复盘的三项核心技能 3.…

java常见问题处理

文章目录一、前言二、实战演练1、idea常用快捷键使用2、idea设置字体大小3、idea设置背景颜色-背景4、idea配置Maven5、idea中配置JDK6、idea中java.util变红报错IDEA中Sources、JavaDocs路径是红色的7、idea中使用mybatisPlus 自增主键失效&#xff0c;自增主键超大小知识点8、…

ZI-data RO-data RW-data Code BSS DATA

KEIL MDK 查看代码量、RAM使用情况--RO-data、RW-data、ZI-data的解释&#xff08;转&#xff09; - 酒醉的Tiger - 博客园源&#xff1a;KEIL MDK 查看代码量、RAM使用情况--RO-data、RW-data、ZI-data的解释KEIL RVMDK编译后的信息Program Size: Code86496 RO-datahttps://ww…

STM32MP157驱动开发——Linux 音频驱动

STM32MP157驱动开发——Linux 音频驱动一、简介1.CS42L51 简介2.I2S总线3.STM32MP1 SAI 总线接口二、驱动开发1.音频驱动1&#xff09;修改设备树i2c 接口&#xff1a;1.8v电源管理&#xff1a;2&#xff09;SAI 音频接口设备树3&#xff09;sound 节点2.使能和修改内核的 CS42…

linux系统中字符设备驱动开发方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;linux系统中的字符设备驱动实现的基本过程。 目录 第一&#xff1a;字符设备驱动简介 第二&#xff1a;字符设备驱动开发步骤 第三&#xff1a;编写字符设备驱动实验程序 第一&#xff1a;字符设备驱动简介 字符设备是Li…

130道基础OJ编程题之: 58 ~ 67 道

130道基础OJ编程题之: 58 ~ 67 道 文章目录130道基础OJ编程题之: 58 ~ 67 道0. 昔日OJ编程题:58. BC61 金字塔图案59. BC62 翻转金字塔图案60. BC63 菱形图案61. BC64 K形图案62. BC65 箭形图案63. BC66 反斜线形图案64. BC67 正斜线形图案65. BC68 X形图案66. BC69 空心正方形…