首页 > 解决方案 > 如何使用 OpenCV 解决图像处理相机 IO 延迟

问题描述

我有一个像这样工作的 OpenCV 程序:

VideoCapture cap(0);
Mat frame;
while(true) {
  cap >> frame;
  myprocess(frame);
}

问题是如果myprocess花费的时间长于相机的IO间隔,则捕获的帧会延迟,无法获得与实时同步的帧。

所以,我认为要解决这个问题,应该让相机流和myprocess并行运行。一个线程做 IO 操作,另一个做 CPU 计算。当相机完成捕获后,发送到工作线程进行处理。

这个想法对吗?有没有更好的策略来解决这个问题?

演示:

int main(int argc, char *argv[])
{
    cv::Mat buffer;
    cv::VideoCapture cap;
    std::mutex mutex;
    cap.open(0);
    std::thread product([](cv::Mat& buffer, cv::VideoCapture cap, std::mutex& mutex){
        while (true) { // keep product the new image
            cv::Mat tmp;
            cap >> tmp;
            mutex.lock();
            buffer = tmp.clone(); // copy the value
            mutex.unlock();
        }
    }, std::ref(buffer), cap, std::ref(mutex));
    product.detach();

    while (cv::waitKey(20)) { // process in the main thread
        mutex.lock();
        cv::Mat tmp = buffer.clone(); // copy the value
        mutex.unlock();
        if(!tmp.data)
            std::cout<<"null"<<std::endl;
        else {
            std::cout<<"not null"<<std::endl;
            cv::imshow("test", tmp);
        }

    }
    return 0;
}

或者使用线程不断清除缓冲区。

int main(int argc, char *argv[])
{
    cv::Mat buffer;
    cv::VideoCapture cap;
    std::mutex mutex;
    cap.open(0);
    std::thread product([](cv::Mat& buffer, cv::VideoCapture cap, std::mutex& mutex){
        while (true) { // keep product the new image
            cap.grab();
        }
    }, std::ref(buffer), cap, std::ref(mutex));
    product.detach();
    int i;
    while (true) { // process in the main thread
        cv::Mat tmp;
        cap.retrieve(tmp);
        if(!tmp.data)
            std::cout<<"null"<<i++<<std::endl;
        else {
            cv::imshow("test", tmp);
        }
        if(cv::waitKey(30) >= 0) break;
    }
    return 0;
}

我认为第二个演示应该是基于https://docs.opencv.org/3.0-beta/modules/videoio/doc/reading_and_writing_video.html#videocapture-grab的工作,但它不是......

标签: c++opencvparallel-processingcamera

解决方案


在具有多目标跟踪的项目中,我为帧(cv::Mat frames[2])和 2 个线程使用了 2 个缓冲区:

  1. 一个线程用于捕获下一帧并检测对象。

  2. 第二个线程用于跟踪检测到的对象并在框架上绘制结果。

我使用 index = [0,1] 进行缓冲区交换,并且该索引受到互斥锁的保护。对于工作结束的信号,使用了 2 个条件变量。

首先使用帧 [capture_ind] 缓冲区使用 CatureAndDetect,然后使用以前的帧 [1-capture_ind] 缓冲区进行跟踪。下一步 - 切换缓冲区:capture_ind = 1 - capture_ind。

你可以在这里做这个项目吗:Multitarget-tracker


推荐阅读