c++ - 在 OpenCV 中使用多线程访问 Mat 是线程安全的吗?

标签 c++ opencv parallel-processing

我想加速一种算法(具有圆形邻居的完整局部二进制模式),为此我遍历所有像素并用它的邻居计算一些东西(所以我需要邻居像素访问)。

目前,我通过使用一个线程/进程遍历所有像素来实现这一点。我想通过将输入图像分成多个 ROI 并分别计算每个 ROI(使用多个线程)来并行化此任务。

这里的问题是,ROI 是重叠的(因为要计算一个像素,有时我需要看远处的邻居)并且可能有多个线程访问像素数据(阅读)在同一时间。如果两个或多个线程同时读取相同索引的相同 Mat,这是一个问题吗?

如果我并行写入同一个 Mat 但索引不同,这也是一个问题吗?

最佳答案

通常,并行读取不是问题,因为 cv::Mat 只是一个很好的数组包装器,就像 std::vector (是的,有差异,但我看不出它们会如何影响这里的主题,所以我将忽略它们)。但是,并行化不会自动提升性能。这里有很多事情需要考虑:

创建线程会占用大量资源,如果任务相对较短(就计算时间而言)可能会产生很大的负面影响,因此必须考虑线程池。

如果您编写高性能代码(无论是多线程还是单线程),您应该了解硬件的工作原理。在这种情况下:内存和 CPU。有一个 very good talk来自 CppCon 2016 的 Timur Doumler 关于该主题。这应该可以帮助您避免缓存未命中。

另外值得一提的是编译器优化。打开它。我知道这听起来非常明显,但是 SO 上有很多人询问有关性能的问题,但他们不知道什么是编译器优化。

最后,还有 OpenCV 透明 API (TAPI),它基本上利用 GPU 而不是 CPU。几乎所有 OpenCV 的内置算法都支持 TAPI,您只需传递一个 cv::UMat 而不是 cv::Mat。这两种类型可以相互转换。但是,转换非常耗时,因为 UMat 基本上是 GPU 内存 (VRAM) 上的一个数组,这意味着每次转换时都必须复制它。访问 VRAM 的时间也比访问 RAM 的时间长(对于 CPU 而言)。 但是,您必须记住,如果不将 VRAM 数据复制到 RAM,则无法使用 CPU 访问 VRAM 数据。这意味着如果您使用 cv::UMat,则无法迭代像素。仅当您编写自己的 OpenCL 或 Cuda 代码以便您的算法可以在 GPU 上运行时才有可能。

在大多数消费级 PC 中,对于滑动窗口算法(基本上是遍历像素并围绕每个像素执行计算的任何算法),使用 GPU 通常是迄今为止最快的方法(但也需要最多的努力来实现) .当然,这仅在数据缓冲区(您的图像)足够大以使其值得复制到 VRAM 和从 VRAM 复制时才成立。

对于平行书写:只要没有重叠区域,通常是安全的。但是,缓存未命中和 false sharing (正如 NathanOliver 所指出的)是需要考虑的问题。

关于c++ - 在 OpenCV 中使用多线程访问 Mat 是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57420290/

相关文章:

python - 使用 PyCUDA 后无输出

c++ - VS2010 可以显示哪个头文件拉入声明吗?

c++ - 如何从 OpenCV 中的目录中按顺序读取文件?

python - 如何分离等于阈值的灰度图像区域?

opencv - 如何将网络摄像头录制到 X11 之外的文件中?

algorithm - paranthesized 字符串并行处理的有效性

c++ - 有没有办法简单地连接多个 vector ?

c++ - 访问以指针类型为键的 std::map

python - OpenCV断言失败,并带有负值

c# - 如何在 C# 控制台应用程序、.NET 4.5 中实现并发调用?