opencv的并行处理cv::ParallelLoopBody

opencv的并行处理cv::ParallelLoopBody

0.引言

1.cv::ParallelLoopBody

  • 在 OpenCV 中,使用 cv::parallel_for_ 函数进行多线程处理。这个函数接受一个 cv::Range 对象和一个 cv::ParallelLoopBody 对象作为参数。cv::Range 表示要处理的数据范围,cv::ParallelLoopBody 表示要执行的任务。
  • cv::ParallelLoopBody 是 OpenCV 中的一个类,用于多线程处理图像或视频数据。它是一个纯虚类,需要子类继承并实现它的 operator() 函数。
  • 在执行 cv::parallel_for_ 函数时,OpenCV 会将数据范围分成多个子范围,并创建多个线程来执行 cv::ParallelLoopBody 中的任务。每个线程负责处理其中一个子范围。当所有线程都完成任务后,cv::parallel_for_ 函数才会返回。

因此,cv::ParallelLoopBody 的作用就是实现并行处理算法,以提高图像或视频处理的速度。它可以在 OpenCV 中使用多线程来处理大量数据,从而使算法更加高效。

2.demo1

#include <functional>
#include <iostream>
#include <opencv2/opencv.hpp>

class GrayscaleTransform : public cv::ParallelLoopBody {
 public:
  GrayscaleTransform(cv::Mat &image) : img(image) {}

  virtual void operator()(const cv::Range &range) const {
    for (int r = range.start; r < range.end; ++r) {
      for (int c = 0; c < img.cols; ++c) {
        cv::Vec3b &pixel = img.at<cv::Vec3b>(r, c);
        uchar gray = cv::saturate_cast<uchar>(
            0.299 * pixel[2] + 0.587 * pixel[1] + 0.114 * pixel[0]);
        pixel[0] = gray;
        pixel[1] = gray;
        pixel[2] = gray;
      }
    }
  }

 private:
  cv::Mat &img;
};

int main() {
  cv::Mat image = cv::imread("../lena.png");
  if (image.empty()) {
    std::cerr << "Failed to read image" << std::endl;
    return 1;
  }
  GrayscaleTransform transform(image);

  cv::parallel_for_(cv::Range(0, image.rows), transform);

  cv::imshow("Grayscale Image", image);
  cv::waitKey(0);
  return 0;
}
  • 例子中,定义了一个 GrayscaleTransform 类,继承自 cv::ParallelLoopBody,并实现了 operator() 函数。在 operator() 函数中,使用 cv::saturate_cast 函数来将每个像素的 RGB 值转换为灰度值,并将其赋值给每个通道。然后,将 GrayscaleTransform 的实例传递给 cv::parallel_for_ 函数,该函数将数据范围划分为多个子范围,并创建多个线程来执行 GrayscaleTransform::operator() 函数。
cv::parallel_for_(cv::Range(0, image.rows), transform);
  • 函数接受两个参数:一个 cv::Range 对象和一个 cv::ParallelLoopBody 对象。

  • cv::Range 表示要处理的数据范围,这里是 cv::Range(0, image.rows),表示从第 0 行到最后一行,这是对整个图像进行处理。

  • transform 是一个 GrayscaleTransform 类的实例,也就是继承了 cv::ParallelLoopBody 类的自定义类,它的 operator() 函数将在多个线程上并行执行。

  • cv::parallel_for_ 函数会将数据范围划分成多个子范围,并创建多个线程来执行 GrayscaleTransform::operator() 函数,从而实现图像的并行处理。

3.demo2

同样的功能,将具体的处理代码解耦到客户端:

#include <fstream>
#include <functional>
#include <iostream>
#include <opencv2/opencv.hpp>

/**
 * @brief Helper class to do OpenCV parallelization
 *
 * This is a utility class required to build with older version of opencv
 * On newer versions this doesn't seem to be needed, but here we just use it to
 * ensure we can work for more opencv version.
 * https://answers.opencv.org/question/65800/how-to-use-lambda-as-a-parameter-to-parallel_for_/?answer=130691#post-id-130691
 */
class LambdaBody : public cv::ParallelLoopBody {
 public:
  explicit LambdaBody(const std::function<void(const cv::Range &)> &body)
      : body_(body) {}
  void operator()(const cv::Range &range) const override { body_(range); }

 private:
  std::function<void(const cv::Range &)> body_;
};

void processImage(cv::Mat &image) {
  // Create a lambda function to transform the image
  auto transform = [&](const cv::Range &range) {
    for (int i = range.start; i < range.end; ++i) {
      // Process image row i here
      for (int c = 0; c < image.cols; ++c) {
        cv::Vec3b &pixel = image.at<cv::Vec3b>(i, c);
        uchar gray = cv::saturate_cast<uchar>(
            0.299 * pixel[2] + 0.587 * pixel[1] + 0.114 * pixel[0]);
        pixel[0] = gray;
        pixel[1] = gray;
        pixel[2] = gray;
      }
    }
  };

  // Create a LambdaBody object and use it to parallelize the image processing
  LambdaBody body(transform);
  cv::parallel_for_(cv::Range(0, image.rows), body);
}

int main() {
  // Load an image
  cv::Mat image = cv::imread("../lena.png");
  if (image.empty()) {
    std::cerr << "Failed to read image" << std::endl;
    return 1;
  }

  // Process the image
  processImage(image);

  // Display the processed image
  cv::imshow("Processed Image", image);
  cv::waitKey(0);

  return 0;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值