c++ - 将代码移动到 Opencv cv::ParallelLoopBody

标签 c++ opencv

我有这个 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/

相关文章:

c++ - 什么是 “pch.h”,为什么需要将其作为第一个头文件包含在内?

c++ - 如果有虚方法,是否要创建vtable?

c++ - 仅读取数字的 scanf 格式说明符

c++ - PCC-S-02015,无法打开包含文件

image-processing - openCV 中 Unresolved external symbol 错误

c++ - 如何显示窗口大小不同的输出图像?通过使用 cv::Mat

opencv - 为什么我们使用SURF描述符?

c++ - 获取用户定义类的实例

image-manipulation - OpenCV:如何旋转 IplImage?

Visual Studio 中的 C++ 和 OpenCV 退出并出现代码 -1 (0xffffffff) 错误