首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >调整cv::Mat大小的最有效方法

调整cv::Mat大小的最有效方法
EN

Stack Overflow用户
提问于 2015-08-01 19:16:36
回答 1查看 6.4K关注 0票数 1

我正在编写一个图像处理程序,它在一帧中使用cv::resize(INTER_LINEAR)数百次。然而,我发现cv::resize()是一个cpu杀手,它是我的程序中的热点。有没有更好的方法来调整图像的大小,而cpu使用率更低?

代码有点像这样:

代码语言:javascript
复制
void process(const cv::Mat& frame) {
    for(int i = 0; i < COUNTS; ++i) {
        int new_rows = CalculateHeight();
        int new_cols = CalculateWidth();
        cv::Mat new_img;
        cv::resize(frame, new_mg, cv::Size(new_cols, new_rows));
        // ...
    }
    // ...
}

谢谢!

EN

回答 1

Stack Overflow用户

发布于 2015-08-01 20:59:43

以下是我使用OpenCV函数10,000次调整随机图像大小的一些测试结果。最好的解决方案似乎是在调整大小之前转换为灰度(如果可能),使用ROI或滚动您自己的ASM AVX函数来使用每1/3(或任何您需要的缩放因子)行和列来调整大小。调整大小的函数得到了相当的优化。

代码语言:javascript
复制
Colour
INTER_LINEAR 7953.89ms
INTER_LINEAR GPU 2252.72ms
INTER_LINEAR GPU MEMIO 23303.7ms
INTER_NEAREST 7297.58ms
INTER_NEAREST GPU 906.336ms
INTER_NEAREST GPU MEMIO 22374.1ms
BORDER_DEFAULT 47488.8ms
BORDER_REFLECT 47515.4ms
BORDER_REPLICATE 47516ms
BORDER_WRAP 47980.7ms
PYR GPU 4126.93ms

Grayscale
INTER_LINEAR 413.789ms
INTER_LINEAR GPU 1027.85ms
INTER_LINEAR GPU MEMIO 9568.99ms
INTER_NEAREST 978.89ms
INTER_NEAREST GPU 747.621ms
INTER_NEAREST GPU MEMIO 9346.28ms
BORDER_DEFAULT 19266.7ms
BORDER_REFLECT 19274.1ms
BORDER_REPLICATE 19300.8ms
BORDER_WRAP 19386.3ms
PYR GPU 2272.7ms


#include "opencv2/opencv.hpp"
#include "opencv2/cudaimgproc.hpp"
#include "opencv2/cudawarping.hpp"

#include <iostream>
#include <string>
#include <chrono>

using namespace std;
using namespace cv;

template <typename T>
double resizePerfEval(const Mat& frame, unsigned int n, T resizeFlag) {

    auto start = chrono::steady_clock::now();

    for (auto i = 0; i < n; i++) {
        Mat temp;
        resize(frame, temp, Size(), 0.5, 0.5, resizeFlag); 
    }

    return chrono::duration <double, milli>(chrono::steady_clock::now() - start).count();
}

template <typename T>
double pyramidPerfEval(const Mat& frame, unsigned int n, T border) {

    auto start = chrono::steady_clock::now();
    Size s(frame.cols / 2, frame.rows / 2);

    for (auto i = 0; i < n; i++) {
        Mat tmp;
        pyrDown(frame, tmp, s, border); 
    }

    return chrono::duration <double, milli>(chrono::steady_clock::now() - start).count();
}

template <typename T>
double resizePerfEvalGPU(const Mat& frame, unsigned int n, T resizeFlag, bool uploadDownload=false) {

    auto start = chrono::steady_clock::now();

    Mat tmp;
    cuda::GpuMat frame_d, temp;
    frame_d.upload(frame);

    for (auto i = 0; i < n; i++) {          

        cuda::resize(frame_d, temp, Size(), 0.5, 0.5, resizeFlag);
        if (uploadDownload) {
            temp.download(tmp);
            frame_d.upload(frame);
        }
    }

    return chrono::duration <double, milli>(chrono::steady_clock::now() - start).count();
}

double pyramidPerfEvalGPU(const Mat& frame, unsigned int n, bool uploadDownload = false) {

    auto start = chrono::steady_clock::now();

    Mat tmp;
    cuda::GpuMat frame_d, temp;
    frame_d.upload(frame);

    for (auto i = 0; i < n; i++) {      

        cuda::pyrDown(frame_d, temp);
        if (uploadDownload) {
            temp.download(tmp);
            frame_d.upload(frame);
        }

    }

    return chrono::duration <double, milli>(chrono::steady_clock::now() - start).count();
}


void runTest(const Mat& frame, unsigned int n) {

    cout << "INTER_LINEAR "     << resizePerfEval(frame, n, INTER_LINEAR) << "ms" << endl;
    cout << "INTER_LINEAR GPU " << resizePerfEvalGPU(frame, n, INTER_LINEAR) << "ms" << endl;
    cout << "INTER_LINEAR GPU MEMIO " << resizePerfEvalGPU(frame, n, INTER_LINEAR, true) << "ms" << endl;

    cout << "INTER_NEAREST "    << resizePerfEval(frame, n, INTER_NEAREST) << "ms" << endl;
    cout << "INTER_NEAREST GPU "    << resizePerfEvalGPU(frame, n, INTER_NEAREST) << "ms" << endl;
    cout << "INTER_NEAREST GPU MEMIO " << resizePerfEvalGPU(frame, n, INTER_NEAREST, true) << "ms" << endl;

    cout << "BORDER_DEFAULT "   << pyramidPerfEval(frame, n, BORDER_DEFAULT) << "ms" << endl;
    cout << "BORDER_REFLECT "   << pyramidPerfEval(frame, n, BORDER_REFLECT) << "ms" << endl;
    cout << "BORDER_REPLICATE " << pyramidPerfEval(frame, n, BORDER_REPLICATE) << "ms" << endl;
    cout << "BORDER_WRAP "      << pyramidPerfEval(frame, n, BORDER_WRAP) << "ms" << endl;
    cout << "PYR GPU "          << pyramidPerfEvalGPU(frame, n) << "ms" << endl;

}

int main(int argc, char* argv[])
{

    Mat gsframe, frame = Mat::ones(Size(1920, 1080), CV_8UC3);
    randu(frame, Scalar::all(0), Scalar::all(255));
    cvtColor(frame, gsframe, CV_BGR2GRAY);
    auto n = 10000;

    cout << "Colour" << endl;
    runTest(frame, n);

    cout << endl << "Grayscale" << endl;
    runTest(gsframe, n);    

    return 0;
}

如果算法在PC上运行,另一种方法是在支持CUDA的GPU上进行大小调整。但是,您在选择卡时必须小心,因为您需要足够高的内存带宽,以适应从GPU内存上传和下载图像所需的时间。

请注意,当图像在GPU内存中不可用时,CPU在灰度上优于GPU。如果图像在GPU内存中可用,那么对于Colour来说,使用GPU可以加速3.5倍(特别是对于非常大的图像尺寸)。对于高端应用,可以使用带有GPUDirect的NVIDIA捕获卡来实现这一点。

在Xeon E5 v2 @3.0 out 680GTX上进行了测试

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31761203

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档