使用 Qt 实现基于海康相机的图像采集和显示系统(不使用外部视觉库,如Halcon\OpenCv)[工程源码联系博主索要]

本文将梳理一个不借助外部视觉库(如 OpenCV/Halcon)的海康相机图像采集和显示 Demo。该程序直接使用 Qt GUI 来显示图像。通过海康 MVS SDK 实现相机的连接、参数设置、图像采集和异常处理等功能,并通过 Qt 界面展示操作结果。


在这里插入图片描述

1. 功能概述

该程序通过 Qt 的 GUI 作为界面,通过海康 MVS SDK 控制相机并显示实时图像。主要功能包括:

  • 相机连接和设置
  • 参数调整(如曝光时间和触发模式)
  • 图像采集与显示
  • 异常处理(如设备断开)

2. 初始化与 GUI 设置

MainWindow 的构造函数中进行界面初始化,包括设置按钮的可见性、启用状态等。 initStyle() 函数用于加载并应用界面的样式表。

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

    // 设置初始 UI 状态
    ui->btn_Start->setEnabled(false);
    ui->btn_Stop->setEnabled(false);
    ui->btn_close->setEnabled(false);
    ui->btn_Grab->setVisible(false);
    ui->groupBox->setEnabled(false);
}

3. 相机连接与操作

3.1 枚举和连接相机

通过点击“搜索相机”按钮,程序调用 MV_CC_EnumDevices 枚举连接的相机设备,将可用的相机序列号显示在列表中供用户选择。

void MainWindow::on_btnSeachCamera_clicked() {
    ui->listWidget->clear();
    int nRet = MV_OK;
    bool isGige = ui->radioGIGE->isChecked();

    // 枚举连接的相机
    if (isGige) {
        nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE, &cameraList);
    } else {
        nRet = MV_CC_EnumDevices(MV_USB_DEVICE, &cameraList);
    }

    if (nRet != MV_OK || cameraList.nDeviceNum == 0) {
        setLastErrorMsg(tc("未找到任何可用相机, 错误码: %1").arg(nRet));
        return;
    }

    // 添加相机序列号到列表中
    for (int i = 0; i < cameraList.nDeviceNum; i++) {
        const char *serial = isGige
                             ? reinterpret_cast<char *>(cameraList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chSerialNumber)
                             : reinterpret_cast<char *>(cameraList.pDeviceInfo[i]->SpecialInfo.stUsb3VInfo.chSerialNumber);
        ui->listWidget->addItem(serial);
    }
}
3.2 相机连接及初始化

点击“连接相机”按钮后,程序通过创建相机句柄并打开设备。设置默认曝光时间和注册图像采集、异常处理回调函数。

void MainWindow::on_btnconnect_clicked() {
    MV_CC_DEVICE_INFO cameraInfo;
    int nRet = MV_OK;

    // 创建句柄并打开相机
    memcpy(&cameraInfo, cameraList.pDeviceInfo[0], sizeof(MV_CC_DEVICE_INFO));
    if ((nRet = MV_CC_CreateHandle(&m_handle, &cameraInfo)) != MV_OK) {
        setLastErrorMsg(tc("相机初始化失败, 错误码: %1").arg(nRet));
        return;
    }

    if ((nRet = MV_CC_OpenDevice(m_handle, MV_ACCESS_Exclusive)) != MV_OK) {
        setLastErrorMsg(tc("相机打开失败, 错误码: %1").arg(nRet));
        return;
    }

    // 设置曝光时间并注册回调函数
    MV_CC_SetExposureTime(m_handle, ui->spinBox->value());
    MV_CC_RegisterImageCallBackEx(m_handle, ImageCallBack, this);
    MV_CC_RegisterExceptionCallBack(m_handle, ExceptionCallBack, this);

    // 更新 UI 状态
    ui->btn_Start->setEnabled(true);
    ui->btn_Stop->setEnabled(true);
    ui->btn_close->setEnabled(true);
    ui->btnconnect->setEnabled(false);
    ui->groupBox->setEnabled(true);
}

4. 图像采集与显示

4.1 图像采集回调

通过注册图像回调函数 ImageCallBack,将采集到的图像数据转换为 QImage 格式,以便在 Qt 的 QLabel 中显示。

void ImageCallBack(unsigned char *pData, MV_FRAME_OUT_INFO_EX *pFrameInfo, void *pUser) {
    MainWindow *camera = static_cast<MainWindow *>(pUser);
    QImage img;

    switch (pFrameInfo->enPixelType) {
        case PixelType_Gvsp_Mono8:
            // 单通道灰度图像转换
            img = QImage(pData, pFrameInfo->nWidth, pFrameInfo->nHeight, pFrameInfo->nWidth, QImage::Format_Grayscale8);
            break;

        case PixelType_Gvsp_RGB8_Packed:
            // RGB8 数据转换
            img = QImage(pData, pFrameInfo->nWidth, pFrameInfo->nHeight, QImage::Format_RGB888);
            break;

        case PixelType_Gvsp_BayerRG8:
        case PixelType_Gvsp_BayerBG8:
            // Bayer 格式转换
            img = QImage(pFrameInfo->nWidth, pFrameInfo->nHeight, QImage::Format_RGB888);
            for (int y = 0; y < pFrameInfo->nHeight - 1; y++) {
                for (int x = 0; x < pFrameInfo->nWidth - 1; x++) {
                    int index = y * pFrameInfo->nWidth + x;
                    uchar r, g, b;
                    if (pFrameInfo->enPixelType == PixelType_Gvsp_BayerRG8) {
                        r = pData[index];
                        g = (pData[index + 1] + pData[index + pFrameInfo->nWidth]) / 2;
                        b = pData[index + pFrameInfo->nWidth + 1];
                    } else {
                        b = pData[index];
                        g = (pData[index + 1] + pData[index + pFrameInfo->nWidth]) / 2;
                        r = pData[index + pFrameInfo->nWidth + 1];
                    }
                    img.setPixel(x, y, qRgb(r, g, b));
                }
            }
            break;

        default:
            qWarning("Unsupported pixel type");
            return;
    }

    // 显示图像
    camera->detect(img);
}

void MainWindow::detect(const QImage &image) {
    ui->lab_image->setPixmap(QPixmap::fromImage(image).scaled(ui->lab_image->size()));
}
4.2 触发模式和曝光时间调整

根据用户选择的触发模式和曝光时间设置相机参数。Qt 的信号和槽机制使得切换触发模式和调整曝光时间变得直观。

void MainWindow::on_comboBox_activated(int index) {
    int nRet = MV_OK;
    switch (index) {
        case OpenContinue:
            nRet = MV_CC_SetEnumValue(m_handle, "TriggerMode", 0);
            break;
        case OpenSoftWare:
            nRet = MV_CC_SetEnumValue(m_handle, "TriggerMode", 1);
            nRet = MV_CC_SetEnumValue(m_handle, "TriggerSource", 7);
            break;
        case OpenHardWare:
            nRet = MV_CC_SetEnumValue(m_handle, "TriggerMode", 1);
            nRet = MV_CC_SetEnumValue(m_handle, "TriggerSource", 0);
            break;
    }
    if (nRet != MV_OK) setLastErrorMsg(tc("设置触发模式失败, 错误码: %1").arg(nRet));
}

5. 异常处理与资源释放

5.1 异常处理

程序注册了异常回调函数 ExceptionCallBack,用于处理如设备断开连接等异常情况,并将错误信息显示在界面上。

void ExceptionCallBack(unsigned int nMsgType, void *pUser) {
    if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT) {
        MainWindow *camera = static_cast<MainWindow *>(pUser);
        camera->setLastErrorMsg(tc("相机连接断开"));
    }
}
5.2 资源释放

程序退出时,调用相机停止、关闭函数,释放资源以避免内存泄漏。

void MainWindow::on_btn_close_clicked() {
    on_btn_Stop_clicked();
    int nRet = MV_CC_CloseDevice(m_handle);
    if (nRet != MV_OK) {
        setLastErrorMsg(tc("关闭相机失败, 错误码: %1").arg(nRet));
    }
}

6. 总结

本代码实现了

基于 Qt 的海康相机图像采集和显示系统,直接通过 MVS SDK 进行图像数据处理和显示。Qt 的信号槽机制、MVS SDK 的相机控制 API,以及图像格式转换,使得整个系统操作简单高效。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C# 异步Task异常处理和堆栈追踪显示

Task的问题 在C#中异步Task是一个很方便的语法&#xff0c;经常用在处理异步&#xff0c;例如需要下载等待等方法中&#xff0c;不用函数跳转&#xff0c;代码阅读性大大提高&#xff0c;深受大家喜欢。 但是有时候发现我们的异步函数可能出现了报错&#xff0c;但是异常又没…

31.3 XOR压缩和相关的prometheus源码解读

本节重点介绍 : xor 压缩value原理xor压缩过程讲解xor压缩prometheus源码解读xor 压缩效果 xor 压缩value原理 原理:时序数据库相邻点变化不大&#xff0c;采用异或压缩float64的前缀和后缀0个数 xor压缩过程讲解 第一个值使用原始点存储计算和前面的值的xor 如果XOR值为0&…

游戏引擎学习第16天

视频参考:https://www.bilibili.com/video/BV1mEUCY8EiC/ 这些字幕讨论了编译器警告的概念以及如何在编译过程中启用和处理警告。以下是字幕的内容摘要&#xff1a; 警告的定义&#xff1a;警告是编译器用来告诉你某些地方可能存在问题&#xff0c;尽管编译器不强制要求你修复…

解析煤矿一张图

解析煤矿一张图 ​ 煤矿一张图是指通过数字化、智能化技术将煤矿的各项信息、数据和资源进行集中展示和管理&#xff0c;形成一个综合的可视化平台。这一平台将矿井的地理信息、设备状态、人员位置、安全生产、环境监测等信息整合成一个统一的“图形”&#xff0c;以便于管理者…

Python学习27天

字典 dict{one:1,two:2,three:3} # 遍历1&#xff1a; # 先取出Key for key in dict:# 取出Key对应的valueprint(f"key:{key}---value:{dict[key]}")#遍历2&#xff0c;依次取出value for value in dict.values():print(value)# 遍历3&#xff1a;依次取出key,value …

【伪造检测】Noise Based Deepfake Detection via Multi-Head Relative-Interaction

一、研究动机 [!note] 动机&#xff1a;目前基于噪声的检测是利用Photo Response Non-Uniformity (PRNU)实现的&#xff0c;这是一种由于相机感光传感器而造成的缺陷噪声&#xff0c;主要用图像的源识别&#xff0c;在伪造检测的任务中并没有很好的表现。因此在文中提出了一种基…

【eNSP】企业网络架构实验——vlan间的路由通信(三)

VLAN间的路由是指不同VLAN之间的通信&#xff0c;通常VLAN是用来分割网络流量和提高网络安全性的。 一、VLAN 1. 什么是VLAN&#xff1f; VLAN&#xff0c;全称是虚拟局域网&#xff08;Virtual Local Area Network&#xff09;&#xff0c;是一种将物理局域网&#xff08;LA…

github 模型下载方法

github 模型权重&#xff0c;如果是项目下载&#xff0c;pth文件有时下载后只有1kb 本人测试ok下载方法&#xff1a; 点击view raw&#xff0c;然后可以下载模型权重文件了。

【微软:多模态基础模型】(2)视觉理解

欢迎关注【youcans的AGI学习笔记】原创作品 【微软&#xff1a;多模态基础模型】&#xff08;1&#xff09;从专家到通用助手 【微软&#xff1a;多模态基础模型】&#xff08;2&#xff09;视觉理解 【微软&#xff1a;多模态基础模型】&#xff08;3&#xff09;视觉生成 【微…

Dolby TrueHD和Dolby Digital Plus (E-AC-3)编码介绍

文章目录 1. Dolby TrueHD特点总结 2. Dolby Digital Plus (E-AC-3)特点总结 Dolby TrueHD 与 Dolby Digital Plus (E-AC-3) 的对比 Dolby TrueHD和Dolby Digital Plus (E-AC-3) 是两种高级的杜比音频编码格式&#xff0c;常用于蓝光影碟、流媒体、影院等高品质音频传输场景。它…

基于SpringBoot的养老院管理系统+文档

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

Figma汉化:提升设计效率,降低沟通成本

在UI设计领域&#xff0c;Figma因其强大的功能而广受欢迎&#xff0c;但全英文界面对于国内设计师来说是一个不小的挑战。幸运的是&#xff0c;通过Figma汉化插件&#xff0c;我们可以克服语言障碍。以下是两种获取和安装Figma汉化插件的方法&#xff0c;旨在帮助国内的UI设计师…

JavaWeb之AJAX

前言 这一节讲JavaWeb之AJAX 1.概述 以前我们在servlet中得到数据&#xff0c;必须通过域给jsp&#xff0c;然后jsp在响应给浏览器 纯html不能获取servlet返回数据 所以我们用jsp 但是现在我们可以同AJAX给返回数据了 我们可以在sevlet中直接通过AJAX返回给浏览器 html中的J…

【Spring】Bean

Spring 将管理对象称为 Bean。 Spring 可以看作是一个大型工厂&#xff0c;用于生产和管理 Spring 容器中的 Bean。如果要使用 Spring 生产和管理 Bean&#xff0c;那么就需要将 Bean 配置在 Spring 的配置文件中。Spring 框架支持 XML 和 Properties 两种格式的配置文件&#…

[Python学习日记-68] 绑定方法与非绑定方法

[Python学习日记-68] 绑定方法与非绑定方法 简介 绑定方法 非绑定方法 绑定方法与非绑定方法的应用 简介 在之前我们学习类与对象的属性查找与绑定方法的时候就接触过绑定方法了&#xff0c;不过当时是简单的介绍了针对于对象的绑定方法&#xff0c;其实在类内部定义的函数…

逆向攻防世界CTF系列39-debug

逆向攻防世界CTF系列39-debug 查了资料说.NET要用其它调试器&#xff0c;下载了ILSPY和dnSPY ILSPY比较适合静态分析代码最好了&#xff0c;函数名虽然可能乱码不显示&#xff0c;但是单击函数名还是能跟踪的&#xff0c;而dnSPY在动态调试上效果好&#xff0c;它的函数名不仅…

Spring-事务学习

spring事务 1. 什么是事务? 事务其实是一个并发控制单位&#xff0c;是用户定义的一个操作序列&#xff0c;这些操作要么全部完成&#xff0c;要不全部不完成&#xff0c;是一个不可分割的工作单位。事务有 ACID 四个特性&#xff0c;即&#xff1a; 原子性&#xff08;Atom…

RHCE的学习(21)

第三章 Shell条件测试 用途 为了能够正确处理Shell程序运行过程中遇到的各种情况&#xff0c;Linux Shell提供了一组测试运算符。 通过这些运算符&#xff0c;Shell程序能够判断某种或者几个条件是否成立。 条件测试在各种流程控制语句&#xff0c;例如判断语句和循环语句中…

用pyspark把kafka主题数据经过etl导入另一个主题中的有关报错

首先看一下我们的示例代码 import os from pyspark.sql import SparkSession import pyspark.sql.functions as F """ ------------------------------------------Description : TODO&#xff1a;SourceFile : etl_stream_kafkaAuthor : zxxDate : 2024/11/…

单片机_day3_GPIO

目录 1. 灯如何才能亮 1.1原理图 1.2 二极管 1.3 换了一个灯和原理图 ​编辑 1.4 三极管 1.4.1 NPN型三极管 1.4.2 PNP型三极管 2. 基本概念 3. 输入 3.1 浮空输入 3.2 上拉输入 3.3 下拉输入 3.4 模拟输入 4. 输出 4.1 推挽输出 4.2 开漏输出 如何让开漏输出…