从IDirect3DSurface9创建cv :: Mat

时间:2016-10-20 03:24:07

标签: 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:错误:(-215)total()== 0 || data!=函数cv :: Mat :: Mat

中的NULL

我知道我可以通过将IDirect3DSurface9保存到文件a然后使用cv::imread进行阅读来实现,但我要避免不必要的磁盘操作,除非有&#39别无他法。

btw将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已成功创建,但会失真。撤消图片应该不是问题,但我不知道颜色有什么问题:< / p>

enter image description here

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

enter image description here

以下是原始屏幕截图的外观:( D3DXSaveSurfaceToFile

的结果

enter image description here

1 个答案:

答案 0 :(得分:1)

我想我弄清楚问题是什么。 cv::Mat data参数显然需要仅原始图像(像素数组)

我们使用D3DXSaveSurfaceToFileInMemory得到的缓冲区正是D3DXSaveSurfaceToFile写的文件,只加载到内存中(我检查过:在将缓冲区写入文件后,我们获得了相同的正确图像由D3DXSaveSurfaceToFile

创建

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

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

这适用于 bmp 格式,但我不太了解其他图片格式。

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

  

该函数从内存中的指定缓冲区中读取图像。

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

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

PS。正如我所提到的,还有一件事要翻转图像:(x轴)

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