OpenCV使用CUDA比OpenCV使用CPU运行速度慢

5
我一直在努力使用OpenCV CUDA来提高性能,例如对从AVI文件读取的视频进行腐蚀/膨胀、帧差分等处理。通常情况下,GPU(580gtx)的FPS只有CPU(AMD 955BE)的一半。在您询问我是否正确测量了fps之前,您可以肉眼清楚地看到GPU的滞后,特别是在使用高腐蚀/膨胀级别时。
似乎我没有并行读入帧?以下是代码:
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/video/tracking.hpp>
#include <opencv2/gpu/gpu.hpp>
#include <stdlib.h>
#include <stdio.h>

using namespace cv;
using namespace cv::gpu;

Mat cpuSrc;
GpuMat src, dst;

int element_shape = MORPH_RECT;

//the address of variable which receives trackbar position update
int max_iters = 10;
int open_close_pos = 0;
int erode_dilate_pos = 0;

// callback function for open/close trackbar
void OpenClose(int)
{
     IplImage disp;
     Mat temp;
    int n = open_close_pos - max_iters;
    int an = n > 0 ? n : -n;
    Mat element = getStructuringElement(element_shape, Size(an*2+1, an*2+1), Point(an, an) );
    if( n < 0 )
        cv::gpu::morphologyEx(src, dst, CV_MOP_OPEN, element);
    else
        cv::gpu::morphologyEx(src, dst, CV_MOP_CLOSE, element);

    dst.download(temp);
    disp = temp;    
   // cvShowImage("Open/Close",&disp);
}

// callback function for erode/dilate trackbar
void ErodeDilate(int)
{
     IplImage disp;
     Mat temp;
    int n = erode_dilate_pos - max_iters;
    int an = n > 0 ? n : -n;
    Mat element = getStructuringElement(element_shape, Size(an*2+1, an*2+1), Point(an, an) );
    if( n < 0 )
        cv::gpu::erode(src, dst, element);
    else
        cv::gpu::dilate(src, dst, element);
    dst.download(temp);
    disp = temp;    
    cvShowImage("Erode/Dilate",&disp);
}


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

    VideoCapture capture("TwoManLoiter.avi");

    //create windows for output images
    namedWindow("Open/Close",1);
    namedWindow("Erode/Dilate",1);

    open_close_pos = 3;
    erode_dilate_pos = 0;
    createTrackbar("iterations", "Open/Close",&open_close_pos,max_iters*2+1,NULL);
    createTrackbar("iterations", "Erode/Dilate",&erode_dilate_pos,max_iters*2+1,NULL);

    for(;;)
    {

         capture >> cpuSrc;
         src.upload(cpuSrc);
         GpuMat grey;
         cv::gpu::cvtColor(src, grey, CV_BGR2GRAY); 
         src = grey;

        int c;

        ErodeDilate(erode_dilate_pos);
        c = cvWaitKey(25);

        if( (char)c == 27 )
            break;

    }

    return 0;
}

CPU实现基本相同,只是当然不使用cv::gpu命名空间和GpuMat,而是使用Mat。
谢谢。

你的视频分辨率是多少? - Andrey Kamaev
640x480...随着腐蚀或膨胀的增加,GPU 的速度下降呈指数级增长,比 CPU 更慢。当使用低膨胀/腐蚀值时,GPU 实际上略快于 CPU。 - user779328
1个回答

6
我猜测,GPU的腐蚀/膨胀性能提升被每帧传输图像到GPU和从GPU传回的内存操作所抵消。请记住,内存带宽是GPGPU算法中至关重要的因素,CPU与GPU之间的带宽更为重要。
编辑:为了优化性能,您可以编写自己的图像显示程序(而不是cvShowImage),使用OpenGL仅将图像显示为OpenGL纹理。在这种情况下,您无需将处理过的图像从GPU读取回CPU,并且可以直接使用OpenGL纹理/缓冲区作为CUDA图像/缓冲区,因此您甚至不需要在GPU内部复制图像。但是在这种情况下,您可能需要自己管理CUDA资源。通过这种方法,您还可以使用PBO将视频上传到纹理中,并从异步中获得一些收益。

听起来很有趣,也很有可能。只是好奇,使用CUDA是否可以在GPU内存中分配图像并在捕获/加载时直接进行DMA传输? - kenny
我同意Christian的观点。你似乎正在使用1x1过滤器,执行时间几乎为零。此外,你正在将许多不必要的数据复制到GPU上(BGR,而你只需要灰度)。如果你只是进行这种非常简单的膨胀/腐蚀操作,那么在GPU上处理这些图像只会浪费时间,因为复制数据所需的时间比执行时间还长。 - w-m
即使不考虑 memcpy 的开销:对于像图像形态学这样的操作,GPU 很难与经过 SSE2 优化的 CPU 代码竞争。CPU 可以在一条指令中执行 16 个字节级最小/最大操作,并以 5 倍于 GPU 的时钟速率运行。对于涉及大量常规、窄整数运算的工作负载,GPU 只能希望达到平衡。使用 SM 2.1,Fermi 添加了对“视频指令”的支持,可以在 32 位寄存器中的字节上执行某些 4 路 SIMD 操作,但也许 OpenCV 还没有实现对它们的支持。 - ArchaeaSoftware
哦,我明白了。谢谢大家。我会考虑你们说的一切,并告诉你们是否奏效 :) OpenGL 不是我的重点,但你的评论确实让我考虑它。 - user779328

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接