在 OpenCV 中将某些行从一个矩阵复制到另一个矩阵的最快方法

Fastest way to copy some rows from one matrix to another in OpenCV

本文关键字:复制 一个 另一个 方法 OpenCV      更新时间:2023-10-16

我有一个[32678 x 10]矩阵(w2c),我想将其中的24700行复制到另一个矩阵(out)。我有要在向量( index )中复制的行的索引。为了在 matlab 中执行此操作,我这样做:

out = w2c(index_im,:);

大约需要 0.002622 秒。

在 OpenCV 中:

Mat out(index.cols, w2c.cols, w2c.type());
for (int i = 0; i < index.cols; ++i) {
    w2c.row(index.at<int>(i) - 1).copyTo(out.row(i));
}

大约需要 0.015121 秒。

如您所见,Matlab 的速度提高了 6 倍。如何使OpenCV代码高效?

我正在使用cmake-2.9,g ++ -4.8,opencv-2.4.9,ubuntu 14.04

更新:

我在发布模式下运行我的代码,这是结果(它仍然比 Matlab 慢得多)

RELEASE     DEBUG       MATLAB
0.008183    0.010070    0.001604    
0.009630    0.010050    0.001679
0.009120    0.009890    0.001566
0.007534    0.009567    0.001635
0.007886    0.009886    0.001840

根据我们在聊天中的讨论,您没有在启用优化的情况下进行编译。如果这样做,您将看到显着的性能提升。此外,请确保您正在链接到OpenCV的发布版本。

我在未启用优化和启用优化的情况下测量了以下示例的执行时间:

主.cpp

#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <random>
#include <vector>
#include <chrono>
#include <opencv2/opencv.hpp>

int main(int argc, char **argv)
{
    const int num_rows = 32678;
    const int num_cols = 10;
    const int index_size = 24700;
    const int num_runs = 1000;
    const int seed = 42;
    std::vector<int> index_vec(num_rows);
    // fill index with sequence
    std::iota (index_vec.begin(), index_vec.end(), 0);
    // randomize sequence
    std::random_device rd;
    std::mt19937 g(rd());
    g.seed(seed);
    std::shuffle(index_vec.begin(), index_vec.end(), g);
    // trunkate index
    index_vec.resize(index_size);
    cv::Mat w2c(num_rows, num_cols, CV_32F);
    // copy
    cv::Mat out(index_size, w2c.cols, w2c.type());
    auto start = std::chrono::high_resolution_clock::now();
    for (int k = 0; k<num_runs; ++k)
    {
        for (int i = 0; i < index_size; ++i)
        {
            w2c.row(index_vec[i]).copyTo(out.row(i));
        }
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    std::cout << duration.count()/num_runs << " microseconds" << std::endl;
    return 0;
}

CMakeList.txt

project(copy)
find_package(OpenCV REQUIRED)
add_executable(copy main.cpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(copy ${OpenCV_LIBS})

无需优化即可编译和运行

cmake . -DCMAKE_BUILD_TYPE=DEBUG
make
./copy
3924 microseconds

通过优化进行编译和运行

cmake . -DCMAKE_BUILD_TYPE=RELEASE
make
./copy
2664 microseconds

我运行了这些测试

  • 英特尔酷睿 i7-4600U 处理器
  • 乌班图14.04(x64)
  • 海湾合作委员会 4.8.2
  • OpenCV 3.0.0 (发布版本)

所以我尝试了不同的方法来解决这个问题,而获得比 Matlab 更好的性能的唯一方法是使用memcpy并直接自己复制数据。

    Mat out( index.cols, w2c.cols, w2c.type() );
    for ( int i=0;i<index.cols;++i ){
        int ind = index.at<int>(i)-1;
        const float *src = w2c.ptr<float> (ind);
        float *des = out.ptr<float> (i);
        memcpy(des,src,w2c.cols*sizeof(float));
    }

这样,整个过程大约花费了 0.001063,比 Matlab 快一点。

我还发现以这种方式复制数据:

    Mat out;
    Mat out( index.cols, w2c.cols, w2c.type() );
    for ( int i=0;i<index.cols;++i ){
        int ind = index.at<int>(i)-1;
        out.push_back(w2c.row(ind)); 
    }

比像这样复制它更快:

    Mat out( index.cols, w2c.cols, w2c.type() );
    for ( int i=0;i<index.cols;++i ){
        int ind = index.at<int>(i)-1;
        w2c.row(ind).copyTo(out.row(i));
    }

但我不知道为什么。无论如何,它们都比Matlab慢。