当前位置:   article > 正文

opencv的并行处理cv::ParallelLoopBody

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 例子中,定义了一个 GrayscaleTransform 类,继承自 cv::ParallelLoopBody,并实现了 operator() 函数。在 operator() 函数中,使用 cv::saturate_cast 函数来将每个像素的 RGB 值转换为灰度值,并将其赋值给每个通道。然后,将 GrayscaleTransform 的实例传递给 cv::parallel_for_ 函数,该函数将数据范围划分为多个子范围,并创建多个线程来执行 GrayscaleTransform::operator() 函数。
cv::parallel_for_(cv::Range(0, image.rows), transform);
  • 1
  • 函数接受两个参数:一个 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/657425
推荐阅读
相关标签
  

闽ICP备14008679号