【问题标题】:Create cv::Mat from IDirect3DSurface9从 IDirect3DSurface9 创建 cv::Mat
【发布时间】:2017-03-01 21:23:33
【问题描述】:

我正在开发的应用程序目前正在截取基于 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 != 函数 cv::Mat::Mat 中的 NULL


我知道我可以通过将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创建成功,但是变形了。图片反转应该没问题,但是不知道颜色有什么问题:

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

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

【问题讨论】:

  • 您可以使用 D3DXSaveSurfaceToFileInMemory 将表面保存在内存中
  • @Asesh 谢谢 :) 我能够成功创建cv::Mat,但现在图像有问题。我在上面制作和编辑。
  • 看起来它是后缓冲区而不是前缓冲区。您是否使用了指向 IDirect3DSurface9 的相同指针?如果是,那么您可以检查 D3DXSaveSurfaceToFileInMemory 和 D3DXSaveSurfaceToFile 的结果吗?
  • 也就是说,只要将 D3DXSaveSurfaceToFileInMemory 的内容写入一个文件,并将结果与​​ D3DXSaveSurfaceToFile 的输出进行比较即可。
  • 您的 pSurface 的格式是什么?您可以使用 GetDesc 获取它并检查 D3DSURFACE_DESC 结构的 Format 字段。如果不是 d3dformat_x8r8g8b8 则不能直接使用 CV_8UC4/CV_8UC3。

标签: c++ opencv image-processing directx mat


【解决方案1】:

我想我弄清楚了问题所在。 cv::Mat data 参数显然需要仅原始图像(像素阵列)

我们使用D3DXSaveSurfaceToFileInMemory 获得的缓冲区正是D3DXSaveSurfaceToFile 写入的文件,只加载到内存中(我检查了它:将缓冲区写入文件后,我们得到与@ 创建的相同的正确图像987654327@)

我读到herebmp header 开头是 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);

【讨论】:

    猜你喜欢
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    • 2016-02-28
    • 1970-01-01
    • 1970-01-01
    • 2020-02-09
    • 2014-06-21
    • 1970-01-01
    相关资源
    最近更新 更多