如何在 c++11 中使用 std::vector 使其更快?

Posted

技术标签:

【中文标题】如何在 c++11 中使用 std::vector 使其更快?【英文标题】:How Can I make it faster in c++11 with std::vector? 【发布时间】:2019-07-09 15:30:02 【问题描述】:

我有 cv::Mat Mat_A 和 cv::Mat Mat_B 都是 (800000 X 512) 浮点数

下面的代码看起来很慢。

int rows = Mat_B.rows;
cv::Mat Mat_A = cv::repeat(img, rows, 1, Mat_A);
Mat_A = Mat_A - Mat_B
cv::pow(Mat_A,2,Mat_A)
cv::reduce(Mat_A, Mat_A, 1, CV_REDUCE_SUM);
cv::minMaxLoc(Mat_A, &dis, 0, &point, 0);

如何在 std::vector 中做到这一点?

我认为它应该更快。

在我的 2.4 Ghz mabook pro 中需要 4 秒?很慢。

【问题讨论】:

那是一堆花车!您正在尝试使用 3GB 的数据,然后您正在对其进行操作,我不确定您是否可以更快地做到这一点。为什么你认为 std::vector 会更快? Mat_A 和 MAT_B 正如您看到的非常巨大的 Mat 对象和 - 来自。在 Numpy (python) 中执行相同操作时: (np.square(compare_desc - people_descs[x])) 它比上面带有 MAT 对象的 C++ 代码更快(1,9 秒) 具体是怎么编译的? 【参考方案1】:

我认为您不应该使用 std::vector 来执行这些操作。图像处理(CV 又名计算机视觉)算法的计算量往往很大,因为要处理的数据太多。 OpenCV 2.0 C++ 针对此类操作进行了高度优化,例如cv::Mat 有一个标头,每当使用复制赋值或构造函数复制 cv::Mat 时,只会复制标头并带有指向数据的指针。他们使用引用计数来跟踪实例。所以内存管理已经为你完成了,这是一件好事。

https://docs.opencv.org/2.4/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.html

您可以尝试不使用调试符号进行编译,即发布与调试。您还可以尝试使用优化标志进行编译,例如对于 gcc -O3 这应该会减小二进制文件的大小并加快运行时操作。也许它会有所作为。

https://www.rapidtables.com/code/linux/gcc/gcc-o.html

您可以尝试的另一件事是为您的进程赋予更高的优先级,即优先级越高,进程产生的 CPU 越少。同样,这可能没有太大区别,这完全取决于其他流程及其优先级等。

https://superuser.com/questions/42817/is-there-any-way-to-set-the-priority-of-a-process-in-mac-os-x

希望对你有所帮助。

【讨论】:

【参考方案2】:

你的想法是错误的。

    为什么你的程序很慢:

您的 CPU 必须循环处理大量数字并进行计算。这将使计算复杂度很高。这就是为什么它很慢。您的程序速度与 Mat A 和 B 的大小成正比。您可以通过减小/增加 Mat A 和 B 的大小来检查这一点。

    我们可以通过 std::vector 来加速它吗

抱歉,没有。使用 std::vector 不会降低计算复杂度。 opencv 的数学算法是“最好的”,重写只会导致代码变慢。

    如何加速计算:需要开启opencv的加速选项

您可以在:https://github.com/opencv/opencv/wiki/CPU-optimizations-build-options 看到它。英特尔提供英特尔 mkl 库来加速矩阵计算。你可以先试试。

就个人而言,最简单的方法是使用 GPU。但是你的机器没有 GPU,所以不在此范围内。

【讨论】:

【参考方案3】:

您一遍又一遍地迭代数据以对它们进行独立操作。

这样的事情只在数据上迭代一次。

//assumes Mat_B and img cv::Mat
using px_t = float;//you mentioned float so I'll assume both img and Mat_B use floats
int rows = Mat_B.rows;
cv::Mat output(1,rows, Mat_B.type());
auto output_ptr = output.ptr<px_t>(0);
auto img_ptr = img.ptr<px_t>(0);
int min_idx =0;
int max_idx =0;
px_t min_ele = std::numeric_limits<px_t>::max();
px_t max_ele = std::numeric_limits<px_t>::min();
for(int i = 0; i< rows; ++i)

    output[i]=0;
    auto mat_row = Mat_B.ptr<px_t>(i);
    for(int j = 0; j< Mat_B.cols; ++j)
    
        output[i] +=(img_ptr[j]-mat_row[j])*(img_ptr[j]-mat_row[j]);
    
    if(output[i]<min_ele)
    
       min_idx = i;
       min_ele = output[i];
    
    if(output[i]>max_ele)
    
       max_idx = i;
       max_ele = output[i];
    

【讨论】:

【参考方案4】:

虽然我也不确定它是否更快,但假设 Mat_B 包含 uchar

std::vector<uchar> array_B(Mat_B.rows* Mat_B.cols);
if(Mat_B.isContinuous())
    array_B = Mat_B.data;

【讨论】:

鉴于here 和here 提供的类型,这甚至无法编译

以上是关于如何在 c++11 中使用 std::vector 使其更快?的主要内容,如果未能解决你的问题,请参考以下文章

std::vector 的 std:array 的 SFINAE 不能在 C++11 中编译

为啥在 C++11 中更改了 std::vector::resize 签名?

c++11 std::array vs 静态数组 vs std::vector

启用 C++11 时的 std::vector 性能回归

为啥 C++11 会从 std::vector 填充构造函数的原型中移除默认值?

std::vector、默认构造、C++11 和重大更改