本文将梳理一个基于 Qt 和 OpenCV 实现的海康相机图像采集 Demo。该程序能够实现相机连接、参数设置、图像采集与显示、异常处理等功能,并通过 Qt 界面展示操作结果。
在这里插入图片描述

1. 功能概述

该程序使用 Qt 的 GUI 作为界面,OpenCV 作为图像处理库,通过海康 MVS SDK 完成对相机的控制。主要功能包括:

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

2. 初始化与 GUI 设置

2.1 初始化 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 函数枚举设备,再通过 MV_CC_CreateHandleMV_CC_OpenDevice 创建并打开相机句柄。

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

    // 枚举 PC 连接的所有相机
    if (isGige) {
        if (MV_OK != (nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE, &cameraList))) {
            setLastErrorMsg(tc("未找到可用网口相机, 错误码: %1").arg(nRet));
        }
    } else {
        if (MV_OK != (nRet = MV_CC_EnumDevices(MV_USB_DEVICE, &cameraList))) {
            setLastErrorMsg(tc("未找到可用 USB 相机, 错误码: %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 相机参数设置

通过调用 MV_CC_SetExposureTimeMV_CC_SetEnumValue 设置曝光时间和触发模式。使用 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);  // 软件触发模式
        if (MV_OK == nRet) nRet = MV_CC_SetEnumValue(m_handle, "TriggerSource", 7);
        break;
    case OpenHardWare:
        nRet = MV_CC_SetEnumValue(m_handle, "TriggerMode", 1);  // 硬件触发模式
        if (MV_OK == nRet) nRet = MV_CC_SetEnumValue(m_handle, "TriggerSource", 0);
        if (MV_OK == nRet) nRet = MV_CC_SetEnumValue(m_handle, "TriggerActivation", 0);
        break;
    }
    if (MV_OK != nRet) {
        setLastErrorMsg(tc("设置触发模式失败, 错误码: %1").arg(nRet));
    }
}

4. 图像采集与显示

4.1 图像采集回调

通过注册图像回调函数 ImageCallBack,将采集到的图像数据转换为 OpenCV 的 cv::Mat 格式,然后显示在 Qt 的 QLabel 中。

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

    cv::Mat srcImage;
    switch (pFrameInfo->enPixelType) {
    case PixelType_Gvsp_Mono8:
        srcImage = cv::Mat(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC1, pData);  // 单通道灰度
        break;
    case PixelType_Gvsp_RGB8_Packed:
        RGB2BGR(pData, pFrameInfo->nWidth, pFrameInfo->nHeight);  // RGB 转 BGR
        srcImage = cv::Mat(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC3, pData);
        break;
    case PixelType_Gvsp_BayerRG8:
        cv::Mat bayerImage(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC1, pData);
        cv::cvtColor(bayerImage, srcImage, cv::COLOR_BayerRG2BGR);
        break;
    }

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

void MainWindow::detect(const cv::Mat &image) {
    ui->lab_image->setPixmap(QPixmap::fromImage(MatToQImage(image)).scaled(ui->lab_image->size()));
}
4.2 图像格式转换

使用 MatToQImage 函数将 OpenCV 的 cv::Mat 格式图像转换为 Qt 的 QImage 格式,以便在 QLabel 中显示。

QImage MatToQImage(const cv::Mat &mat) {
    switch (mat.type()) {
        case CV_8UC1:
            return QImage(mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_Grayscale8).copy();
        case CV_8UC3: {
            cv::Mat rgbMat;
            cv::cvtColor(mat, rgbMat, cv::COLOR_BGR2RGB);  // BGR 转 RGB
            return QImage(rgbMat.data, rgbMat.cols, rgbMat.rows, static_cast<int>(rgbMat.step), QImage::Format_RGB888).copy();
        }
        case CV_8UC4:
            return QImage(mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_ARGB32).copy();
        default:
            throw std::runtime_error("Unsupported Mat format");
    }
}

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 (MV_OK != nRet) {
        setLastErrorMsg(tc("关闭相机失败, 错误码: %1").arg(nRet));
        return;
    }
}

6. 总结

本代码实现了基于 Qt 和 OpenCV 的相机操作,借助 Qt 的信号槽机制和 OpenCV 的图像处理能力,完成了从相机图像采集到显示的完整流程。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部