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

news/2024/11/15 8:22:58 标签: qt, 数码相机

本文将梳理一个不借助外部视觉库(如 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,以及图像格式转换,使得整个系统操作简单高效。


http://www.niftyadmin.cn/n/5752956.html

相关文章

k8s 1.28.2 集群部署 docker registry 接入 MinIO 存储

文章目录 [toc]docker registry 部署生成 htpasswd 文件生成 secret 文件 生成 registry 配置文件创建 service创建 statefulset创建 ingress验证 docker registry docker registry 监控docker registry ui docker registry dockerfile docker registry 配置文件 S3 storage dr…

vxe-table 表格多选启用快捷选择功能,鼠标滑动范围选择功能

Vxe UI vue vxe-table 中启用表格多选的范围选择功能很简单&#xff0c;启用后就像 excel 一样&#xff0c;可以通过鼠标滑动选择行&#xff0c;也可以按住 ctrl 键部分选择&#xff0c;功能非常强大。 通过设置参数 checkboxConfig.range 就可以开启 支持鼠标直接滑动勾选行 …

Docker 篇-Docker 详细安装、了解和使用 Docker 核心功能(数据卷、自定义镜像 Dockerfile、网络)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Docker 概述 1.1 Docker 主要组成部分 1.2 Docker 安装 2.0 Docker 常见命令 2.1 常见的命令介绍 2.2 常见的命令演示 3.0 数据卷 3.1 数据卷常见的命令 3.2 常见…

springboot如何获取控制层get和Post入参

一、在 Spring 配置中创建一个过滤器&#xff0c;将 HttpServletRequest 包装为 ContentCachingRequestWrapper import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import j…

Java 责任链模式 减少 if else 实战案例

一、场景介绍 假设有这么一个朝廷&#xff0c;它有 县-->府-->省-->朝廷&#xff0c;四级行政机构。 这四级行政机构的关系如下表&#xff1a; 1、县-->府-->省-->朝廷&#xff1a;有些地方有完整的四级行政机构。 2、县-->府-->朝廷&#xff1a;直…

[Electron]总结:如何创建Electron+Element Plus的项目

我将结合官网手册与AI问到的信息&#xff0c;直接给出步骤&#xff0c;与命令。 一、准备环境 首先在C盘Users&#xff0c;你的登录的账号名文件夹下&#xff0c;编辑.npmrc文件。添加镜像地址。 如果使用了yarn&#xff0c;则是.yarnrc。可以全部都配置。 npm install -g …

深度学习之pytorch常见的学习率绘制

文章目录 0. Scope1. StepLR2. MultiStepLR3. ExponentialLR4. CosineAnnealingLR5. ReduceLROnPlateau6. CyclicLR7. OneCycleLR小结参考文献 https://blog.csdn.net/coldasice342/article/details/143435848 0. Scope 在深度学习中&#xff0c;学习率&#xff08;Learning R…

策略模式、状态机详细解读

策略模式 (Strategy Pattern) 策略模式 (Strategy Pattern) 是一种行为型设计模式&#xff0c;旨在将一组算法封装成独立的类&#xff0c;使得它们可以相互替换。这种模式让算法的变化不会影响到使用算法的客户&#xff0c;减少了类之间的耦合。策略模式通常用于处理一类问题&…