首页 > 解决方案 > 将 3 通道图像转换为 T 型单向量的最快方法

问题描述

我想将 3 通道 RGB 图像展平为 T 类型的单个向量。在我的情况下,我专注于浮点数据类型。我写了一个运行良好的函数。但我想在不到 1MilliSecond 内完成这个操作。在这里,时间成本对我来说确实是一个问题。这是我的代码。

template<typename T>
inline std::vector<T> flatten_temp(cv::Mat frame_image)
{
    assert(!frame_image.empty());
    const int image_depth = frame_image.channels();
    frame_image.convertTo(frame_image, CV_32FC3);
    cv::Mat *planes =  new cv::Mat[image_depth];        
    
    // /** Split into BGR */
    cv::split(frame_image, planes);
    std::vector<T> flattened_image;
    
    flattened_image.assign(planes[0].begin<T>(), planes[0].end<T>());

    for (int i = 1; i < image_depth; ++i) {
        flattened_image.insert(flattened_image.end(), planes[i].begin<T>(), planes[i].end<T>());
    }
    frame_image.release();
    delete [] planes;
    return flattened_image;
}

任何帮助,将不胜感激。

标签: imageopencvc++11optimizationc++17

解决方案


inserton多次flattened_image 调整向量的大小。此外,插入可能不如普通的快std::copy(可以在这里完成)。确实,如果planes[i].begin<T>()planes[i].end<T>()是普通的连续随机迭代器, std::copy甚至可以memmove非常memcpy快的内存块。

因此,您可以先尝试使用flattened_image.reserve(image_width * image_height * image_depth). 然后,尝试将向量直接分配到合适的大小(用 0 自动填充),然后执行std::copy(planes[i].begin<T>(), planes[i].end<T>(), flattened_image.begin()). 第二个版本应该快一点。如果通道在内存中交错,则此代码不是最有效的,因为输入图像将在内存中多次读取。在这种情况下,最好在交叉通道的同时逐行遍历图像

请注意,如果数据不连续,您还可以利用并行性SIMD 指令来使此代码更快(OpenMP 可能是一个好的开始)。一旦优化,这样的计算应该受到内存层次结构速度的限制,因此在几乎所有相对较新的计算机上,1920x1080x4 的计算时间都不到 1 毫秒


推荐阅读