【发布时间】:2016-08-19 00:20:33
【问题描述】:
我的目标是读取默认 OpenGL 帧缓冲区的内容并将像素数据存储在 cv::Mat 中。显然有两种不同的方法来实现这一点:
1) 同步:使用FBO和glRealPixels
cv::Mat a = cv::Mat::zeros(cv::Size(1920, 1080), CV_8UC3);
glReadPixels(0, 0, 1920, 1080, GL_BGR, GL_UNSIGNED_BYTE, a.data);
2) 异步:使用 PBO 和glReadPixels
cv::Mat b = cv::Mat::zeros(cv::Size(1920, 1080), CV_8UC3);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_userImage);
glReadPixels(0, 0, 1920, 1080, GL_BGR, GL_UNSIGNED_BYTE, 0);
unsigned char* ptr = static_cast<unsigned char*>(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY));
std::copy(ptr, ptr + 1920 * 1080 * 3 * sizeof(unsigned char), b.data);
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
从我收集的关于这个主题的所有信息来看,异步版本 2) 应该快得多。但是,比较两个版本的经过时间会发现差异通常很小,有时版本 1) 事件的性能优于 PBO 变体。
对于性能检查,我插入了以下代码(基于this 答案):
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
....
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << std::endl;
在创建 PBO 时,我还尝试了 使用提示:我在这里没有发现 GL_DYNAMIC_COPY 和 GL_STREAM_READ 之间有太大区别。
我很乐意提供有关如何进一步提高从帧缓冲区读取此像素操作的速度的建议。
【问题讨论】:
-
您的第二个版本并不是真正的异步,因为您正在阻止结果在拨打
glReadPixels()后立即到达。 -
你的意思是打电话给
std::copy?实际上,如果我注释掉这一行,效果是微乎其微的,而且版本 1 有时会更快。 -
如果我不将 GPU 缓冲区映射到 CPU 内存,那会有很大的不同,这当然是预期的,但在那之后是必要的,因为我想将
cv::Mat存储在向量中