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

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


1. 功能概述

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

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

2. 初始化与 GUI 设置

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

cpp 复制代码
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 枚举连接的相机设备,将可用的相机序列号显示在列表中供用户选择。

cpp 复制代码
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 相机连接及初始化

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

cpp 复制代码
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 中显示。

cpp 复制代码
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 的信号和槽机制使得切换触发模式和调整曝光时间变得直观。

cpp 复制代码
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,用于处理如设备断开连接等异常情况,并将错误信息显示在界面上。

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

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

cpp 复制代码
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,以及图像格式转换,使得整个系统操作简单高效。

相关推荐
xcyxiner1 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner2 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner2 天前
DicomViewer (添加模型类)3
qt
xcyxiner3 天前
DicomViewer (目录调整) 2
qt
xcyxiner3 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
胖咕噜的稞达鸭5 天前
如何写好一个skill
人工智能·数码相机
Hello-FPGA5 天前
CameraLink相机模拟器 信号源加速激光雷达系统算法开发
数码相机
桥田智能5 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
双翌视觉5 天前
机器视觉系统为何离不开光学滤光片?
人工智能·数码相机·视觉检测·制造
森G5 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt