【问题标题】:Desktop Duplication API - Screen Capture doesnt work on 1366x768 (opencv)桌面复制 API - 屏幕捕获在 1366x768 (opencv) 上不起作用
【发布时间】:2021-04-27 01:00:50
【问题描述】:

我正在使用 Desktop Duplication API - 截取屏幕截图 (c++)。这在原则上是有效的,但并非在所有决议中都有效。

我正在从 D3D11_MAPPED_SUBRESOURCE 创建一个 opencv mat,然后显示图像。

在 1920x1080 下看起来像这样(正确):

在 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


【解决方案1】:
    _imageRecognition._image = cv::Mat(_DXGIScreenCapture.desc.Height, _DXGIScreenCapture.desc.Width, CV_8UC4, _DXGIScreenCapture._resource.pData);

需要这样才能处理潜在的扩展步幅:

    _imageRecognition._image = cv::Mat(
        _DXGIScreenCapture.desc.Height, 
        _DXGIScreenCapture.desc.Width, 
        CV_8UC4, 
        _DXGIScreenCapture._resource.pData, 
        _resource.RowPitch // <<--- texture stride might be not the one you expect it
        );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-09
    • 1970-01-01
    • 2017-11-08
    • 2013-08-03
    • 2011-07-09
    • 1970-01-01
    • 2016-03-31
    相关资源
    最近更新 更多