如何使用 OpenCV 解决图像处理相机 IO 延迟

Posted

技术标签:

【中文标题】如何使用 OpenCV 解决图像处理相机 IO 延迟【英文标题】:How to solve image processing camera IO delay with OpenCV 【发布时间】:2019-03-21 04:14:05 【问题描述】:

我有一个这样工作的 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,但它不是......

【问题讨论】:

是的,想法是对的。 @Nuzhny 我添加了两个演示代码,请你看看哪个是正确的。 我不确定这种方法是否可行。它需要为N帧设置捕获顺序并处理N-1帧。 @Nuzhny 我测试了两者,第一个工作,但第二个没有。我只需要最新的,所以没有为 N 帧使用队列。我提到***.com/questions/30032063/… 认为grab 应该和read 一样工作,但事实并非如此。 在我的 Ubuntu 上,第二个测试也有效。但我不确定它是否可以在没有丢帧的情况下正常工作?第二 - cv::VideoCapture 不是线程安全类。 【参考方案1】:

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

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

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

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

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

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

【讨论】:

以上是关于如何使用 OpenCV 解决图像处理相机 IO 延迟的主要内容,如果未能解决你的问题,请参考以下文章

如何使用opencv将鱼眼相机拍摄的图像转换为平面(矩形)图像?

OpenCV - 如何在 Android 中设置全屏相机视图?

如何使用opencv查找从相机拍摄的图像中可用的面部数量?

OpenCV:图像稳定

如何利用opencv计算图像畸变系数,并进行校正与摄像机标定?

使用来自 OpenCV 的转换矩阵手动进行图像校准