【问题标题】:Why do I get corrupted results if I run GPU dense optical flow algorithm concurrently?如果我同时运行 GPU 密集光流算法,为什么会得到损坏的结果?
【发布时间】:2020-03-23 08:22:02
【问题描述】:

在并行使用 OpenCV CUDA 密集光流时,我注意到 有时我会得到损坏的光流结果,尽管我在不同的 cuda::GpuMats 和单独的 cuda::Streams 上运行它并带有单独的 @ 987654330@ 个实例。

在对代码进行一些实验后,我发现如果我用mutex 保护DenseOpticalFlow::calc() 调用或只运行一个线程,我总是得到正确(未损坏)的结果。

我将我的代码缩减为最小的可重现示例,其中我在多个线程中对相同的输入图像多次运行光流算法:

#include <thread>
#include <vector>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    Mat frames[2] = { imread("im0.jpg"), imread("im1.jpg") };
    for (int i = 0; i < 2; i++) cvtColor(frames[i], frames[i], COLOR_BGR2GRAY);
    Size frameSize = frames[0].size();

    vector<thread> workers;
    mutex m;

    for (int id = 0; id < 2; ++id) // 2 threads
        workers.emplace_back([&, id]()
    { // lambda
        // Separate Stream, Algorithm and GpuMats for each thread
        auto algoGpu = cuda::OpticalFlowDual_TVL1::create();
        cuda::Stream stream; 
        cuda::GpuMat optFlow(frameSize, CV_32FC2);
        cuda::GpuMat gpuFrame[2] = {
            cuda::GpuMat(frameSize, CV_8UC1),
            cuda::GpuMat(frameSize, CV_8UC1) 
        };
        Mat downloaded, converted;
        Mat channels[2] = { Mat(), Mat() };

        for (int i = 0; i < 2; ++i) gpuFrame[i].upload(frames[i], stream);

        for (int i = 0; i < 1000; i++) { // run 1000 times with SAME input
            {
                //unique_lock<mutex> l(m); // WORKS OK IF UNCOMMENTED !!!!!
                algoGpu->calc(gpuFrame[0], gpuFrame[1], optFlow, stream);
            }

            if (id == 0) { // show results from same single thread
                optFlow.download(downloaded, stream);
                stream.waitForCompletion();

                split(downloaded, channels);
                channels[0].convertTo(converted, CV_8UC1, 100, 128);
                imshow("flow", converted);
                waitKey(1);
            }
        }

        stream.waitForCompletion();
    });

    for (auto& worker : workers) worker.join();
    return 0;
}

如果我取消注释 //unique_lock&lt;mutex&gt; l(m);,每次调用都会得到相同的有效结果图像。但如果我留下评论,大约一半的结果会损坏。

输入图像:

正确结果:

损坏结果示例:

我使用 OpenCV 4.0 和 CUDA 10.1。

【问题讨论】:

  • 显然有一个竞争条件,你可以通过使用锁来避免。你问的是这个吗?
  • @mkrieger1,不,我在问我为什么需要那个锁?为什么会有竞态条件?
  • 请参阅此链接上的详细说明注释部分。 docs.opencv.org/master/d9/df3/classcv_1_1cuda_1_1Stream.html 这似乎暗示用不同的数据调用相同的 API(就像你在调用 calc(...) 时所做的那样,可能会导致 GPU 内存在前一个任务完成之前被其他异步任务更新的问题) .
  • 我的同事将此发布到 OpenCV 存储库并被标记为错误:github.com/opencv/opencv/issues/16013
  • 这是一个典型的问题:最小,切中要害,完全可重现。赞!你的贡献导致了一个错误被修复。感谢您为我们所有人改进 OpenCV 所做的努力!签署后,一个用户大约一个月后就不得不运行并行光流问题了。你救了我一些头痛!

标签: c++ multithreading opencv


【解决方案1】:

此问题现已由 this PR 解决,并将反映在 OpenCV 的下一版本中。

【讨论】:

    猜你喜欢
    • 2011-08-11
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 2021-07-10
    • 2021-12-22
    • 2022-06-23
    相关资源
    最近更新 更多