2017-07-07 38 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 

可以完全刪除它爲好,雖然這似乎引起「空白「/黑色圖像文件。對我來說,在它開始捕捉之前,只有兩張空白圖像。隨着整個初始化函數的延遲,我得到的第一個圖像也沒有開銷。謝謝。

相關問題