赞
踩
在OpenCV 中,并行框架按照以下顺序提供:
OpenCV库中可以使用多个并行框架。一些并行库是第三方库,必须在CMake(例如TBB,C =)中进行显式构建和启用,其他可以自动与平台(例如APPLE GCD)一起使用,但是您应该可以使用这些库来访问并行框架直接或通过启用CMake中的选项并重建库。
在使用opencv的过程中,对图片的处理计算量还是很大的,所以在实施运行的程序中如何高效的计算会节省很多时间。现有的方法有很多,如OpenMp,TBB,OpenCL,当然还有Nvidia的CUDA。但是OpenMP在windows的VS上支持的很好,设置简单,效果也还不错,但是在Linux虽然也支持,
但是我用Cmake时,感觉效果并不明显。TBB和OpenCL没有直接用过。CUDA是个好东西,但是并不太适合毫秒级别的程序运行,单一张图片在cpu和gpu之间的传输时间就已经达到300ms(我用的是opencv的cuda库函数);在TX2上直接对cuda进行编程,数据的传输也是在50ms(不包含初始化)以上,根本不能拿来做实时的运算。所以如何在cpu上更加高效的计算变得尤为重要。偶然间发现了opencv的并行计算函数parallel_for_,它整合了上述的多个组件。
步骤:
1、声明ParallelLoopBody 子类(取名为FillParallel),并实现其纯虚函数 virtual void operator() (const Range& range) const的功能;
2、实例化子类(FillParallel)的对象(取名为 fill) ;
3、调用 cv::parallel_for_()方式进行并行计算。
- #include <iostream>
- #include <opencv2/core.hpp>
-
-
- class MyParallelClass : public cv::ParallelLoopBody
- {
-
- };
-
- struct MyParallelStruct : public cv::ParallelLoopBody
- {
-
- };
-
- class ParallelAdd : public cv::ParallelLoopBody
- {
- public:
- ParallelAdd(const cv::Mat& _src1, const cv::Mat& _src2, float* _src3)
- {
- src1 = _src1;
- src2 = _src2;
- src3 = _src3;
-
- CV_Assert((src1.rows == src2.rows) && (src1.cols == src2.cols));
- rows = src1.rows;
- cols = src1.cols;
- }
-
- void operator()(const cv::Range& range) const
- {
- size_t step = src1.step1();
- for (int row = range.start; row < range.end; ++row)
- {
- for (int col = 0; col < src1.cols; ++col)
- {
- const float* p1 = src1.ptr<float>(row, col);
- const float* p2 = src2.ptr<float>(row, col);
- src3[row * step + col] = (*p1) * (*p2);
- }
- }
- }
-
- private:
- cv::Mat src1;
- cv::Mat src2;
- float* src3;
- int rows;
- int cols;
- };
-
-
- int main()
- {
- cv::Mat m1(cv::Mat::ones(5000, 5000, CV_32F));
- cv::Mat m2(cv::Mat::ones(5000, 5000, CV_32F));
-
- int64 t1 = cv::getTickCount();
- //直接调用
- cv::Mat r3(m1.rows, m1.cols, m1.type());
- cv::Ptr<ParallelAdd> add= cv::makePtr<ParallelAdd>(m1, m2, (float*)r3.data);
- (*add)(cv::Range(0, m1.rows)); //直接调用,没有并发
- //add->operator()(cv::Range(0, m1.cols));
- int64 t2 = cv::getTickCount();
- std::cout << "time: " << (t2 - t1)/cv::getTickFrequency() * 1000 << " ms" << std::endl;
-
-
- cv::Mat r4(m1.size(), m1.type());
- cv::parallel_for_(cv::Range(0, m1.rows), ParallelAdd(m1, m2, (float*)r3.data));//隐式调用,并发
- int64 t3 = cv::getTickCount();
- std::cout << "parallel time: " << (t3 - t2) / cv::getTickFrequency() * 1000 << " ms" << std::endl;
-
- int64 t4 = cv::getTickCount();
- cv::Mat r5 = m1.mul(m2);
- std::cout << "mat mul: " << (t4 - t3) / cv::getTickFrequency() * 1000 << " ms" << std::endl;
-
- return 1;
- }
-
- time: 1074.81 ms
- parallel time: 160.62 ms
- mat mul: 0.775 ms
总结:使用 parallel_for_ 并发的方式的确比直接调用快一些,但是没有使用 OpenCV 自带的标准函数 mul 函数速度快,因为,OpenCV 实现的函数库不仅仅经过了并行处理,还是用了更强大的底层优化,所以,只要是 OpenCV 一般都是优先使用,除非自己写的比 OpenCV 的还牛逼一些。
最重要的注意点:
T1 = T2 + T3;
可以为T1 = T2.operator+(T3);
也可以为T1 = operator+(T2,T3);
但是这两种方式不能同时声明定义,因为这会出现二义性。造成程序不知道该执行那个函数。在进行运算符重载的时候千万要注意造成二义性的情况。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。