2017-07-07 39 views
0

所以,马上去金属。我正在编写一个C++程序,其目的是将屏幕作为输入图像,并使用对象检测器(来自dlib)处理它,但我有麻烦了解如何获得指向swapChain和上下文/内容的指针屏幕。是否可以使用DirectX工具包中的screengrab进行桌面/屏幕截图捕获?

ScreenGrab (DirectX Tool Kit)下面的代码似乎能够做到这一点。问题是我不知道如何让它起作用。我在Visual Studio 2017年使用的NuGet获得库(称为directxtk_uwp,还有哪些我没有使用一个叫directxtk_desktop_2015)和我得到以下六大误区:

  • 错误C2065 : 'swapChain':未声明的标识符
  • 错误C2227:左 ' - >的GetBuffer' 必须指向类/结构/联合/通用型
  • 错误C2065:immContext':未声明的标识符
  • 错误C2228:左'.Get'必须有class/struct/union
  • 错误C2653:“DX”:不是类或命名空间名称
  • 错误C3861:“ThrowIfFailed”:标识符找不到

从ScreenGrab维基页面运行插入示例代码:

#include <ScreenGrab.h> 
#include <wrl\client.h> 
#include <Wincodec.h> 


int main() { 


    using namespace DirectX; 
    using namespace Microsoft::WRL; 

    ComPtr<ID3D11Texture2D> backBuffer; 
    HRESULT hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), 
     reinterpret_cast<LPVOID*>(backBuffer.GetAddressOf())); 
    if (SUCCEEDED(hr)) 
    { 
     hr = SaveWICTextureToFile(immContext.Get(), backBuffer.Get(), 
      GUID_ContainerFormatJpeg, L"SCREENSHOT.JPG"); 
    } 
    DX::ThrowIfFailed(hr); 


     return 0; 
} 

我真的刚刚开始用C++编程,并且来自Java编程,我一直在积极开发一年。因此,保持简单明了,将不胜感激^^

只是要清楚,我想要的东西相当快。我已经获得了screengrab与GDI合作用下面的代码:

#include <iostream> 
#include <Windows.h> 
#include <Wincodec.h> 
#include <ctime> 
#include <cstring> 
#include <atlimage.h> 
#include <d3d9.h> 
using namespace std; 


int main() 
{ 
    try 
    { 
     int nScreenWidth = GetSystemMetrics(SM_CXSCREEN); 
     int nScreenHeight = GetSystemMetrics(SM_CYSCREEN); 
     HWND hDesktopWnd = GetDesktopWindow(); 
     HDC hDesktopDC = GetDC(hDesktopWnd); 
     HDC hCaptureDC = CreateCompatibleDC(hDesktopDC); 

     for (int i = 0; i < 10;i++) { 
      clock_t begin = clock(); 
      HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hDesktopDC, 
       nScreenWidth, nScreenHeight); 
      SelectObject(hCaptureDC, hCaptureBitmap); 
      BitBlt(hCaptureDC, 0, 0, nScreenWidth, nScreenHeight, 
       hDesktopDC, 0, 0, SRCCOPY | CAPTUREBLT); 
      CImage image; 
      image.Attach(hCaptureBitmap); 
      image.Save("test.jpg"); 
      DeleteObject(hCaptureBitmap); 
      cout << double(clock() - begin)/(clock_t)1000 << endl; 
     } 
     ReleaseDC(hDesktopWnd, hDesktopDC); 
     DeleteDC(hCaptureDC); 
     IDirect3DSurface9 *surface; 
     system("pause"); 
    } 
    catch (exception& e) 
    { 
     cout << "\nexception thrown!" << endl; 
     cout << e.what() << endl; 
     system("pause"); 
    } 
} 

其结果如下:

0.091 
0.05 
0.052 
0.06 
0.047 
0.05 
0.057 
0.06 
0.06 
0.051 

,正如你所看到的,真的只是得到我的高达1/0.47 ≈每秒21帧。我也看到了this的答案,但又一次,我不知道如何获得屏幕的上下文和swapChain。 谢谢。

+0

您正在使用的示例代码避免了假设您正试图截取您自己的渲染目标纹理(直接创建或从您自己的交换链获得)。这适用于您自己的应用程序,但整个桌面截图是需要使用DXGI API的另一个问题。你应该看看[这篇文章](https://www.codeproject.com/Articles/5051/Various-methods-for-capturing-the-screen#Capture%20It%20the%20GDI%20way)了解一些选项。 –

+0

DirectX工具包[wiki](https://github.com/Microsoft/DirectXTK/wiki)上的示例代码假定您至少在[tutorials](https://github.com/Microsoft/DirectXTK/wiki/Getting-Started),其中我覆盖了[ThrowIfFiled](https://github.com/Microsoft/DirectXTK/wiki/ThrowIfFailed)。 –

+0

谢谢,查克!我能够找到该页面,因为您可能在变量名称中看到,我只是记不起该网站。从来没有得到DirectX的方式来工作,但那是相当早的,我认为我现在有一个更好的理解来做到这一点。但是,DirectX9并不像您在关于DirectX11的链接问题中所说的那样过时了吗?无论如何,您的帮助非常感谢! – EvilFeline

回答

0

所以经过一番更多的寻找和伟大查克的指导!我发现一个解决方案将屏幕截图保存到磁盘的速度大约快3.5倍(如果删除绘图鼠标以及grabImage函数开始时的开销为8毫秒)。您可以看到代码here。以下是节省十幅图像到磁盘的毫秒结果时间:

0.015 
0.017 
0.012 
0.021 
0.012 
0.019 
0.012 
0.022 
0.018 
0.015 

这些总结起来,从GDI程序的人,我们得到的速度0.578 /0.163≈3.546倍。请记住,我已经更换这一部分:

// Copy image into GDI drawing texture 
     lImmediateContext->CopyResource(lGDIImage, lAcquiredDesktopImage); 

     // Draw cursor image into GDI drawing texture 
     CComPtrCustom<IDXGISurface1> lIDXGISurface1; 

     hr = lGDIImage->QueryInterface(IID_PPV_ARGS(&lIDXGISurface1)); 

     if (FAILED(hr)) 
      return false; 

     CURSORINFO lCursorInfo = { 0 }; 

     lCursorInfo.cbSize = sizeof(lCursorInfo); 

     auto lBoolres = GetCursorInfo(&lCursorInfo); 

     if (lBoolres == TRUE) 
     { 
      if (lCursorInfo.flags == CURSOR_SHOWING) 
      { 
       auto lCursorPosition = lCursorInfo.ptScreenPos; 

       auto lCursorSize = lCursorInfo.cbSize; 

       HDC lHDC; 

       lIDXGISurface1->GetDC(FALSE, &lHDC); 

       DrawIconEx(
        lHDC, 
        lCursorPosition.x, 
        lCursorPosition.y, 
        lCursorInfo.hCursor, 
        0, 
        0, 
        0, 
        0, 
        DI_NORMAL | DI_DEFAULTSIZE); 

       lIDXGISurface1->ReleaseDC(nullptr); 
      } 

     } 

     // Copy image into CPU access texture 
     lImmediateContext->CopyResource(lDestImage, lGDIImage); 

与以下行:

lImmediateContext-> CopyResource(lDestImage,lAcquiredDesktopImage);

因为我不需要光标。事实上,考虑到我会在屏幕上检测到事情,可能会更糟糕。正如前面提到的,我也搬到了线Sleep(8); // not sure if required从这里:

hr = lDevice->CreateTexture2D(&desc, NULL, &lDestImage); 

    if (FAILED(hr)) 
     return false; 

    if (lDestImage == nullptr) 
     return false; 

    return true; 
} 

bool grabImage() { 
    int lTryCount = 4; 

    do 
    { 
     Sleep(8); // not sure if required 

在这里,在init函数:

hr = lDevice->CreateTexture2D(&desc, NULL, &lDestImage); 

    if (FAILED(hr)) 
     return false; 

    if (lDestImage == nullptr) 
     return false; 
    Sleep(8); 
    return true; 
} 

bool grabImage() { 
    int lTryCount = 4; 

    do 
    { 
      //Sleep(5); // not sure if required 

可以完全删除它为好,虽然这似乎引起“空白“/黑色图像文件。对我来说,在它开始捕捉之前,只有两张空白图像。随着整个初始化函数的延迟,我得到的第一个图像也没有开销。谢谢。

相关问题