将视频帧数据移动到GPU的最有效方法是什么?

时间:2013-04-03 12:53:15

标签: c++ opencv cuda

我目前正在我的GPU(CUDA / C ++)上实现运动跟踪算法,到目前为止我看到了非常强大的加速。然而,人们可能会想到,主要的瓶颈是将帧(图像)数据从CPU实际传输到GPU。

按原样,我正在使用OpenCV读入测试视频文件。但是,OpenCV以RRGGBB RRGGBB ...形式将帧作为压缩字节返回,或者换句话说,每个像素与24位边界对齐。这使我无法使用合并的内存访问,这会对GPU造成严重的性能损失。原样,我只是使用一些预先生成的测试数据 32位对齐(用RRGGBB00 RRGGBB00 ...形式的零填充),但我想开始使用现在的实际视频数据。

这给我带来了一些重大的性能损失,所以我有两个主要问题:

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

  2. 我可以使用另一个图书馆以不同的格式阅读视频吗?例如,我知道SDL表面以32位边界打包,即使没有包含alpha通道。

  3. 我们实现的最终目标是实时与摄像头进行机器人控制接口,虽然目前我只想要能够有效解码我的测试视频以测试我们的特征检测和运动跟踪算法定义的测试数据。

1 个答案:

答案 0 :(得分:2)

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

__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;
}