将代码移动到 Opencv cv::P arallelLoopBody

Moving code to Opencv cv::ParallelLoopBody

本文关键字:arallelLoopBody cv Opencv 代码移动      更新时间:2023-10-16

我有这个opencv函数:

static std::vector<cv::Point> findBoundaryPixels(const cv::Mat_<uchar> &trimap, int a, int b)
{
std::vector<cv::Point> result;
for (int x = 1; x < trimap.cols - 1; ++x)
for (int y = 1; y < trimap.rows - 1; ++y)
{
if (trimap(y, x) == a)
{
if (trimap(y - 1, x) == b ||
trimap(y + 1, x) == b ||
trimap(y, x - 1) == b ||
trimap(y, x + 1) == b)
{
result.push_back(cv::Point(x, y));
}
}
}

return result;
}

我正在考虑使用 OpenCVParallelLoopBody代码加速我的应用程序,以并行运行每个像素的操作。

我添加了这个类:

class Parallel_process : public cv::ParallelLoopBody
{
private:
cv::Mat trimap;
int a;
int b;
std::vector<cv::Point>& result;
public:
Parallel_process(cv::Mat inputImgage, std::vector<cv::Point>& presult, int aa, int bb)
: trimap(inputImgage), result(presult), a(aa), b(bb) {}
virtual void operator()(const cv::Range& range) const
{
for (int i = range.start; i < range.end; i++)
{
int x = i / trimap.cols;
int y = i / trimap.rows;
if (trimap.at<uchar>(y, x) == a)
{
if (trimap.at<uchar>(y - 1, x) == b ||
trimap.at<uchar>(y + 1, x) == b ||
trimap.at<uchar>(y, x - 1) == b ||
trimap.at<uchar>(y, x + 1) == b)
{
result.push_back(cv::Point(x, y));
}
}
}
}
};

并调整了函数,使其显示为:

static std::vector<cv::Point> findBoundaryPixels(const cv::Mat_<uchar> &trimap, int a, int b)
{
std::vector<cv::Point> result;
// create 8 threads and use TBB
cv::parallel_for_(cv::Range(0, 8), Parallel_process(trimap, result, a, b));
return result;
}

但是,这会使我的应用程序崩溃。我试图遵循文档,如下所示:

https://docs.opencv.org/trunk/d7/dff/tutorial_how_to_use_OpenCV_parallel_for_.html

但显然失败了。我哪里出错了?

谢谢。

在教程输入cv::Range中,cv::parallel_for_[0, img.cols * img.width],您应该以相同的方式执行此操作。此输入范围被拆分为较小的范围,并作为 operator() 的参数传递,由线程执行。

所以你应该打电话

cv::parallel_for_(cv::Range(0, trimap.cols * trimap.rows), Parallel_process(trimap, result, a, b));

void operator()(const cv::Range& range)中,您应该使用range的值来计算xy。当您的图像具有宽度和高度,并且我们知道像素存储在行中时,您可以使用这些公式

x = r % 宽度(范围的 r 值)

y = r/宽度

接下来,您应该添加条件来检查像素是否在边框上(x == 0、y == 0 等)

int x = i % trimap.cols;
int y = i / trimap.cols;

if (x == 0 || y == 0 || x == trimap.cols-1 || y == trimap.rows-1)
continue;
if (trimap.at<uchar>(y, x) == a)
{
if (trimap.at<uchar>(y - 1, x) == b ||
trimap.at<uchar>(y + 1, x) == b ||
trimap.at<uchar>(y, x - 1) == b ||
trimap.at<uchar>(y, x + 1) == b)
{
// ---> result.push_back(cv::Point(x, y));
}
}

以及您在不同步的情况下在矢量上调用push_back的最重要的事情。您应该使用mutex来锁定对矢量的访问。如果您使用的是 C++11,则可以将operator()中的互斥锁定义为静态变量

static cv::Mutex mtx;
mtx.lock();
result.push_back(cv::Point(x,y));
mtx.unlock();

当您使用比 C++11 更早的版本时,您可以在Parallel_process中保留对互斥锁(必须在调用cv::parallel_for_之前创建)的引用,并在其上调用锁定/解锁。

在教程中不需要同步,因为创建了输出 cv::Mat,并且对于范围的每个值,写入不同的像素 (x,y)。