我有这个 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;
}
我正在研究使用 opencv ParallelLoopBody
代码加速我的应用程序,以并行运行每个像素的操作。
我已经添加了这个类:
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::parallel_for_
的 cv::Range
是 [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
的值来计算 x
和 y
。当你的图像有 WIDTH 和 HEIGHT,并且我们知道像素是按行存储的,你可以使用这些公式
x = r % WIDTH (r value of range)
y = r / WIDTH
接下来你应该添加条件来检查像素是否在边界上(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));
}
}
最重要的是你在 vector 上调用 push_back
而无需同步。您应该使用 mutex
来锁定对 vector 的访问。如果您使用的是 C++11,则可以在 operator()
中将 mutex 定义为静态变量
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)。
关于c++ - 将代码移动到 Opencv cv::ParallelLoopBody,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48529393/