如何解决图像处理导致相机io延迟的问题?

时间:2019-03-21 04:14:05

标签: opencv parallel-processing camera

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

2 个答案:

答案 0 :(得分:0)

通过线程进行IO操作来提高性能,而另一个线程进行CPU计算的想法是一种经典策略。除了SystemErr R java.net.SocketException: Connection reset SystemErr R at java.net.SocketInputStream.read(SocketInputStream.java:220) SystemErr R at java.net.SocketInputStream.read(SocketInputStream.java:152) SystemErr R at com.ibm.jsse2.a.a(a.java:79) SystemErr R at com.ibm.jsse2.a.a(a.java:182) SystemErr R at com.ibm.jsse2.as.a(as.java:883) SystemErr R at com.ibm.jsse2.as.i(as.java:969) SystemErr R at com.ibm.jsse2.as.a(as.java:680) SystemErr R at com.ibm.jsse2.as.startHandshake(as.java:859) SystemErr R at com.ibm.ws.ssl.config.WSSocket.startHandshake(WSSocket.java:414) SystemErr R at com.ibm.net.ssl.www2.protocol.https.c.afterConnect(c.java:16) SystemErr R at com.ibm.net.ssl.www2.protocol.https.d.connect(d.java:44) SystemErr R at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1561) SystemErr R at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1489) SystemErr R at com.ibm.net.ssl.www2.protocol.https.b.getInputStream(b.java:93) SystemErr R at java.net.URL.openStream(URL.java:1057) 是CPU处理延迟之外,cv2.VideoCapture().read()是一种阻塞操作,因此您的主程序可能会遇到I / O延迟,并且在等待新帧时必须停止任何处理。通过使用单独的专用线程,您的程序可以在 parallel 中运行,而不是依靠单个线程以顺序顺序抓取帧和处理帧。

您可以将IO线程中的所有帧存储到队列中,而处理线程只需读取并处理队列中的最新帧,而不会出现任何延迟问题。

答案 1 :(得分:0)

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

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

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

我使用index = [0,1]进行缓冲区交换,并且此索引受互斥锁保护。为了通知工作结束,使用了两个条件变量。

CatureAndDetect首先使用frame [capture_ind]缓冲区,而Tracking使用先前的frame [1-capture_ind]缓冲区。下一步-切换缓冲区:capture_ind = 1-capture_ind。

您可以在这里进行这个项目吗:Multitarget-tracker