c++ - 从 IDirect3DSurface9 创建 cv::Mat

标签 c++ opencv image-processing directx mat

我正在开发的应用目前截取基于 DirectX 的游戏的屏幕截图。 使用 IDirect3DDevice9::GetBackBuffer 会产生 IDirect3DDevice9 对象。

现在我正在寻找一种直接获取原始图像的方法,因为我需要稍后在 OpenCV 中对其进行处理。

我找到的唯一例子是 OpenCV directx samples ,所以我尝试按以下方式初始化 cv::Mat:

IDirect3DSurface9* pSurface = nullptr;
auto cops = pDevice->CreateOffscreenPlainSurface(ScreenWidth, ScreenHeight, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurface, NULL);
auto gfbd = pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pSurface);

D3DLOCKED_RECT lockedRect;
ZeroMemory(&lockedRect, sizeof(D3DLOCKED_RECT));
pSurface->LockRect(&lockedRect, 0, D3DLOCK_READONLY);

//**** OpenCV

cv::Mat D3DSurface(ScreenHeight, ScreenWidth, CV_8UC4, lockedRect.pBits, lockedRect.Pitch);

cv::imshow("D3DSurface", D3DSurface);

不幸的是,它抛出以下异常:d:\lib\opencv\build\install\include\opencv2\core\mat.inl.hpp:410: error: (-215) total() == 0 || data != NULL 函数 cv::Mat::Mat


我知道我可以通过将 IDirect3DSurface9 保存到一个文件然后用 cv::imread 读取它来做到这一点,但我宁愿避免不必要的磁盘除非别无他法。

顺便说一句,将 IDirect3DSurface9 保存到文件中工作正常,我使用以下方法检查过它:

D3DXSaveSurfaceToFile(L"D:\\ss1.bmp", D3DXIFF_BMP, pSurface, NULL, NULL);

编辑:

正如 @Asesh 提到的,我尝试使用 D3DXSaveSurfaceToFileInMemory,现在代码如下:

LPD3DXBUFFER buffer;
D3DXSaveSurfaceToFileInMemory(&buffer, D3DXIFF_BMP, pSurface, NULL, NULL);
DWORD imSize = buffer->GetBufferSize();
void* imgBuffer = buffer->GetBufferPointer();

//**** OpenCV

cv::Mat D3DSurface(ScreenHeight, ScreenWidth, CV_8UC4, imgBuffer);
cv::imshow("D3DSurface", D3DSurface);

cv::Mat 创建成功,但是它变形了。 反转图像应该没有问题,但是我不知道有什么问题颜色:

enter image description here

cv::Mat 构造函数中使用 CV_8UC3 类型会导致:

enter image description here

原始屏幕截图应如下所示:(D3DXSaveSurfaceToFile 的结果)

enter image description here

最佳答案

我想我知道问题出在哪里了。 cv::Mat data 参数显然需要仅原始图像(像素阵列)

我们使用D3DXSaveSurfaceToFileInMemory得到的buffer正是D3DXSaveSurfaceToFile写入的文件,只是加载到内存中(我查了一下:把buffer写入文件后我们得到与 D3DXSaveSurfaceToFile)

创建的相同的正确图像

我读过 here bmp header 开头是 54 个字节,所以我只是向 imgBuffer 指针添加了一个偏移量 ,图像现在是正确的。

cv::Mat D3DSurface(ScreenHeight, ScreenWidth, CV_8UC4, (BYTE*)imgBuffer + 54);

这适用于 bmp 格式,但我真的不知道其他图像格式如何。

.

困扰我的一件事是 cv::imdecode方法:

The function reads an image from the specified buffer in the memory.

所以也许它应该用于从内存中的文件中获取 cv::Mat,就像 cv::imread 从磁盘加载文件一样。但是我不知道如何让它工作,因为它使用 InputArray 类型作为输入

.

@Asesh @VuVirt 非常感谢您的帮助。


附言。正如我提到的,要做的另一件事是翻转图像:(x 轴)

cv::Mat D3DSurfaceCorrect;  // new image
cv::flip(D3DSurface, D3DSurfaceCorrect, 0);

关于c++ - 从 IDirect3DSurface9 创建 cv::Mat,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40144903/

相关文章:

c++ - 删除共享指针 vector 时可能发生内存泄漏

c++ - 通过 warpAffine(opencv,c++)在旋转图像后获取 cv::rect 的新位置

c++ - opencv 多进程的小加速

python - 如何将调整大小的图像的坐标转换为原始图像的坐标?

image-processing - 射影空间中来自内参的无穷远平面

c++ - 在成员变量中使用模板类作为模板模板参数时出错

c++ - 为什么不能在常量表达式中使用 reinterpret_cast?

c++ - 为什么我不能在即时窗口中索引 std::vector?

c++ - cv::merge 没有匹配函数

python - 图像片段中所有像素的强度值之和