You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCV跨线程捕获的cv::Mat帧无法执行写入绘制操作的问题

问题诱因
  1. cv::Mat浅拷贝导致内存共享与数据覆写
    cv::Mat的赋值、拷贝构造默认都是浅拷贝,仅复制头信息,指向同一块像素数据内存。你代码中Camera类的captureVideo方法返回的是类成员frame,子线程采集时每次调用cap >> frame都会覆写同一块内存,而你往frameStack里push的frame本质都指向这块内存。主线程刚拿到contour准备绘制时,子线程已经将该内存块的内容替换成了新的采集帧,绘制操作相当于画在了马上要被丢弃的内存上,自然看不到效果。
  2. 多线程无锁访问导致数据竞争
    全局的frameStack和停止信号stopSig都没有加互斥保护,子线程增删帧、主线程读取帧的操作会同时发生,可能出现你读取到的帧是不完整的、或者容器结构被破坏的情况,进一步导致绘制失效,严重时会触发程序崩溃。
  3. 缓冲区逻辑混乱
    你现有逻辑中缓冲区超过2帧就pop末尾、满20帧就清空全量缓冲的逻辑非常不合理,会频繁出现缓冲被清空、主线程拿不到稳定帧的情况,也会加剧上述两个问题的出现概率。
修复方案
  • 强制帧数据深拷贝:子线程往缓冲区存帧时,调用clone()方法生成独立的帧副本,避免共享同一块采集内存:
// 修改grabFrame中的push逻辑
::frameStack.push_back(frame.clone());
  • 加互斥锁保护共享资源:定义全局互斥锁,所有操作frameStack、stopSig的位置都要加锁:
// 全局添加互斥锁定义
std::mutex frameMutex;

子线程操作缓冲时加锁:

void grabFrame(void) {
    Mat frame;
    std::lock_guard<std::mutex> lock(frameMutex);
    ::frameStack.clear();
    lock.unlock();

    while(!::stopSig) {
        frame = ::cam1.captureVideo();
        std::lock_guard<std::mutex> opLock(frameMutex);
        // 操作frameStack的代码都放在锁区间内
        if(::frameStack.size() >= ::frameBuffer) {
            ::frameStack.erase(::frameStack.begin()); // 弹出最旧的帧,不要全清
        }
        ::frameStack.push_back(frame.clone());
    }
    return;
}

主线程读取帧时加锁:

while(1) {
    Mat contour;
    {
        std::lock_guard<std::mutex> lock(frameMutex);
        if(::frameStack.size() >= 2)  {
            contour = ::frameStack.back().clone(); // 再拷贝一份,避免锁释放后数据被修改
        }
    }
    // 锁释放后再执行绘制、显示操作,避免锁占用时间过长影响采集
    if(!contour.empty()) {
        circle(contour, Point(150,150),50, Scalar(0,255,255),cv::FILLED, 8);
        putText(contour, "some text", Point(100,100), FONT_HERSHEY_DUPLEX, 1, Scalar(0,143,143), 2);
        imshow("Contour Video", contour);
    }
    // 退出逻辑加锁
    if (waitKey(1) == 27) 
    {
        std::lock_guard<std::mutex> lock(frameMutex);
        ::stopSig = 1;
        frameStack.clear();
        break; 
    }
}
  • 优化缓冲区逻辑:将缓冲区改为先进先出的环形缓冲,满了就弹出最旧的首帧,不要直接清空整个缓冲区,保证主线程始终能拿到最新的几帧数据。

内容的提问来源于stack exchange,提问作者fisakhan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 09:12:07