gpt4 book ai didi

c++ - 如何使用 cv::parallel_for_ 减少执行时间

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:16:54 24 4
gpt4 key购买 nike

我使用 OpenCV 创建了一个图像处理算法,目前我正在尝试提高我自己的简单函数的时间效率,该函数类似于 LUT,但在值之间进行插值 (double calibRI::corr(double ))。我根据 OpenCV docs 优化了像素循环.

非并行函数(calib(cv::Mat) - calibRI 仿函数类的对象)大约需要 0.15 秒。我决定使用 cv::parallel_for_ 来缩短它。首先,我将其实现为图像平铺 - 根据 >> this文档。时间减少到 0.12 秒(4 个线程)。

    virtual void operator()(const cv::Range& range) const
{
for(int i = range.start; i < range.end; i++)
{
// divide image in 'thr' number of parts and process simultaneously
cv::Rect roi(0, (img.rows/thr)*i, img.cols, img.rows/thr);
cv::Mat in = img(roi);
cv::Mat out = retVal(roi);
out = calib(in); //loops over all pixels and does out[u,v]=calibRI::corr(in[u,v])
}

我虽然为子图像/tiles/ROIs 并行运行我的函数还不是最优的,所以我实现如下:

template <typename T>
class ParallelPixelLoop : public cv::ParallelLoopBody
{
typedef boost::function<T(T)> pixelProcessingFuntionPtr;
private:
cv::Mat& image; //source and result image (to be overwritten)
bool cont; //if the image is continuous
size_t rows;
size_t cols;
size_t threads;
std::vector<cv::Range> ranges;
pixelProcessingFuntionPtr pixelProcessingFunction; //pixel modif. function
public:
ParallelPixelLoop(cv::Mat& img, pixelProcessingFuntionPtr fun, size_t thr = 4)
: image(img), cont(image.isContinuous()), rows(img.rows), cols(img.cols), pixelProcessingFunction(fun), threads(thr)
{
int groupSize = 1;
if (cont) {
cols *= rows;
rows = 1;
groupSize = ceil( cols / threads );
}
else {
groupSize = ceil( rows / threads );
}

int t = 0;
for(t=0; t<threads-1; ++t) {
ranges.push_back( cv::Range( t*groupSize, (t+1)*groupSize ) );
}
ranges.push_back( cv::Range( t*groupSize, rows<=1?cols:rows ) ); //last range must be to the end of image (ceil used before)
}

virtual void operator()(const cv::Range& range) const
{
for(int r = range.start; r < range.end; r++)
{
T* Ip = nullptr;
cv::Range ran = ranges.at(r);
if(cont) {
Ip = image.ptr<T>(0);
for (int j = ran.start; j < ran.end; ++j)
{
Ip[j] = pixelProcessingFunction(Ip[j]);
}
}
else {
for(int i = ran.start; i < ran.end; ++i)
{
Ip = image.ptr<T>(i);
for (int j = 0; j < cols; ++j)
{
Ip[j] = pixelProcessingFunction(Ip[j]);
}
}
}
}
}
};

然后我在 1280x1024 64FC1 图像、i5 处理器、Win8 上运行它,并使用以下代码在 0.4s 范围内运行时间:

double t = cv::getTickCount();
ParallelPixelLoop<double> loop(V,boost::bind(&calibRI::corr,this,_1),4);
cv::parallel_for_(cv::Range(0,4),loop);
std::cout << "Exec time: " << (cv::getTickCount()-t)/cv::getTickFrequency() << "s\n";

我不知道为什么我的实现比迭代子图像中的所有像素慢得多...我的代码中是否存在错误或 OpenCV ROI 以某种特殊方式进行了优化?我不认为存在时间测量错误问题,如所述here .我正在使用 OpenCV 时间函数。

有没有其他方法可以减少这个函数的时间?

提前致谢!

最佳答案

通常很难说为什么使用 cv::parallel_for 无法加速整个过程。一种可能是问题与处理/多线程无关,而是与时间测量有关。大约 2 个月前,我尝试优化 this算法,我注意到了一件奇怪的事情——我第一次使用它需要 x 毫秒,但是如果使用它第二次、第三次……时间(当然没有重新启动应用程序)它需要大约 x/2(甚至 x/3 ) 小姐。我不确定是什么导致了这种行为 - 很可能(在我看来)它是由分支预测引起的 - 当代码第一次执行时,分支预测器“学习”通常采用哪些路径,因此下次它可以预测采用哪个分支(通常猜测是正确的)。您可以阅读更多相关信息 here - 这是一个非常好的问题,它可以让您大开眼界,了解一些非常重要的事情。

所以,在你的情况下,我会尝试一些事情:

  • 多次测量 - 100 或 1000 应该足够(如果需要 0.12-0.4 秒,则不会花费太多时间)并查看您的代码的最新版本是否仍然是最慢的版本。所以只需用这个替换你的代码:

    双 t = cv::getTickCount();
    for (unsigned int i=0; i<1000; i++) {
    ParallelPixelLoop loop(V,boost::bind(&calibRI::corr,this,_1),4);
    cv::parallel_for_(cv::Range(0,4),loop);

    std::cout << "执行时间:"<< (cv::getTickCount()-t)/cv::getTickFrequency() << "s\n";

  • 在更大的图像上测试它。也许在您的情况下您只是“不需要”4 个内核,但在更大的图像中,4 个内核会产生积极的影响。

  • 使用分析器(例如 Very Sleepy)查看代码的哪一部分是关键的

关于c++ - 如何使用 cv::parallel_for_ 减少执行时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29625510/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com