OpenCV - 基本操作 - 性能问题[模式:发布]

时间:2017-08-19 20:02:13

标签: c++ performance opencv optimization performance-testing

我可能会发现OpenCV自己实现矩阵乘法/求和的一个巨大的性能问题,并想与你们核实我是否遗漏了一些东西:

提前:所有运行都是在(OpenCV' s)发布模式下完成的。

设定:

(a)我用矩阵矢量乘法进行1000万次,其中3乘3矩阵和3乘1矢量。实现遵循以下代码:res = mat * vec;

(b)我将自己实现相同的单独访问元素,然后使用指针算法进行乘法处理。 [基本上只是将过程相乘并写下结果向量的每一行的等式]

我使用编译器标志-O0,-O1,-O2,-O3,-Ofast和OpenCV 3.1&amp ;;测试了这些变体。 3.2。

时序是在Ubuntu 16.04上使用chrono(high_resolution_clock)完成的。

调查结果:

在所有情况下,非优化方法(b)的性能优于OpenCV方法(a)约100至1000倍。

问题:

情况怎么样?不应该针对这些程序优化OpenCV吗?我应该在Github上提出一个问题,还是有些东西我完全失踪了?

代码:[准备在您的机器上复制和测试]

#include <chrono>
#include <iostream>

#include "opencv2/core/cvstd.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"



int main()
{

    // 1. Setup:

    std::vector<std::chrono::high_resolution_clock::time_point> timestamp_vec_start(2);
    std::vector<std::chrono::high_resolution_clock::time_point> timestamp_vec_end(2);
    std::vector<double> timestamp_vec_total(2);


    cv::Mat test_mat = (cv::Mat_<float>(3,3) <<  0.023, 232.33, 0.545, 
                                                 22.22, 0.1123, 4.444,
                                                 0.012, 3.4521, 0.202);

    cv::Mat test_vec = (cv::Mat_<float>(3,1) <<  5.77, 
                                                 1.20,
                                                 0.03);

    cv::Mat result_1 = cv::Mat(3, 1, CV_32FC1);
    cv::Mat result_2 = cv::Mat(3, 1, CV_32FC1);

    cv::Mat temp_test_mat_results = cv::Mat(3, 3, CV_32FC1);
    cv::Mat temp_test_vec_results = cv::Mat(3, 1, CV_32FC1);

    auto ptr_test_mat_res_0 = temp_test_mat_results.ptr<float>(0);
    auto ptr_test_mat_res_1 = temp_test_mat_results.ptr<float>(1);
    auto ptr_test_mat_res_2 = temp_test_mat_results.ptr<float>(2);

    auto ptr_test_vec_res_0 = temp_test_vec_results.ptr<float>(0);
    auto ptr_test_vec_res_1 = temp_test_vec_results.ptr<float>(1);
    auto ptr_test_vec_res_2 = temp_test_vec_results.ptr<float>(2);

    auto ptr_res_0 = result_2.ptr<float>(0);
    auto ptr_res_1 = result_2.ptr<float>(1);
    auto ptr_res_2 = result_2.ptr<float>(2);





    // 2. OpenCV Basic Matrix Operations:

    timestamp_vec_start[0] = std::chrono::high_resolution_clock::now();

    for(int i = 0; i < 10000000; ++i)
    {
        // factor of up to 5000 here:
        // result_1 = (test_mat + test_mat + test_mat) * (test_vec + test_vec);

        // factor of 30~100 here:
        result_1 = test_mat * test_vec;
    }

    timestamp_vec_end[0]   = std::chrono::high_resolution_clock::now();
    timestamp_vec_total[0] = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(timestamp_vec_end[0] - timestamp_vec_start[0]).count());





    // 3. Pixel-Wise Operations:

    timestamp_vec_start[1] = std::chrono::high_resolution_clock::now();

    for(int i = 0; i < 10000000; ++i)
    {
        auto ptr_test_mat_0 = test_mat.ptr<float>(0);
        auto ptr_test_mat_1 = test_mat.ptr<float>(1);
        auto ptr_test_mat_2 = test_mat.ptr<float>(2);

        auto ptr_test_vec_0 = test_vec.ptr<float>(0);
        auto ptr_test_vec_1 = test_vec.ptr<float>(1);
        auto ptr_test_vec_2 = test_vec.ptr<float>(2);


        ptr_test_mat_res_0[0] = ptr_test_mat_0[0] + ptr_test_mat_0[0] + ptr_test_mat_0[0];
        ptr_test_mat_res_0[1] = ptr_test_mat_0[1] + ptr_test_mat_0[1] + ptr_test_mat_0[1];
        ptr_test_mat_res_0[2] = ptr_test_mat_0[2] + ptr_test_mat_0[2] + ptr_test_mat_0[2];

        ptr_test_mat_res_1[0] = ptr_test_mat_1[0] + ptr_test_mat_1[0] + ptr_test_mat_1[0];
        ptr_test_mat_res_1[1] = ptr_test_mat_1[1] + ptr_test_mat_1[1] + ptr_test_mat_1[1];
        ptr_test_mat_res_1[2] = ptr_test_mat_1[2] + ptr_test_mat_1[2] + ptr_test_mat_1[2];

        ptr_test_mat_res_2[0] = ptr_test_mat_2[0] + ptr_test_mat_2[0] + ptr_test_mat_2[0];
        ptr_test_mat_res_2[1] = ptr_test_mat_2[1] + ptr_test_mat_2[1] + ptr_test_mat_2[1];
        ptr_test_mat_res_2[2] = ptr_test_mat_2[2] + ptr_test_mat_2[2] + ptr_test_mat_2[2];

        ptr_test_vec_res_0[0] = ptr_test_vec_0[0] + ptr_test_vec_0[0];
        ptr_test_vec_res_1[0] = ptr_test_vec_1[0] + ptr_test_vec_1[0];
        ptr_test_vec_res_2[0] = ptr_test_vec_2[0] + ptr_test_vec_2[0];

        ptr_res_0[0] = ptr_test_mat_res_0[0]*ptr_test_vec_res_0[0] + ptr_test_mat_res_0[1]*ptr_test_vec_res_1[0] + ptr_test_mat_res_0[2]*ptr_test_vec_res_2[0];
        ptr_res_1[0] = ptr_test_mat_res_1[0]*ptr_test_vec_res_0[0] + ptr_test_mat_res_1[1]*ptr_test_vec_res_1[0] + ptr_test_mat_res_1[2]*ptr_test_vec_res_2[0];
        ptr_res_2[0] = ptr_test_mat_res_2[0]*ptr_test_vec_res_0[0] + ptr_test_mat_res_2[1]*ptr_test_vec_res_1[0] + ptr_test_mat_res_2[2]*ptr_test_vec_res_2[0];
    }

    timestamp_vec_end[1]   = std::chrono::high_resolution_clock::now();
    timestamp_vec_total[1] = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(timestamp_vec_end[1] - timestamp_vec_start[1]).count());





    // 4. Printout Timing Results:

    std::cout << "\n\nTimings:\n\n";
    std::cout << "Time spent in OpenCV's implementation:      "  << timestamp_vec_total[0]/1000.0 << " ms.\n";
    std::cout << "Time spent in element-wise implementation:  "  << timestamp_vec_total[1]/1000.0 << " ms.\n\n";

    std::cin.get();

    return 0;
}

1 个答案:

答案 0 :(得分:2)

OpenCV未针对小型矩阵操作进行优化 您可以使用cv::gemm

为循环内的结果分配新的Matrix,从而减少开销。

但如果小矩阵操作是您的瓶颈,我建议您使用Eigen

使用快速的特征实现,如:

Eigen::Matrix3d mat;
mat << 0.023, 232.33, 0.545,
    22.22, 0.1123, 4.444,
    0.012, 3.4521, 0.202;

Eigen::Vector3d vec3;
vec3 << 5.77,
    1.20,
    0.03;

Eigen::Vector3d result_e;

for (int i = 0; i < 10000000; ++i)
{
    result_e = (mat *3 ) * (vec3 *2);
}

给了我以下VS2015的数字(显然在GCC或Clang中差异可能不那么显着):

Timings:

Time spent in OpenCV's implementation:      2384.45 ms.
Time spent in element-wise implementation:  78.653 ms.
Time spent in Eigen implementation:         36.088 ms.
相关问题