QT+OpenCV+海康SDK环境搭建,调用海康相机实时显示

代码和流程基本仿照这位大佬Qt+OpenCV调用海康相机SDK采集图像(C++) - 威海云博客 - 博客园,只做了一些跟自己适配的调整。

一、版本

Qt 构建套件(Kit)版本:

OpenCV版本:4.5.5,vc15

海康SDK:V.4.1.3

相机:海康工业相机MV-CA020-20GC(网口版)

二、流程及代码

2.1确保相机可以正常使用

网线连接相机和电脑确保相机和电脑在同一网段,打开海康官方软件MVS,当自动识别到相机后点击连接,点击开始采集,确保相机可以正常使用。

2.2 新建一个QT项目,新建好后添加mycanera.cpp和mycanera.h(原作者camera写错了)并在该项目的根目录下新建includes和libs文件夹。

将SDK文件夹下代码MVS\Development\Libraries\win64中的MvCameraControl.lib复制到新建的libs中

和MVS\Development\Includes中的所有文件复制到includes中

2.3 代码

Test02.pro,注意修改其中opencv路径至自己的路径,即最后部分(约49-57行)

#-------------------------------------------------
#
# Project created by QtCreator 2025-09-03T19:32:08
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = Test02
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0


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

HEADERS += \
        mainwindow.h \
    mycanera.h \
    mycanera.h

FORMS += \
        mainwindow.ui

win32: LIBS += -L$$PWD/libs/ -lMvCameraControl

INCLUDEPATH += $$PWD/libs
DEPENDPATH += $$PWD/libs
INCLUDEPATH += $$PWD/includes/
INCLUDEPATH += $$PWD/includes/GenICam/

DEPENDPATH += $$PWD/includes/
DEPENDPATH += $$PWD/includes/GenICam/

win32: LIBS += -LD:/soft/OpenCV/opencv-4.5.5/opencv/build/x64/vc15/lib/ -lopencv_world455d

INCLUDEPATH += D:/soft/OpenCV/opencv-4.5.5/opencv/build/x64/vc15
DEPENDPATH += D:/soft/OpenCV/opencv-4.5.5/opencv/build/x64/vc15
INCLUDEPATH += D:/soft/OpenCV/opencv-4.5.5/opencv/build/include/
                D:/soft/OpenCV/opencv-4.5.5/opencv/build/include/opencv2
 DEPENDPATH += D:/soft/OpenCV/opencv-4.5.5/opencv/build/include/
                D:/soft/OpenCV/opencv-4.5.5/opencv/build/include/opencv2

mainwindow.h代码

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

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

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();
    void on_pushButton_realtime_clicked(); // 实时显示按钮
    void updateFrame(); // 定时器超时槽函数

private:
    Ui::MainWindow *ui;
    QTimer *m_timer; // 用于定时获取图像
    bool m_bIsGrabbing; // 标记是否正在连续采集
};
#endif // MAINWINDOW_H

mycanera.h代码


#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>
#include <QDateTime> // 用于生成时间戳文件名

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

mainwindow.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_timer = new QTimer(this);
     m_bIsGrabbing = false;
     connect(m_timer, SIGNAL(timeout()), this, SLOT(updateFrame()));

    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() << "连接相机成功";

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

        // 尝试使用序列号连接
        QString serialNumber = QString::fromLocal8Bit((char *)m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.chSerialNumber);
        qDebug() << "尝试使用序列号连接:" << serialNumber;

        int linkBySerial = m_pcMycamera->connectCamera(serialNumber.toStdString());
        qDebug() << "使用序列号连接结果:" << linkBySerial;
    }
}
//添加实时显示按钮的槽函数
void MainWindow::on_pushButton_realtime_clicked()
{
    if (!m_bIsGrabbing) {
        // 开始实时显示
        if (m_pcMycamera->setTriggerMode(0) == 0) { // 设置为连续采集模式
            m_timer->start(33); // 约30帧/秒
            m_bIsGrabbing = true;
            ui->pushButton_realtime->setText("停止实时显示");
        }
    } else {
        // 停止实时显示
        m_timer->stop();
        m_bIsGrabbing = false;
        ui->pushButton_realtime->setText("开始实时显示");
    }
}

// 定时器超时槽函数,用于更新画面
void MainWindow::updateFrame()
{
    // 读取相机中的图像
    int readInt = m_pcMycamera->ReadBuffer(imageMat);
    if(readInt != 0){
        qDebug() << "读取图像失败";
        return;
    }

    // 转换并显示图像
    image = cvMat2QImage(imageMat);
    ui->label_image->setPixmap(QPixmap::fromImage(image).scaled(
        ui->label_image->width(),
        ui->label_image->height(),
        Qt::KeepAspectRatio));
}

// 修改单张采集函数,确保在单张采集时使用触发模式
void MainWindow::on_pushButton_caiji_clicked()
{
    // 如果正在实时显示,先停止
    if (m_bIsGrabbing) {
        m_timer->stop();
        m_bIsGrabbing = false;
        ui->pushButton_realtime->setText("开始实时显示");
    }

    // 设置为触发模式
    m_pcMycamera->setTriggerMode(1);

    // 发送软触发
    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).scaled(
        ui->label_image->width(),
        ui->label_image->height(),
        Qt::KeepAspectRatio));
}
//关闭设备
void MainWindow::on_pushButton_close_clicked()
{
    //关闭设备,释放资源
    int close = m_pcMycamera->closeCamera();
    if(close != 0){
        qDebug() << "相机关闭失败";
    }
}

//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();
    }
}

mycanera.h代码

#include "mycanera.h"
#include <QDebug>
MyCanera::MyCanera()
{
    m_hDevHandle = NULL;
        m_pBufForSaveImage = nullptr;
        m_nBufSizeForSaveImage = 0;
        m_pBufForDriver = nullptr;
        m_nBufSizeForDriver = 0;
        memset(&m_stDevList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
        m_Device = NULL;
}

MyCanera::~MyCanera()
{
    if (m_pBufForDriver != nullptr) {
            free(m_pBufForDriver);
            m_pBufForDriver = nullptr;
        }
        if (m_pBufForSaveImage != nullptr) {
            free(m_pBufForSaveImage);
            m_pBufForSaveImage = nullptr;
        }

        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) {
        qDebug() << "枚举设备失败,错误码:" << temp;
        return -1;
    }

    if(m_stDevList.nDeviceNum == 0) {
        qDebug() << "未找到任何相机";
        return 2;
    }

    m_Device = NULL;
    for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++)
    {
        MV_CC_DEVICE_INFO* pDeviceInfo = m_stDevList.pDeviceInfo[i];
        if (NULL == pDeviceInfo)
        {
            continue;
        }

        if(id == (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chUserDefinedName ||
           id == (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chSerialNumber)
        {
            m_Device = m_stDevList.pDeviceInfo[i];
            break;
        }
    }

    if(m_Device == NULL) {
        qDebug() << "未找到指定名称的相机";
        return 3;
    }

    temp = MV_CC_CreateHandle(&m_hDevHandle, m_Device);
    if(temp != MV_OK) {
        qDebug() << "创建句柄失败,错误码:" << temp;
        return -1;
    }

    temp = MV_CC_OpenDevice(m_hDevHandle);
    if (temp != MV_OK) {
        qDebug() << "打开设备失败,错误码:" << temp;
        MV_CC_DestroyHandle(m_hDevHandle);
        m_hDevHandle = NULL;
        return -1;
    }

    // 设置触发模式为关闭(连续采集模式)
    int triggerResult = setTriggerMode(0);
    if (triggerResult != 0) {
        qDebug() << "设置触发模式失败";
        MV_CC_CloseDevice(m_hDevHandle);
        MV_CC_DestroyHandle(m_hDevHandle);
        m_hDevHandle = NULL;
        return -1;
    }

    return 0;
}
//设置相机是否开启触发模式
int MyCanera::setTriggerMode(unsigned int TriggerModeNum)
{
    int nRet = MV_CC_SetTriggerMode(m_hDevHandle,TriggerModeNum);
    if (MV_OK != nRet)
    {
        return -1;
    }

}
//启动相机采集
int MyCanera::startCamera()
{
    if (m_hDevHandle == NULL) {
            qDebug() << "相机句柄为空,无法启动采集";
            return -1;
        }

        int temp = MV_CC_StartGrabbing(m_hDevHandle);
        if(temp != 0)
        {
            qDebug() << "抓图失败,错误码:" << temp;
            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)
{
    if (m_hDevHandle == NULL) {
        qDebug() << "相机句柄为空,无法读取图像";
        return -1;
    }

    // 释放之前分配的内存
    if (m_pBufForDriver != nullptr) {
        free(m_pBufForDriver);
        m_pBufForDriver = nullptr;
    }
    if (m_pBufForSaveImage != nullptr) {
        free(m_pBufForSaveImage);
        m_pBufForSaveImage = nullptr;
    }

    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失败,错误码:" << tempValue;
        return -1;
    }

    nBufSize = stIntvalue.nCurValue;
    m_pBufForDriver = (unsigned char *)malloc(nBufSize);
    if (m_pBufForDriver == nullptr) {
        qDebug() << "内存分配失败";
        return -1;
    }

    MV_FRAME_OUT_INFO_EX stImageInfo;
    memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));

    int timeout = MV_CC_GetOneFrameTimeout(m_hDevHandle, m_pBufForDriver, nBufSize, &stImageInfo, 1000);
    if(timeout != 0)
    {
        qDebug() << "GetOneFrameTimeout失败,错误码:" << timeout;
        free(m_pBufForDriver);
        m_pBufForDriver = nullptr;
        return -1;
    }

    m_nBufSizeForSaveImage = stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
    m_pBufForSaveImage = (unsigned char*)malloc(m_nBufSizeForSaveImage);
    if (m_pBufForSaveImage == nullptr) {
        qDebug() << "内存分配失败";
        free(m_pBufForDriver);
        m_pBufForDriver = nullptr;
        return -1;
    }

    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
    {
        MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {0};
        stConvertParam.nWidth = stImageInfo.nWidth;
        stConvertParam.nHeight = stImageInfo.nHeight;
        stConvertParam.pSrcData = m_pBufForDriver;
        stConvertParam.nSrcDataLen = stImageInfo.nFrameLen;
        stConvertParam.enSrcPixelType = stImageInfo.enPixelType;
        stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed;
        stConvertParam.pDstBuffer = m_pBufForSaveImage;
        stConvertParam.nDstBufferSize = m_nBufSizeForSaveImage;

        int convertResult = MV_CC_ConvertPixelType(m_hDevHandle, &stConvertParam);
        if (convertResult != MV_OK) {
            qDebug() << "像素格式转换失败,错误码:" << convertResult;
            free(m_pBufForDriver);
            free(m_pBufForSaveImage);
            m_pBufForDriver = nullptr;
            m_pBufForSaveImage = nullptr;
            return -1;
        }

        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;
}

main.cpp代码

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.ui,我的界面不好看,也可以自行美化,只要几个按钮对应上就好了

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>736</width>
    <height>509</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QLabel" name="label_image">
    <property name="geometry">
     <rect>
      <x>40</x>
      <y>40</y>
      <width>641</width>
      <height>311</height>
     </rect>
    </property>
    <property name="text">
     <string/>
    </property>
   </widget>
   <widget class="QGroupBox" name="groupBox">
    <property name="geometry">
     <rect>
      <x>20</x>
      <y>10</y>
      <width>701</width>
      <height>351</height>
     </rect>
    </property>
    <property name="title">
     <string>相机实时画面</string>
    </property>
   </widget>
   <widget class="QWidget" name="">
    <property name="geometry">
     <rect>
      <x>60</x>
      <y>390</y>
      <width>631</width>
      <height>31</height>
     </rect>
    </property>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <widget class="QPushButton" name="pushButton_link">
       <property name="text">
        <string>连接相机</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="pushButton_realtime">
       <property name="text">
        <string>开始实时显示</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="pushButton_caiji">
       <property name="text">
        <string>采集单张图像</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="pushButton_close">
       <property name="text">
        <string>关闭相机</string>
       </property>
      </widget>
     </item>
    </layout>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>736</width>
     <height>17</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

结果:运行后点击连接相机-点击开始实时显示

即可显示相机画面

问题:我这个还有逻辑不通的地方,关闭相机不成功,可以让AI改一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值