【发布时间】:2021-04-27 01:00:50
【问题描述】:
我正在使用 Desktop Duplication API - 截取屏幕截图 (c++)。这在原则上是有效的,但并非在所有决议中都有效。
我正在从 D3D11_MAPPED_SUBRESOURCE 创建一个 opencv mat,然后显示图像。
在 1366x768 下看起来像这样(错误)(而 1360x768 工作正常): 还有其他一些具有相同效果的分辨率。
有人知道这可能是什么吗?
这是我截屏的完整代码:
DXGIScreenCapture.h DXGIScreenCapture 类 { 民众: DXGIScreenCapture(); ~DXGIScreenCapture();
bool Init();
bool CaptureScreen();
D3D11_TEXTURE2D_DESC desc;
D3D11_MAPPED_SUBRESOURCE _resource;
private:
ID3D11Device* _lDevice;
ID3D11DeviceContext* _lImmediateContext;
IDXGIOutputDuplication* _lDeskDupl;
ID3D11Texture2D* _lAcquiredDesktopImage;
DXGI_OUTPUT_DESC _lOutputDesc;
DXGI_OUTDUPL_DESC _lOutputDuplDesc;
ID3D11Texture2D* currTexture;
};
DXGIScreenCapture.cpp
DXGIScreenCapture::DXGIScreenCapture()
{
Init();
}
DXGIScreenCapture::~DXGIScreenCapture()
{
}
bool DXGIScreenCapture::Init() {
// Feature levels supported
D3D_FEATURE_LEVEL gFeatureLevels[] = {
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_1
};
UINT gNumFeatureLevels = ARRAYSIZE(gFeatureLevels);
D3D_FEATURE_LEVEL lFeatureLevel;
HRESULT hr(E_FAIL);
hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_FLAG::D3D11_CREATE_DEVICE_SINGLETHREADED, gFeatureLevels, gNumFeatureLevels, D3D11_SDK_VERSION, &_lDevice, &lFeatureLevel, &_lImmediateContext);
if (FAILED(hr))
return false;
if (!_lDevice)
return false;
// Get DXGI device
IDXGIDevice* lDxgiDevice;
hr = _lDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&lDxgiDevice));
if (FAILED(hr))
return false;
// Get DXGI adapter
IDXGIAdapter* lDxgiAdapter;
hr = lDxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&lDxgiAdapter));
lDxgiDevice->Release();
lDxgiDevice = nullptr;
if (FAILED(hr))
return false;
UINT Output = 0;
// Get output
IDXGIOutput* lDxgiOutput;
hr = lDxgiAdapter->EnumOutputs(Output, &lDxgiOutput);
if (FAILED(hr))
return false;
lDxgiAdapter->Release();
lDxgiAdapter = nullptr;
hr = lDxgiOutput->GetDesc(&_lOutputDesc);
if (FAILED(hr))
return false;
// QI for Output 1
IDXGIOutput1* lDxgiOutput1;
hr = lDxgiOutput->QueryInterface(__uuidof(lDxgiOutput1), reinterpret_cast<void**>(&lDxgiOutput1));
lDxgiOutput->Release();
lDxgiOutput = nullptr;
if (FAILED(hr))
return false;
// Create desktop duplication
hr = lDxgiOutput1->DuplicateOutput(_lDevice, &_lDeskDupl);
if (FAILED(hr))
return false;
lDxgiOutput1->Release();
lDxgiOutput1 = nullptr;
// Create GUI drawing texture
_lDeskDupl->GetDesc(&_lOutputDuplDesc);
// Create CPU access texture
desc.Width = _lOutputDuplDesc.ModeDesc.Width;
desc.Height = _lOutputDuplDesc.ModeDesc.Height;
desc.Format = _lOutputDuplDesc.ModeDesc.Format;
desc.ArraySize = 1;
desc.BindFlags = 0;
desc.MiscFlags = 0;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.MipLevels = 1;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_FLAG::D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE::D3D11_USAGE_STAGING;
hr = _lDevice->CreateTexture2D(&desc, NULL, &currTexture);
if (!currTexture)
{
hr = _lDeskDupl->ReleaseFrame();
return false;
}
return true;
}
bool DXGIScreenCapture::CaptureScreen()
{
HRESULT hr(E_FAIL);
IDXGIResource* lDesktopResource = nullptr;
DXGI_OUTDUPL_FRAME_INFO lFrameInfo;
//_lDeskDupl->ReleaseFrame();
hr = _lDeskDupl->AcquireNextFrame(0, &lFrameInfo, &lDesktopResource);
if (FAILED(hr))
return false;
if (lFrameInfo.LastPresentTime.HighPart == 0) // not interested in just mouse updates, which can happen much faster than 60fps if you really shake the mouse
{
hr = _lDeskDupl->ReleaseFrame();
return false;
}
// QI for ID3D11Texture2D
hr = lDesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&_lAcquiredDesktopImage));
lDesktopResource->Release();
lDesktopResource = nullptr;
if (FAILED(hr))
{
hr = _lDeskDupl->ReleaseFrame();
return false;
}
_lImmediateContext->CopyResource(currTexture, _lAcquiredDesktopImage);
UINT subresource = D3D11CalcSubresource(0, 0, 0);
_lImmediateContext->Map(currTexture, subresource, D3D11_MAP_READ, 0, &_resource);
_lImmediateContext->Unmap(currTexture, 0);
hr = _lDeskDupl->ReleaseFrame();
return true;
}
截图:
screenshot()
{
while (!_DXGIScreenCapture.CaptureScreen());
_imageRecognition._image = cv::Mat(_DXGIScreenCapture.desc.Height, _DXGIScreenCapture.desc.Width, CV_8UC4, _DXGIScreenCapture._resource.pData);
}
谢谢你:-)
【问题讨论】:
-
我不能确定这就是问题所在,但是当图像宽度与显示器认为的不匹配时,我通常会看到那种奇怪的对角线翘曲。您实际上可以通过检查这些线的斜率来计算显示的预期值。有可能您使用的任何东西都不支持某些分辨率,而只是降级到它支持的最接近的分辨率。
-
你正在使用
Mat构造函数默认参数, size_t step=AUTO_STEP),而你必须选择_resource.RowPitch。 -
非常感谢@RomanR。 !这就是我需要的提示 :-)
标签: c++ windows opencv screenshot desktop-duplication