Qt 与Halcon联合开发七: 多线程图像处理架构设计(附源码)

一、引言

在工业视觉项目中,我们经常面临两个矛盾:

  • 相机采集线程(如海康 SDK 的回调函数)需要高速、连续获取图像;
  • 图像处理逻辑往往较复杂(如 Halcon 识别、定位、测量),处理耗时较长。

若两者直接耦合,容易出现卡顿、数据丢失、资源争用。因此,我们采用一种典型的并发编程方案——生产者-消费者模型,并结合 Qt 多线程与 Halcon 图像接口,实现高性能、高稳定性的视觉系统架构

容器类源码下载

📦 ImageData 类源码(含 .h 和 .cpp 文件)

通过网盘分享的文件:Qt 与Halcon联合开发七: 多线程图像处理架构设计
链接: https://pan.baidu.com/s/1PRRBlfkZEapBLTYTFrlAJA?pwd=jkcf 提取码: jkcf


二、系统架构概览

模块划分

  1. 海康 SDK 采集回调线程(生产者)
  2. ImageData 图像缓存容器(缓存缓冲区)
  3. 图像处理线程(Halcon算法)(消费者)
  4. Qt GUI 主界面(控制、展示)

数据流动图

[海康回调线程]
       ↓ addImageData()
[ImageData 缓存队列]
       ↑ getImageData()
[Halcon 图像处理线程]
       ↑
[Qt 控制/展示界面]

三、图像容器类 ImageData 设计

ImageData 类是图像采集和处理之间的中转站,设计目标如下:

设计需求实现方式
线程安全每个队列绑定 QMutex
多缓存队列支持多个相机或并行任务
等待/唤醒机制使用 QWaitCondition
状态反馈支持处理慢、失败等情况返回
异常信息追踪getLastErrorMsg() 提供错误信息

结构定义

class ImageData {
public:
    enum class ImageDataDistributionMode { ByOrder, ByUser };
    enum ObtainImageDataResultStatus {
        NoImageData,
        ExistDataButObtainFailed,
        ExistDataButObtainWithProblem,
        ExistDataAndObtainSucced
    };

    void setImageDataQueneNumber(int num = 1);
    bool addImageData(int index, const HalconCpp::HObject& ho_Image);
    int getImageData(int index, HalconCpp::HObject* ho_Image);
    int distributeImageDataQuene(ImageDataDistributionMode mode = ImageDataDistributionMode::ByOrder);
    void clearImageData();
    void wakeUp(int index);
    void wait(int index);
    QString getLastErrorMsg() const;

private:
    QList<QList<HalconCpp::HObject>> m_images;
    QList<QMutex*> m_mutexs;
    QList<QWaitCondition*> m_waits;
    QList<QMutex*> m_waitMutexs;
    int m_num;
    unsigned int m_flag;
    QString m_lastErrorMsg;
};

四、图像采集线程(生产者)实现

海康工业相机使用回调机制采集图像数据,以下为图像采集回调函数 ImageCallBack 的核心代码:

void ImageCallBack(unsigned char* pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser) {
    HikCamera* camera = static_cast<HikCamera*>(pUser);
    try {
        int ImageWidth = pFrameInfo->nWidth;
        int ImageHeight = pFrameInfo->nHeight;
        HalconCpp::HObject ho_Image;

        switch (pFrameInfo->enPixelType) {
        case PixelType_Gvsp_Mono8:
            HalconCpp::GenImage1(&ho_Image, "byte", ImageWidth, ImageHeight, reinterpret_cast<Hlong>(pData));
            break;
        case PixelType_Gvsp_RGB8_Packed:
            HalconCpp::GenImageInterleaved(&ho_Image, reinterpret_cast<Hlong>(pData), "rgb",
                ImageWidth, ImageHeight, -1, "byte", 0, 0, 0, 0, -1, 0);
            break;
        case PixelType_Gvsp_BayerRG8:
            HalconCpp::GenImage1(&ho_Image, "byte", ImageWidth, ImageHeight, reinterpret_cast<Hlong>(pData));
            HalconCpp::CfaToRgb(ho_Image, &ho_Image, "bayer_rg", "bilinear");
            break;
        default:
            HalconCpp::GenImageConst(&ho_Image, "byte", ImageWidth, ImageHeight);
            break;
        }

        if (!camera->getImageData()->addImageData(0, ho_Image))
            camera->sendErrorsMsgs(camera->getImageData()->getLastErrorMsg());
    } catch (const HalconCpp::HException&) {
        camera->sendErrorsMsgs(tc("C25: 图像数据转换失败"));
    }
}

说明:

  • 根据不同像素格式构建 Halcon 图像;
  • 通过 addImageData() 存入图像容器;
  • 支持 Bayer 格式自动去马赛克;
  • 回调函数中不执行耗时逻辑,快速返回。

五、图像处理线程(消费者)实现

图像处理线程不断尝试从 ImageData 中获取图像:

while (m_isRun) {
    HalconCpp::HObject ho_Image;
    switch (m_imgData->getImageData(m_imgIndex, &ho_Image)) {
    case ImageData::NoImageData:
        m_imgData->wait(m_imgIndex);
        continue;
    case ImageData::ExistDataButObtainFailed:
        emit errors(m_cameraIndex, m_imgData->getLastErrorMsg());
        m_isRun = false;
        continue;
    case ImageData::ExistDataButObtainWithProblem:
        emit warnings(m_cameraIndex, m_imgData->getLastErrorMsg());
        break;
    case ImageData::ExistDataAndObtainSucced:
        break;
    }
    processWithHalcon(ho_Image);  // 图像算法处理
}

说明:

  • 无图像时调用 wait(),自动挂起,节省 CPU;
  • 获取失败时可输出错误,便于故障诊断;
  • 获取成功后调用图像处理函数;
  • 支持线程终止中断(通过 m_isRun 控制)。

六、状态码说明(接口健壮性)

状态值含义处理建议
NoImageData缓存为空可等待或跳过
ExistDataButObtainFailed图像出错输出日志,跳出线程
ExistDataButObtainWithProblem图像堆积处理慢,可能性能瓶颈
ExistDataAndObtainSucced成功获取图像正常处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客晨风

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值