2013-04-03 31 views
1

我目前在我的GPU(CUDA/C++)上实现了一个运动跟踪算法,并且目前看到非常强大的加速。然而,正如人们可以预料的那样,主要的瓶颈是帧(图像)数据从CPU到GPU的实际传输。将视频帧数据移动到GPU的最有效方法是什么?

因为我使用OpenCV来读取测试视频文件。但是,OpenCV以RRGGBB RRGGBB ...的形式将封包以字节形式返回,或者换句话说,每个像素都对齐到24位​​边界。这不允许我使用合并内存访问,这会在GPU上导致严重的性能损失。原来,我只是使用一些预先生成的测试数据,其中 32位对齐(以RRGGBB00 RRGGBB00 ...的形式用零填充),但我现在要开始使用实际的视频数据。

这引起了我一些显著的性能损失,所以我有两个主要问题:

  1. 虽然我可以手动预处理的CPU上的感兴趣像素,然后开始转移,有没有方法可以快速将像素数据传输到GPU,但对齐到32位边界? (然而,我认为这与预处理具有相同的性能)

  2. 是否有另一个库可以用来以不同格式读取视频?例如,我知道即使没有包含Alpha通道,SDL表面也会打包在32位边界中。

我们实现的最终目标将是实时与机器人控制摄像头接口,虽然现在我只是想的东西,可以高效地解码我的测试视频来测试我们的功能检测和运动跟踪具有预定义测试数据的算法。

+0

可能重复的[快速24位数组 - > 32位数组转换?](http://stackoverflow.com/questions/2973708/fast-24-bit-array-32-bit-array-conversion) – MSalters

+0

你的视频文件格式是什么?您可以尝试使用其他内容加载视频,如FFMpeg或CUDA解码器库(我认为OpenCV自2.4版起还有FFMpeg绑定?)。 – alrikai

+0

@alrikai现在,它只是一个使用x264压缩的视频(因此h.264在.MKV容器中)。我查看了CUDA解码器库,但我不确定它是否与Linux兼容,并且我希望解决方案能够扩展到当我们使用实际相机的系统时(因此不能反正使用CUDA解码器)。就OpenCV而言,我相信它已经在Linux上使用了FFMPEG,但在Windows上却没有(请参阅[这里的文档](http://opencv.willowgarage.com/documentation/python/reading_and_writing_images_and_video.html#capturefromfile))。 – Breakthrough

回答

2

我尝试编写一个简单的CUDA内核,使用共享内存将24位值填充到32位。请注意,这不是一个非常整洁的代码(仅适用于1个块,依赖int为32位) - 小心使用。我尝试了一个版本与共享内存atomics和没有 - 似乎是工作。:

__global__ void pad(unsigned int *data, unsigned int* odata) { 
__shared__ unsigned int array[WORK_SIZE]; 
unsigned int v, high, low; 
const int index = (threadIdx.x * sizeof(unsigned int))/3; 

array[threadIdx.x] = 0; 
__syncthreads(); 

const int shl = threadIdx.x % 3; 
const int shr = 3 - shl; 

if (threadIdx.x 
     < ((WORK_SIZE * 3) + sizeof(unsigned int) - 1) 
       /sizeof(unsigned int)) { 
    v = data[threadIdx.x]; 
    high = (v >> (shl * 8)) & ~0xFF; 
    low = v << (shr * 8); 
#if __CUDA_ARCH__ < 200 
    array[index] = high; 
} 
__syncthreads(); 
if (threadIdx.x 
     < ((WORK_SIZE * 3) + sizeof(unsigned int) - 1) 
     /sizeof(unsigned int)) { 
    array[index + 1] += low; 
#else 
    if (high) 
     atomicOr(array + index, high); 
    if (low) 
     atomicOr(array + 1 + index, low); 
#endif 
} 
__syncthreads(); 

// Do computations! 
odata[threadIdx.x] = array[threadIdx.x] + 0xFF; 
} 
+0

我给这个upvote,因为我能够使内核工作作为给定(加上一些修改)。由于我的代码位于*不*使用完整视频帧的位置,因此在CPU上预处理数据会更快。如果我们的限制改变,我会记住这一点。 – Breakthrough

+0

嗯,我相信我仍然回答你的问题;) – Eugene

+0

接受,但请注意,有些人会使用[24位 - > 32位CPU转换]获得更好的加速(http://stackoverflow.com/questions/2973708/fast-24-bit-array-32-bit-array-conversion)@MSalters链接到上面。一如既往,这取决于您的特定应用程序和实施:) – Breakthrough

相关问题