首先,谢谢你澄清了这个问题。
问:
在OpenCV的应用程序级别上使用(多)线程可以吗?
答:
是的,在OpenCV的应用程序级别上使用多线程是完全可以的,除非并且直到您使用可以利用多线程的函数,例如模糊、颜色空间变化,在这里,您可以将图像分割成多个部分,并在分割的部分应用全局函数,然后重新组合它以给出最终输出。
在Hough、pca_分析等函数中,如果将其应用于分割的图像区域,然后重新组合,则无法给出正确的结果,因此在应用程序级对这些函数应用多线程可能无法给出正确的结果,因此不应执行。
正如±1所提到的,您的多线程实现不会给您带来优势,因为您将线程连接到for循环本身中。我建议您使用promise和future对象(如果您想要一个如何使用的示例,请在评论中让我知道,我将分享这个片段)。
下面的答案需要大量的研究,谢谢你的提问,它真的帮助我增加了我的多线程知识的信息:)
如果是,为什么我的程序打印的时间跨度会随着时间而增长?
经过大量的研究,我发现创建和销毁线程需要大量的CPU和内存资源。当我们初始化一个线程时(在您的代码中:
thread t(blurSlowdown, nullptr);
)一个标识符被写入这个变量指向的内存位置,这个标识符使我们能够引用线程。现在,在您的程序中,您正在以非常高的速度创建和销毁线程,现在发生的情况是,有一个线程池分配给一个程序,通过它,我们的程序可以运行和销毁线程,我将保持它的简短,让我们看一下下面的解释:
-
-
当您销毁线程时,此内存将被释放
但是
-
当您在第一个线程没有被破坏之后再次创建一个线程时,这个新线程的标识符指向
新位置
(上一个线程以外的位置)在线程池中。
-
在反复创建和销毁线程之后
线程池已耗尽
CPU被迫将我们的程序周期放慢一点,以便线程池再次被释放
为新的线腾出空间。
问:
2019年的TBB现在是否得到广泛支持?
是的,您可以在OpenCV程序中利用TBB,同时在构建OpenCV时启用TBB支持。
以下是在medianBlur中实现TBB的程序:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <chrono>
using namespace cv;
using namespace std;
using namespace std::chrono;
class Parallel_process : public cv::ParallelLoopBody
{
private:
cv::Mat img;
cv::Mat& retVal;
int size;
int diff;
public:
Parallel_process(cv::Mat inputImgage, cv::Mat& outImage,
int sizeVal, int diffVal)
: img(inputImgage), retVal(outImage),
size(sizeVal), diff(diffVal)
{
}
virtual void operator()(const cv::Range& range) const
{
for(int i = range.start; i < range.end; i++)
{
/* divide image in 'diff' number
of parts and process simultaneously */
cv::Mat in(img, cv::Rect(0, (img.rows/diff)*i,
img.cols, img.rows/diff));
cv::Mat out(retVal, cv::Rect(0, (retVal.rows/diff)*i,
retVal.cols, retVal.rows/diff));
cv::medianBlur(in, out, size);
}
}
};
int main()
{
VideoCapture cap(0);
cv::Mat img, out;
while(1)
{
cap.read(img);
out = cv::Mat::zeros(img.size(), CV_8UC3);
// create 8 threads and use TBB
auto start1 = high_resolution_clock::now();
cv::parallel_for_(cv::Range(0, 8), Parallel_process(img, out, 9, 8));
//cv::medianBlur(img, out, 9); //Uncomment to compare time w/o TBB
auto stop1 = high_resolution_clock::now();
auto duration1 = duration_cast<microseconds>(stop1 - start1);
auto time_taken1 = duration1.count()/1000;
cout << "TBB Time: " << time_taken1 << "ms" << endl;
cv::imshow("image", img);
cv::imshow("blur", out);
cv::waitKey(1);
}
return 0;
}
在我的机器上,TBB的实现大约需要10毫秒,不带TBB的实现大约需要40毫秒。
如果是,有什么能提供更好的性能,在应用程序级别(如果允许)或TBB/OpenMP上实现多线程?
我建议在POSIX多线程(pthread/thread)上使用TBB/OpenMP,因为TBB提供了更好的线程控制+更好的结构来编写并行代码,并在内部管理pthreads。如果您使用pthreads,那么您必须在代码中注意同步和安全等问题。但是使用这些框架抽象了处理线程的需求,这可能会变得非常复杂。
编辑:
我检查了有关图像尺寸与要分割处理的线程数不兼容的注释。所以这里有一个
解决方法(尚未测试但应该有效),将图像分辨率缩放到兼容的维度,如:
Parallel_process
然后将输出缩小到原始大小458x 647。
this answer