从 IDirect3DSurface9 创建 cv::Mat
Create cv::Mat from IDirect3DSurface9
我正在开发的应用目前正在截取 DirectX-based 游戏的屏幕截图。
使用 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 ||数据 != 函数中的 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
创建成功,但是变形了倒转应该没问题,但是不知道是哪里出了问题颜色:
在 cv::Mat
构造函数中使用 CV_8UC3
类型会导致:
原始屏幕截图应如下所示:(D3DXSaveSurfaceToFile
的结果)
我想我明白问题出在哪里了。 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
非常感谢您的帮助。
PS。正如我提到的,要做的另一件事是翻转图像:(x 轴)
cv::Mat D3DSurfaceCorrect; // new image
cv::flip(D3DSurface, D3DSurfaceCorrect, 0);
我正在开发的应用目前正在截取 DirectX-based 游戏的屏幕截图。
使用 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 ||数据 != 函数中的 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
创建成功,但是变形了倒转应该没问题,但是不知道是哪里出了问题颜色:
在 cv::Mat
构造函数中使用 CV_8UC3
类型会导致:
原始屏幕截图应如下所示:(D3DXSaveSurfaceToFile
的结果)
我想我明白问题出在哪里了。 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 非常感谢您的帮助。
PS。正如我提到的,要做的另一件事是翻转图像:(x 轴)
cv::Mat D3DSurfaceCorrect; // new image
cv::flip(D3DSurface, D3DSurfaceCorrect, 0);