Commit f0197006 authored by Vladimir Dudnik's avatar Vladimir Dudnik

removed original samples and replace them with new ones. modified new samples…

removed original samples and replace them with new ones. modified new samples (reduce code duplication, add cmd line params and short description)
parent 3cb4954d
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d3d10.h>
#pragma comment (lib, "d3d10.lib")
#define USE_D3D10
#define WINDOW_NAME "OpenCV Direct3D 10 Sample"
#include "opencv2/core.hpp"
#include "opencv2/core/directx.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "d3dsample.hpp"
IDXGISwapChain *swapchain = NULL;
ID3D10Device *dev = NULL;
ID3D10Texture2D *pBackBufferTexture = NULL;
ID3D10Texture2D *pCPUWriteTexture = NULL;
ID3D10Texture2D *pInputTexture = NULL;
ID3D10RenderTargetView *backbuffer = NULL;
#pragma comment (lib, "d3d10.lib")
#include "d3d_base.inl.hpp"
bool initDirect3D()
using namespace std;
using namespace cv;
class D3D10WinApp : public D3DSample
{
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = WIDTH; // set the back buffer width
scd.BufferDesc.Height = HEIGHT; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 1; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching
if (FAILED(D3D10CreateDeviceAndSwapChain(
NULL,
D3D10_DRIVER_TYPE_HARDWARE,
NULL,
0,
D3D10_SDK_VERSION,
&scd,
&swapchain,
&dev)))
{
return false;
}
public:
D3D10WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
D3DSample(width, height, window_name, cap) {}
~D3D10WinApp() {}
if (FAILED(swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBufferTexture)))
{
return false;
}
if (FAILED(dev->CreateRenderTargetView(pBackBufferTexture, NULL, &backbuffer)))
int create(void)
{
return false;
}
// base initialization
D3DSample::create();
dev->OMSetRenderTargets(1, &backbuffer, NULL);
// initialize DirectX
HRESULT r;
D3D10_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D10_VIEWPORT));
viewport.Width = WIDTH;
viewport.Height = HEIGHT;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 0.0f;
dev->RSSetViewports(1, &viewport);
DXGI_SWAP_CHAIN_DESC scd;
return true;
}
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
bool initDirect3DTextures()
{
{ // Create texture for demo 0
D3D10_TEXTURE2D_DESC desc = { 0 };
desc.Width = WIDTH;
desc.Height = HEIGHT;
desc.MipLevels = desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
if (FAILED(dev->CreateTexture2D(&desc, NULL, &pCPUWriteTexture)))
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = m_width; // set the back buffer width
scd.BufferDesc.Height = m_height; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = m_hWnd; // the window to be used
scd.SampleDesc.Count = 1; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching
r = ::D3D10CreateDeviceAndSwapChain(
NULL,
D3D10_DRIVER_TYPE_HARDWARE,
NULL,
0,
D3D10_SDK_VERSION,
&scd,
&m_pD3D10SwapChain,
&m_pD3D10Dev);
if (FAILED(r))
{
return -1;
}
r = m_pD3D10SwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&m_pBackBuffer);
if (FAILED(r))
{
return -1;
}
r = m_pD3D10Dev->CreateRenderTargetView(m_pBackBuffer, NULL, &m_pRenderTarget);
if (FAILED(r))
{
std::cerr << "Can't create texture for CPU write sample" << std::endl;
return false;
return -1;
}
}
{ // Create Read-only texture
cv::Mat inputMat = getInputTexture();
m_pD3D10Dev->OMSetRenderTargets(1, &m_pRenderTarget, NULL);
D3D10_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D10_VIEWPORT));
viewport.Width = m_width;
viewport.Height = m_height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 0.0f;
m_pD3D10Dev->RSSetViewports(1, &viewport);
D3D10_TEXTURE2D_DESC desc = { 0 };
desc.Width = inputMat.size().width;
desc.Height = inputMat.size().height;
desc.MipLevels = desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.Usage = D3D10_USAGE_IMMUTABLE;
desc.CPUAccessFlags = cv::ocl::useOpenCL() ? 0 : D3D10_CPU_ACCESS_READ;
D3D10_SUBRESOURCE_DATA srInitData;
srInitData.pSysMem = inputMat.ptr();
srInitData.SysMemPitch = (UINT)inputMat.step[0];
desc.Width = m_width;
desc.Height = m_height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
if (FAILED(dev->CreateTexture2D(&desc, &srInitData, &pInputTexture)))
r = m_pD3D10Dev->CreateTexture2D(&desc, NULL, &m_pSurface);
if (FAILED(r))
{
std::cerr << "Can't create texture with input image" << std::endl;
return false;
return -1;
}
}
return true;
}
// initialize OpenCL context of OpenCV lib from DirectX
if (cv::ocl::haveOpenCL())
{
m_oclCtx = cv::directx::ocl::initializeContextFromD3D10Device(m_pD3D10Dev);
}
void cleanUp(void)
{
if (swapchain) swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode
m_oclDevName = cv::ocl::useOpenCL() ?
cv::ocl::Context::getDefault().device(0).name() :
"No OpenCL device";
SAFE_RELEASE(swapchain);
SAFE_RELEASE(pCPUWriteTexture);
SAFE_RELEASE(pInputTexture);
SAFE_RELEASE(pBackBufferTexture);
SAFE_RELEASE(backbuffer);
SAFE_RELEASE(dev);
}
return 0;
} // create()
void render(void)
{
// check to make sure you have a valid Direct3D device
CV_Assert(dev);
// get media data on DX surface for further processing
int get_surface(ID3D10Texture2D** ppSurface)
{
HRESULT r;
if (!m_cap.read(m_frame_bgr))
return -1;
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA);
UINT subResource = ::D3D10CalcSubresource(0, 0, 1);
D3D10_MAPPED_TEXTURE2D mappedTex;
r = m_pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
// copy video frame data to surface
m_frame_rgba.copyTo(m);
m_pSurface->Unmap(subResource);
*ppSurface = m_pSurface;
return 0;
} // get_surface()
// process and render media data
int render()
{
try
{
if (m_shutdown)
return 0;
HRESULT r;
ID3D10Texture2D* pSurface;
r = get_surface(&pSurface);
if (FAILED(r))
{
return -1;
}
switch (m_mode)
{
case MODE_NOP:
// no processing
break;
case MODE_CPU:
{
// process video frame on CPU
UINT subResource = ::D3D10CalcSubresource(0, 0, 1);
D3D10_MAPPED_TEXTURE2D mappedTex;
r = m_pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
if (!m_disableProcessing)
{
// blur D3D10 surface with OpenCV on CPU
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7));
}
m_pSurface->Unmap(subResource);
break;
}
case MODE_GPU:
{
// process video frame on GPU
cv::UMat u;
cv::directx::convertFromD3D10Texture2D(pSurface, u);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on GPU with OpenCL
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7));
}
cv::directx::convertToD3D10Texture2D(u, pSurface);
break;
}
} // switch
print_info(pSurface, m_mode, getFps(), m_oclDevName);
// traditional DX render pipeline:
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
m_pD3D10Dev->CopyResource(m_pBackBuffer, pSurface);
// present the back buffer contents to the display
// switch the back buffer and the front buffer
r = m_pD3D10SwapChain->Present(0, 0);
if (FAILED(r))
{
return -1;
}
} // try
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
return 0;
} // render()
void print_info(ID3D10Texture2D* pSurface, int mode, float fps, cv::String oclDevName)
{
HRESULT r;
UINT subResource = ::D3D10CalcSubresource(0, 0, 1);
D3D10_MAPPED_TEXTURE2D mappedTex;
r = pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
cv::String strMode = cv::format("%s", m_modeStr[mode].c_str());
cv::String strFPS = cv::format("%2.1f", fps);
cv::String strDevName = cv::format("%s", oclDevName.c_str());
cv::putText(m, strMode, cv::Point(0, 16), 1, 0.8, cv::Scalar(0, 0, 0));
cv::putText(m, strFPS, cv::Point(0, 32), 1, 0.8, cv::Scalar(0, 0, 0));
cv::putText(m, strDevName, cv::Point(0, 48), 1, 0.8, cv::Scalar(0, 0, 0));
m_pSurface->Unmap(subResource);
return;
} // print_info()
int cleanup(void)
{
SAFE_RELEASE(m_pSurface);
SAFE_RELEASE(m_pBackBuffer);
SAFE_RELEASE(m_pD3D10SwapChain);
SAFE_RELEASE(m_pRenderTarget);
SAFE_RELEASE(m_pD3D10Dev);
D3DSample::cleanup();
return 0;
} // cleanup()
private:
ID3D10Device* m_pD3D10Dev;
IDXGISwapChain* m_pD3D10SwapChain;
ID3D10Texture2D* m_pBackBuffer;
ID3D10Texture2D* m_pSurface;
ID3D10RenderTargetView* m_pRenderTarget;
cv::ocl::Context m_oclCtx;
cv::String m_oclPlatformName;
cv::String m_oclDevName;
};
renderToD3DObject();
// switch the back buffer and the front buffer
swapchain->Present(0, 0);
}
// main func
ENTRY_POINT(D3D10WinApp, "D3D10 interop sample");
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d3d10.h>
#include <string>
#include <iostream>
#include <queue>
#include "opencv2/core.hpp"
#include "opencv2/core/directx.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "winapp.hpp"
#pragma comment (lib, "d3d10.lib")
class D3D10WinApp : public WinApp
{
public:
D3D10WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
WinApp(width, height, window_name)
{
m_shutdown = false;
m_mode = 0;
m_modeStr[0] = cv::String("No processing");
m_modeStr[1] = cv::String("Processing on CPU");
m_modeStr[2] = cv::String("Processing on GPU");
m_disableProcessing = false;
m_cap = cap;
}
~D3D10WinApp() {}
int onClose(void)
{
m_shutdown = true;
cleanup();
::DestroyWindow(m_hWnd);
return 0;
}
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CHAR:
if (wParam >= '0' && wParam <= '2')
{
m_mode = (char)wParam - '0';
return 0;
}
else if (wParam == VK_SPACE)
{
m_disableProcessing = !m_disableProcessing;
return 0;
}
else if (wParam == VK_ESCAPE)
{
return onClose();
}
break;
case WM_CLOSE:
return onClose();
case WM_DESTROY:
::PostQuitMessage(0);
return 0;
}
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
static float getFps()
{
static std::queue<int64> time_queue;
int64 now = cv::getTickCount();
int64 then = 0;
time_queue.push(now);
if (time_queue.size() >= 2)
then = time_queue.front();
if (time_queue.size() >= 25)
time_queue.pop();
return time_queue.size() * (float)cv::getTickFrequency() / (now - then);
}
int init(void)
{
HRESULT r;
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = m_width; // set the back buffer width
scd.BufferDesc.Height = m_height; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = m_hWnd; // the window to be used
scd.SampleDesc.Count = 1; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching
r = ::D3D10CreateDeviceAndSwapChain(
NULL,
D3D10_DRIVER_TYPE_HARDWARE,
NULL,
0,
D3D10_SDK_VERSION,
&scd,
&m_pD3D10SwapChain,
&m_pD3D10Dev);
if (FAILED(r))
{
return -1;
}
r = m_pD3D10SwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&m_pBackBuffer);
if (FAILED(r))
{
return -1;
}
r = m_pD3D10Dev->CreateRenderTargetView(m_pBackBuffer, NULL, &m_pRenderTarget);
if (FAILED(r))
{
return -1;
}
m_pD3D10Dev->OMSetRenderTargets(1, &m_pRenderTarget, NULL);
D3D10_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D10_VIEWPORT));
viewport.Width = m_width;
viewport.Height = m_height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 0.0f;
m_pD3D10Dev->RSSetViewports(1, &viewport);
D3D10_TEXTURE2D_DESC desc = { 0 };
desc.Width = m_width;
desc.Height = m_height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
r = m_pD3D10Dev->CreateTexture2D(&desc, NULL, &m_pSurface);
if (FAILED(r))
{
std::cerr << "Can't create texture with input image" << std::endl;
return -1;
}
if (cv::ocl::haveOpenCL())
{
m_oclCtx = cv::directx::ocl::initializeContextFromD3D10Device(m_pD3D10Dev);
}
m_oclDevName = cv::ocl::useOpenCL() ?
cv::ocl::Context::getDefault().device(0).name() :
"No OpenCL device";
return 0;
} // init()
int get_surface(ID3D10Texture2D** ppSurface)
{
HRESULT r;
if (!m_cap.read(m_frame_bgr))
return -1;
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA);
UINT subResource = ::D3D10CalcSubresource(0, 0, 1);
D3D10_MAPPED_TEXTURE2D mappedTex;
r = m_pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
// copy video frame data to surface
m_frame_rgba.copyTo(m);
m_pSurface->Unmap(subResource);
*ppSurface = m_pSurface;
return 0;
}
void print_info(ID3D10Texture2D* pSurface, int mode, float fps, cv::String oclDevName)
{
HRESULT r;
UINT subResource = ::D3D10CalcSubresource(0, 0, 1);
D3D10_MAPPED_TEXTURE2D mappedTex;
r = pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
cv::String strMode = cv::format("%s", m_modeStr[mode].c_str());
cv::String strFPS = cv::format("%2.1f", fps);
cv::String strDevName = cv::format("%s", oclDevName.c_str());
cv::putText(m, strMode, cv::Point(0, 16), 1, 0.8, cv::Scalar(0, 0, 0));
cv::putText(m, strFPS, cv::Point(0, 32), 1, 0.8, cv::Scalar(0, 0, 0));
cv::putText(m, strDevName, cv::Point(0, 48), 1, 0.8, cv::Scalar(0, 0, 0));
m_pSurface->Unmap(subResource);
return;
}
int render()
{
try
{
if (m_shutdown)
return 0;
HRESULT r;
ID3D10Texture2D* pSurface;
r = get_surface(&pSurface);
if (FAILED(r))
{
return -1;
}
switch (m_mode)
{
case 0:
// no processing
break;
case 1:
{
// process video frame on CPU
UINT subResource = ::D3D10CalcSubresource(0, 0, 1);
D3D10_MAPPED_TEXTURE2D mappedTex;
r = m_pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
if (!m_disableProcessing)
{
// blur D3D10 surface with OpenCV on CPU
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7));
}
m_pSurface->Unmap(subResource);
break;
}
case 2:
{
// process video frame on GPU
cv::UMat u;
cv::directx::convertFromD3D10Texture2D(pSurface, u);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on GPU with OpenCL
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7));
}
cv::directx::convertToD3D10Texture2D(u, pSurface);
break;
}
} // switch
print_info(pSurface, m_mode, getFps(), m_oclDevName);
// traditional DX render pipeline:
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
m_pD3D10Dev->CopyResource(m_pBackBuffer, pSurface);
// present the back buffer contents to the display
// switch the back buffer and the front buffer
r = m_pD3D10SwapChain->Present(0, 0);
if (FAILED(r))
{
return -1;
}
}
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
return 0;
}
int cleanup(void)
{
SAFE_RELEASE(m_pSurface);
SAFE_RELEASE(m_pBackBuffer);
SAFE_RELEASE(m_pD3D10SwapChain);
SAFE_RELEASE(m_pRenderTarget);
SAFE_RELEASE(m_pD3D10Dev);
return 0;
}
private:
bool m_shutdown;
int m_mode;
cv::String m_modeStr[3];
int m_disableProcessing;
ID3D10Device* m_pD3D10Dev;
IDXGISwapChain* m_pD3D10SwapChain;
ID3D10Texture2D* m_pBackBuffer;
ID3D10Texture2D* m_pSurface;
ID3D10RenderTargetView* m_pRenderTarget;
cv::VideoCapture m_cap;
cv::Mat m_frame_bgr;
cv::Mat m_frame_rgba;
cv::ocl::Context m_oclCtx;
cv::String m_oclPlatformName;
cv::String m_oclDevName;
};
using namespace cv;
int main(int argc, char** argv)
{
cv::VideoCapture cap;
if (argc > 1)
{
cap.open(argv[1]);
}
else
cap.open(0);
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH);
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT);
std::string wndname = "D3D10 Window";
D3D10WinApp app(width, height, wndname, cap);
try
{
app.Create();
return app.run();
}
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
catch (...)
{
std::cerr << "FATAL ERROR: Unknown exception" << std::endl;
return 11;
}
}
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")
#define USE_D3D11
#define WINDOW_NAME "OpenCV Direct3D 11 Sample"
#include "opencv2/core.hpp"
#include "opencv2/core/directx.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "d3dsample.hpp"
IDXGISwapChain *swapchain = NULL;
ID3D11Device *dev = NULL;
ID3D11DeviceContext *devcon = NULL;
ID3D11Texture2D *pBackBufferTexture = NULL;
ID3D11Texture2D *pCPUWriteTexture = NULL;
ID3D11Texture2D *pInputTexture = NULL;
ID3D11RenderTargetView *backbuffer = NULL;
#pragma comment (lib, "d3d11.lib")
#include "d3d_base.inl.hpp"
bool initDirect3D()
using namespace std;
using namespace cv;
class D3D11WinApp : public D3DSample
{
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = WIDTH; // set the back buffer width
scd.BufferDesc.Height = HEIGHT; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 1; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching
if (FAILED(D3D11CreateDeviceAndSwapChain(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
0,
NULL,
0,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon)))
{
return false;
}
public:
D3D11WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
D3DSample(width, height, window_name, cap) {}
~D3D11WinApp() {}
if (FAILED(swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBufferTexture)))
{
return false;
}
if (FAILED(dev->CreateRenderTargetView(pBackBufferTexture, NULL, &backbuffer)))
int create(void)
{
return false;
}
// base initialization
D3DSample::create();
devcon->OMSetRenderTargets(1, &backbuffer, NULL);
// initialize DirectX
HRESULT r;
D3D11_VIEWPORT viewport = { 0 };
viewport.Width = WIDTH;
viewport.Height = HEIGHT;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 0.0f;
devcon->RSSetViewports(1, &viewport);
DXGI_SWAP_CHAIN_DESC scd;
return true;
}
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
bool initDirect3DTextures()
{
{ // Create texture for demo 0
D3D11_TEXTURE2D_DESC desc = { 0 };
desc.Width = WIDTH;
desc.Height = HEIGHT;
desc.MipLevels = desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (FAILED(dev->CreateTexture2D(&desc, NULL, &pCPUWriteTexture)))
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = m_width; // set the back buffer width
scd.BufferDesc.Height = m_height; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = m_hWnd; // the window to be used
scd.SampleDesc.Count = 1; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching
r = ::D3D11CreateDeviceAndSwapChain(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
0,
NULL,
0,
D3D11_SDK_VERSION,
&scd,
&m_pD3D11SwapChain,
&m_pD3D11Dev,
NULL,
&m_pD3D11Ctx);
if (FAILED(r))
{
return -1;
}
r = m_pD3D11SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&m_pBackBuffer);
if (FAILED(r))
{
return -1;
}
r = m_pD3D11Dev->CreateRenderTargetView(m_pBackBuffer, NULL, &m_pRenderTarget);
if (FAILED(r))
{
std::cerr << "Can't create texture for CPU write sample" << std::endl;
return false;
return -1;
}
}
{ // Create Read-only texture
cv::Mat inputMat = getInputTexture();
m_pD3D11Ctx->OMSetRenderTargets(1, &m_pRenderTarget, NULL);
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.Width = (float)m_width;
viewport.Height = (float)m_height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 0.0f;
m_pD3D11Ctx->RSSetViewports(1, &viewport);
D3D11_TEXTURE2D_DESC desc = { 0 };
desc.Width = inputMat.size().width;
desc.Height = inputMat.size().height;
desc.MipLevels = desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.CPUAccessFlags = cv::ocl::useOpenCL() ? 0 : D3D11_CPU_ACCESS_READ;
D3D11_SUBRESOURCE_DATA srInitData;
srInitData.pSysMem = inputMat.ptr();
srInitData.SysMemPitch = (UINT)inputMat.step[0];
desc.Width = m_width;
desc.Height = m_height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (FAILED(dev->CreateTexture2D(&desc, &srInitData, &pInputTexture)))
r = m_pD3D11Dev->CreateTexture2D(&desc, NULL, &m_pSurface);
if (FAILED(r))
{
std::cerr << "Can't create texture with input image" << std::endl;
return false;
return -1;
}
}
return true;
}
// initialize OpenCL context of OpenCV lib from DirectX
if (cv::ocl::haveOpenCL())
{
m_oclCtx = cv::directx::ocl::initializeContextFromD3D11Device(m_pD3D11Dev);
}
void cleanUp(void)
{
if (swapchain) swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode
m_oclDevName = cv::ocl::useOpenCL() ?
cv::ocl::Context::getDefault().device(0).name() :
"No OpenCL device";
SAFE_RELEASE(swapchain);
SAFE_RELEASE(pCPUWriteTexture);
SAFE_RELEASE(pInputTexture);
SAFE_RELEASE(pBackBufferTexture);
SAFE_RELEASE(backbuffer);
SAFE_RELEASE(dev);
SAFE_RELEASE(devcon);
}
return 0;
} // create()
void render(void)
{
// check to make sure you have a valid Direct3D device
CV_Assert(dev);
// get media data on DX surface for further processing
int get_surface(ID3D11Texture2D** ppSurface)
{
HRESULT r;
if (!m_cap.read(m_frame_bgr))
return -1;
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA);
UINT subResource = ::D3D11CalcSubresource(0, 0, 1);
D3D11_MAPPED_SUBRESOURCE mappedTex;
r = m_pD3D11Ctx->Map(m_pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
// copy video frame data to surface
m_frame_rgba.copyTo(m);
m_pD3D11Ctx->Unmap(m_pSurface, subResource);
*ppSurface = m_pSurface;
return 0;
} // get_surface()
// process and render media data
int render()
{
try
{
if (m_shutdown)
return 0;
HRESULT r;
ID3D11Texture2D* pSurface;
r = get_surface(&pSurface);
if (FAILED(r))
{
return -1;
}
switch (m_mode)
{
case MODE_NOP:
// no processing
break;
case MODE_CPU:
{
// process video frame on CPU
UINT subResource = ::D3D11CalcSubresource(0, 0, 1);
D3D11_MAPPED_SUBRESOURCE mappedTex;
r = m_pD3D11Ctx->Map(m_pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
if (!m_disableProcessing)
{
// blur D3D10 surface with OpenCV on CPU
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7));
}
m_pD3D11Ctx->Unmap(m_pSurface, subResource);
break;
}
case MODE_GPU:
{
// process video frame on GPU
cv::UMat u;
cv::directx::convertFromD3D11Texture2D(pSurface, u);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on GPU with OpenCL
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7));
}
cv::directx::convertToD3D11Texture2D(u, pSurface);
break;
}
} // switch
print_info(pSurface, m_mode, getFps(), m_oclDevName);
// traditional DX render pipeline:
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
m_pD3D11Ctx->CopyResource(m_pBackBuffer, pSurface);
// present the back buffer contents to the display
// switch the back buffer and the front buffer
r = m_pD3D11SwapChain->Present(0, 0);
if (FAILED(r))
{
return -1;
}
} // try
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
return 0;
} // render()
void print_info(ID3D11Texture2D* pSurface, int mode, float fps, cv::String oclDevName)
{
HRESULT r;
UINT subResource = ::D3D11CalcSubresource(0, 0, 1);
D3D11_MAPPED_SUBRESOURCE mappedTex;
r = m_pD3D11Ctx->Map(pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
cv::String strMode = cv::format("%s", m_modeStr[mode].c_str());
cv::String strFPS = cv::format("%2.1f", fps);
cv::String strDevName = cv::format("%s", oclDevName.c_str());
cv::putText(m, strMode, cv::Point(0, 16), 1, 0.8, cv::Scalar(0, 0, 0));
cv::putText(m, strFPS, cv::Point(0, 32), 1, 0.8, cv::Scalar(0, 0, 0));
cv::putText(m, strDevName, cv::Point(0, 48), 1, 0.8, cv::Scalar(0, 0, 0));
m_pD3D11Ctx->Unmap(pSurface, subResource);
return;
} // printf_info()
int cleanup(void)
{
SAFE_RELEASE(m_pSurface);
SAFE_RELEASE(m_pBackBuffer);
SAFE_RELEASE(m_pD3D11SwapChain);
SAFE_RELEASE(m_pRenderTarget);
SAFE_RELEASE(m_pD3D11Dev);
SAFE_RELEASE(m_pD3D11Ctx);
D3DSample::cleanup();
return 0;
} // cleanup()
private:
ID3D11Device* m_pD3D11Dev;
IDXGISwapChain* m_pD3D11SwapChain;
ID3D11DeviceContext* m_pD3D11Ctx;
ID3D11Texture2D* m_pBackBuffer;
ID3D11Texture2D* m_pSurface;
ID3D11RenderTargetView* m_pRenderTarget;
cv::ocl::Context m_oclCtx;
cv::String m_oclPlatformName;
cv::String m_oclDevName;
};
renderToD3DObject();
// switch the back buffer and the front buffer
swapchain->Present(0, 0);
}
// main func
ENTRY_POINT(D3D11WinApp, "D3D11 interop sample");
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d3d11.h>
#include <string>
#include <iostream>
#include <queue>
#include "opencv2/core.hpp"
#include "opencv2/core/directx.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "winapp.hpp"
#pragma comment (lib, "d3d11.lib")
class D3D11WinApp : public WinApp
{
public:
D3D11WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
WinApp(width, height, window_name)
{
m_shutdown = false;
m_mode = 0;
m_modeStr[0] = cv::String("No processing");
m_modeStr[1] = cv::String("Processing on CPU");
m_modeStr[2] = cv::String("Processing on GPU");
m_disableProcessing = false;
m_cap = cap;
}
~D3D11WinApp() {}
int onClose(void)
{
m_shutdown = true;
cleanup();
::DestroyWindow(m_hWnd);
return 0;
}
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CHAR:
if (wParam >= '0' && wParam <= '2')
{
m_mode = (char)wParam - '0';
return 0;
}
else if (wParam == VK_SPACE)
{
m_disableProcessing = !m_disableProcessing;
return 0;
}
else if (wParam == VK_ESCAPE)
{
return onClose();
}
break;
case WM_CLOSE:
return onClose();
case WM_DESTROY:
::PostQuitMessage(0);
return 0;
}
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
static float getFps()
{
static std::queue<int64> time_queue;
int64 now = cv::getTickCount();
int64 then = 0;
time_queue.push(now);
if (time_queue.size() >= 2)
then = time_queue.front();
if (time_queue.size() >= 25)
time_queue.pop();
return time_queue.size() * (float)cv::getTickFrequency() / (now - then);
}
int init(void)
{
HRESULT r;
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = m_width; // set the back buffer width
scd.BufferDesc.Height = m_height; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = m_hWnd; // the window to be used
scd.SampleDesc.Count = 1; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching
r = ::D3D11CreateDeviceAndSwapChain(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
0,
NULL,
0,
D3D11_SDK_VERSION,
&scd,
&m_pD3D11SwapChain,
&m_pD3D11Dev,
NULL,
&m_pD3D11Ctx);
if (FAILED(r))
{
return -1;
}
r = m_pD3D11SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&m_pBackBuffer);
if (FAILED(r))
{
return -1;
}
r = m_pD3D11Dev->CreateRenderTargetView(m_pBackBuffer, NULL, &m_pRenderTarget);
if (FAILED(r))
{
return -1;
}
m_pD3D11Ctx->OMSetRenderTargets(1, &m_pRenderTarget, NULL);
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.Width = (float)m_width;
viewport.Height = (float)m_height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 0.0f;
m_pD3D11Ctx->RSSetViewports(1, &viewport);
D3D11_TEXTURE2D_DESC desc = { 0 };
desc.Width = m_width;
desc.Height = m_height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
r = m_pD3D11Dev->CreateTexture2D(&desc, NULL, &m_pSurface);
if (FAILED(r))
{
std::cerr << "Can't create texture with input image" << std::endl;
return -1;
}
if (cv::ocl::haveOpenCL())
{
m_oclCtx = cv::directx::ocl::initializeContextFromD3D11Device(m_pD3D11Dev);
}
m_oclDevName = cv::ocl::useOpenCL() ?
cv::ocl::Context::getDefault().device(0).name() :
"No OpenCL device";
return 0;
} // init()
int get_surface(ID3D11Texture2D** ppSurface)
{
HRESULT r;
if (!m_cap.read(m_frame_bgr))
return -1;
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA);
UINT subResource = ::D3D11CalcSubresource(0, 0, 1);
D3D11_MAPPED_SUBRESOURCE mappedTex;
r = m_pD3D11Ctx->Map(m_pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
// copy video frame data to surface
m_frame_rgba.copyTo(m);
m_pD3D11Ctx->Unmap(m_pSurface, subResource);
*ppSurface = m_pSurface;
return 0;
}
void print_info(ID3D11Texture2D* pSurface, int mode, float fps, cv::String oclDevName)
{
HRESULT r;
UINT subResource = ::D3D11CalcSubresource(0, 0, 1);
D3D11_MAPPED_SUBRESOURCE mappedTex;
r = m_pD3D11Ctx->Map(pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
cv::String strMode = cv::format("%s", m_modeStr[mode].c_str());
cv::String strFPS = cv::format("%2.1f", fps);
cv::String strDevName = cv::format("%s", oclDevName.c_str());
cv::putText(m, strMode, cv::Point(0, 16), 1, 0.8, cv::Scalar(0, 0, 0));
cv::putText(m, strFPS, cv::Point(0, 32), 1, 0.8, cv::Scalar(0, 0, 0));
cv::putText(m, strDevName, cv::Point(0, 48), 1, 0.8, cv::Scalar(0, 0, 0));
m_pD3D11Ctx->Unmap(pSurface, subResource);
return;
}
int render()
{
try
{
if (m_shutdown)
return 0;
HRESULT r;
ID3D11Texture2D* pSurface;
r = get_surface(&pSurface);
if (FAILED(r))
{
return -1;
}
switch (m_mode)
{
case 0:
// no processing
break;
case 1:
{
// process video frame on CPU
UINT subResource = ::D3D11CalcSubresource(0, 0, 1);
D3D11_MAPPED_SUBRESOURCE mappedTex;
r = m_pD3D11Ctx->Map(m_pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
if (!m_disableProcessing)
{
// blur D3D10 surface with OpenCV on CPU
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7));
}
m_pD3D11Ctx->Unmap(m_pSurface, subResource);
break;
}
case 2:
{
// process video frame on GPU
cv::UMat u;
cv::directx::convertFromD3D11Texture2D(pSurface, u);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on GPU with OpenCL
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7));
}
cv::directx::convertToD3D11Texture2D(u, pSurface);
break;
}
} // switch
print_info(pSurface, m_mode, getFps(), m_oclDevName);
// traditional DX render pipeline:
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
m_pD3D11Ctx->CopyResource(m_pBackBuffer, pSurface);
// present the back buffer contents to the display
// switch the back buffer and the front buffer
r = m_pD3D11SwapChain->Present(0, 0);
if (FAILED(r))
{
return -1;
}
}
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
return 0;
}
int cleanup(void)
{
SAFE_RELEASE(m_pSurface);
SAFE_RELEASE(m_pBackBuffer);
SAFE_RELEASE(m_pD3D11SwapChain);
SAFE_RELEASE(m_pRenderTarget);
SAFE_RELEASE(m_pD3D11Dev);
SAFE_RELEASE(m_pD3D11Ctx);
return 0;
}
private:
bool m_shutdown;
int m_mode;
cv::String m_modeStr[3];
int m_disableProcessing;
ID3D11Device* m_pD3D11Dev;
IDXGISwapChain* m_pD3D11SwapChain;
ID3D11DeviceContext* m_pD3D11Ctx;
ID3D11Texture2D* m_pBackBuffer;
ID3D11Texture2D* m_pSurface;
ID3D11RenderTargetView* m_pRenderTarget;
cv::VideoCapture m_cap;
cv::Mat m_frame_bgr;
cv::Mat m_frame_rgba;
cv::ocl::Context m_oclCtx;
cv::String m_oclPlatformName;
cv::String m_oclDevName;
};
using namespace cv;
int main(int argc, char** argv)
{
cv::VideoCapture cap;
if (argc > 1)
{
cap.open(argv[1]);
}
else
cap.open(0);
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH);
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT);
std::string wndname = "D3D11 Window";
D3D11WinApp app(width, height, wndname, cap);
try
{
app.Create();
return app.run();
}
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
catch (...)
{
std::cerr << "FATAL ERROR: Unknown exception" << std::endl;
return 11;
}
}
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d3d9.h>
#pragma comment (lib, "d3d9.lib")
#define USE_D3D9
#define WINDOW_NAME "OpenCV Direct3D 9 Sample"
#include "opencv2/core.hpp"
#include "opencv2/core/directx.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "d3dsample.hpp"
IDirect3D9 *pD3D = NULL;
IDirect3DDevice9 *dev = NULL;
IDirect3DSurface9 *pBackBuffer = NULL;
IDirect3DSurface9 *pCPUWriteSurface = NULL; // required name
IDirect3DSurface9 *pReadOnlySurface = NULL; // required name
HANDLE readOnlySurfaceShared = 0; // required name
IDirect3DSurface9 *pSurface = NULL; // required name
HANDLE surfaceShared = 0; // required name
#pragma comment (lib, "d3d9.lib")
#include "d3d_base.inl.hpp"
bool initDirect3D(void)
using namespace std;
using namespace cv;
class D3D9WinApp : public D3DSample
{
if (NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
{
return false;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_NOWINDOWCHANGES
| D3DCREATE_MULTITHREADED;
d3dpp.Windowed = true;
d3dpp.Flags = 0;
d3dpp.BackBufferCount = 0;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferHeight = HEIGHT;
d3dpp.BackBufferWidth = WIDTH;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, flags, &d3dpp, &dev)))
{
return false;
}
public:
D3D9WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
D3DSample(width, height, window_name, cap) {}
~D3D9WinApp() {}
if (FAILED(dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)))
int create(void)
{
return false;
}
// base initialization
D3DSample::create();
return true;
}
// initialize DirectX
HRESULT r;
bool initDirect3DTextures()
{
// Note: sharing is not supported on some platforms
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pSurface, NULL/*&surfaceShared*/)))
{
std::cerr << "Can't create surface for result" << std::endl;
return false;
}
m_pD3D9 = ::Direct3DCreate9(D3D_SDK_VERSION);
if (NULL == m_pD3D9)
{
return -1;
}
// Note: sharing is not supported on some platforms
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pReadOnlySurface, NULL/*&readOnlySurfaceShared*/)))
{
std::cerr << "Can't create read only surface" << std::endl;
return false;
}
else
{
IDirect3DSurface9* pTmpSurface;
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pTmpSurface, NULL)))
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING |
D3DCREATE_PUREDEVICE |
D3DCREATE_NOWINDOWCHANGES |
D3DCREATE_MULTITHREADED |
D3DCREATE_FPU_PRESERVE;
D3DPRESENT_PARAMETERS d3dpp;
::ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
d3dpp.Windowed = true;
d3dpp.Flags = 0;
d3dpp.BackBufferCount = 0;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferHeight = m_height;
d3dpp.BackBufferWidth = m_width;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = m_hWnd;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
r = m_pD3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, &m_pD3D9Dev);
if (FAILED(r))
{
std::cerr << "Can't create temp surface for CPU write" << std::endl;
return false;
return -1;
}
D3DLOCKED_RECT memDesc = {0, NULL};
RECT rc = {0, 0, WIDTH, HEIGHT};
if (SUCCEEDED(pTmpSurface->LockRect(&memDesc, &rc, 0)))
r = m_pD3D9Dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer);
if (FAILED(r))
{
cv::Mat m(cv::Size(WIDTH, HEIGHT), CV_8UC4, memDesc.pBits, (int)memDesc.Pitch);
getInputTexture().copyTo(m);
pTmpSurface->UnlockRect();
dev->StretchRect(pTmpSurface, NULL, pReadOnlySurface, NULL, D3DTEXF_NONE);
return -1;
}
else
r = m_pD3D9Dev->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pSurface, NULL);
if (FAILED(r))
{
std::cerr << "Can't LockRect() on surface" << std::endl;
std::cerr << "Can't create surface for result" << std::endl;
return -1;
}
pTmpSurface->Release();
}
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pCPUWriteSurface, NULL)))
{
std::cerr << "Can't create surface for CPU write" << std::endl;
return false;
}
// initialize OpenCL context of OpenCV lib from DirectX
if (cv::ocl::haveOpenCL())
{
m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9Dev);
}
return true;
}
m_oclDevName = cv::ocl::useOpenCL() ?
cv::ocl::Context::getDefault().device(0).name() :
"No OpenCL device";
void render(void)
{
// check to make sure you have a valid Direct3D device
CV_Assert(dev);
return 0;
} // create()
renderToD3DObject();
if (g_sampleType == 0)
// get media data on DX surface for further processing
int get_surface(LPDIRECT3DSURFACE9* ppSurface)
{
// nothing
}
else if (g_sampleType == 1)
HRESULT r;
if (!m_cap.read(m_frame_bgr))
return -1;
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA);
D3DLOCKED_RECT memDesc = { 0, NULL };
RECT rc = { 0, 0, m_width, m_height };
r = m_pSurface->LockRect(&memDesc, &rc, 0);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch);
// copy video frame data to surface
m_frame_rgba.copyTo(m);
r = m_pSurface->UnlockRect();
if (FAILED(r))
{
return r;
}
*ppSurface = m_pSurface;
return 0;
} // get_surface()
// process and render media data
int render()
{
if (FAILED(dev->StretchRect(pCPUWriteSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE)))
try
{
if (m_shutdown)
return 0;
HRESULT r;
LPDIRECT3DSURFACE9 pSurface;
r = get_surface(&pSurface);
if (FAILED(r))
{
return -1;
}
switch (m_mode)
{
case MODE_NOP:
// no processing
break;
case MODE_CPU:
{
// process video frame on CPU
D3DLOCKED_RECT memDesc = { 0, NULL };
RECT rc = { 0, 0, m_width, m_height };
r = pSurface->LockRect(&memDesc, &rc, 0);
if (FAILED(r))
{
return -1;
}
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on CPU
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7));
}
r = pSurface->UnlockRect();
if (FAILED(r))
{
return -1;
}
break;
}
case MODE_GPU:
{
// process video frame on GPU
cv::UMat u;
cv::directx::convertFromDirect3DSurface9(pSurface, u);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on GPU with OpenCL
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7));
}
cv::directx::convertToDirect3DSurface9(u, pSurface);
break;
}
} // switch
print_info(pSurface, m_mode, getFps(), m_oclDevName);
// traditional DX render pipeline:
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
r = m_pD3D9Dev->StretchRect(pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE);
if (FAILED(r))
{
return -1;
}
// present the back buffer contents to the display
r = m_pD3D9Dev->Present(NULL, NULL, NULL, NULL);
if (FAILED(r))
{
return -1;
}
} // try
catch (cv::Exception& e)
{
std::cerr << "Can't StretchRect()" << std::endl;
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
}
else
return 0;
} // render()
void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName)
{
if (FAILED(dev->StretchRect(pSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE)))
HDC hDC;
HRESULT r = pSurface->GetDC(&hDC);
if (FAILED(r))
{
std::cerr << "Can't StretchRect()" << std::endl;
return;
}
HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT);
HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont);
if (hOldFont)
{
TEXTMETRIC tm;
::GetTextMetrics(hDC, &tm);
char buf[256];
int y = 0;
buf[0] = 0;
sprintf(buf, "Mode: %s", m_modeStr[mode].c_str());
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
y += tm.tmHeight;
buf[0] = 0;
sprintf(buf, "FPS: %2.1f", fps);
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
y += tm.tmHeight;
buf[0] = 0;
sprintf(buf, "OpenCL device: %s", oclDevName.c_str());
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
::SelectObject(hDC, hOldFont);
}
}
if (SUCCEEDED(dev -> BeginScene()))
r = pSurface->ReleaseDC(hDC);
return;
} // print_info()
int cleanup(void)
{
// end the scene
dev -> EndScene();
}
SAFE_RELEASE(m_pSurface);
SAFE_RELEASE(m_pBackBuffer);
SAFE_RELEASE(m_pD3D9Dev);
SAFE_RELEASE(m_pD3D9);
D3DSample::cleanup();
return 0;
} // cleanup()
// present the back buffer contents to the display
dev->Present(NULL, NULL, NULL, NULL);
}
private:
LPDIRECT3D9 m_pD3D9;
LPDIRECT3DDEVICE9 m_pD3D9Dev;
LPDIRECT3DSURFACE9 m_pBackBuffer;
LPDIRECT3DSURFACE9 m_pSurface;
cv::ocl::Context m_oclCtx;
cv::String m_oclPlatformName;
cv::String m_oclDevName;
};
void cleanUp (void)
{
SAFE_RELEASE(pCPUWriteSurface);
SAFE_RELEASE(pReadOnlySurface);
SAFE_RELEASE(pSurface);
SAFE_RELEASE(pBackBuffer);
SAFE_RELEASE(dev);
SAFE_RELEASE(pD3D);}
// main func
ENTRY_POINT(D3D9WinApp, "D3D9 interop sample");
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d3d9.h>
#include <string>
#include <iostream>
#include <queue>
#include "opencv2/core.hpp"
#include "opencv2/core/directx.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "winapp.hpp"
#pragma comment (lib, "d3d9.lib")
class D3D9WinApp : public WinApp
{
public:
D3D9WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
WinApp(width, height, window_name)
{
m_shutdown = false;
m_mode = 0;
m_modeStr[0] = cv::String("No processing");
m_modeStr[1] = cv::String("Processing on CPU");
m_modeStr[2] = cv::String("Processing on GPU");
m_disableProcessing = false;
m_cap = cap;
}
~D3D9WinApp() {}
int onClose(void)
{
m_shutdown = true;
cleanup();
::DestroyWindow(m_hWnd);
return 0;
}
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CHAR:
if (wParam >= '0' && wParam <= '2')
{
m_mode = (char)wParam - '0';
return 0;
}
else if (wParam == VK_SPACE)
{
m_disableProcessing = !m_disableProcessing;
return 0;
}
else if (wParam == VK_ESCAPE)
{
return onClose();
}
break;
case WM_CLOSE:
return onClose();
case WM_DESTROY:
::PostQuitMessage(0);
return 0;
}
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
static float getFps()
{
static std::queue<int64> time_queue;
int64 now = cv::getTickCount();
int64 then = 0;
time_queue.push(now);
if (time_queue.size() >= 2)
then = time_queue.front();
if (time_queue.size() >= 25)
time_queue.pop();
return time_queue.size() * (float)cv::getTickFrequency() / (now - then);
}
int init(void)
{
HRESULT r;
m_pD3D9 = ::Direct3DCreate9(D3D_SDK_VERSION);
if (NULL == m_pD3D9)
{
return -1;
}
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING |
D3DCREATE_PUREDEVICE |
D3DCREATE_NOWINDOWCHANGES |
D3DCREATE_MULTITHREADED |
D3DCREATE_FPU_PRESERVE;
D3DPRESENT_PARAMETERS d3dpp;
::ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
d3dpp.Windowed = true;
d3dpp.Flags = 0;
d3dpp.BackBufferCount = 0;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferHeight = m_height;
d3dpp.BackBufferWidth = m_width;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = m_hWnd;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
r = m_pD3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, &m_pD3D9Dev);
if (FAILED(r))
{
return -1;
}
r = m_pD3D9Dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer);
if (FAILED(r))
{
return -1;
}
r = m_pD3D9Dev->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pSurface, NULL);
if (FAILED(r))
{
std::cerr << "Can't create surface for result" << std::endl;
return -1;
}
if (cv::ocl::haveOpenCL())
{
m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9Dev);
}
m_oclDevName = cv::ocl::useOpenCL() ?
cv::ocl::Context::getDefault().device(0).name() :
"No OpenCL device";
return 0;
} // init()
int get_surface(LPDIRECT3DSURFACE9* ppSurface)
{
HRESULT r;
if (!m_cap.read(m_frame_bgr))
return -1;
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA);
D3DLOCKED_RECT memDesc = { 0, NULL };
RECT rc = { 0, 0, m_width, m_height };
r = m_pSurface->LockRect(&memDesc, &rc, 0);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch);
// copy video frame data to surface
m_frame_rgba.copyTo(m);
r = m_pSurface->UnlockRect();
if (FAILED(r))
{
return r;
}
*ppSurface = m_pSurface;
return 0;
}
void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName)
{
HDC hDC;
HRESULT r = pSurface->GetDC(&hDC);
if (FAILED(r))
{
return;
}
HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT);
HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont);
if (hOldFont)
{
TEXTMETRIC tm;
::GetTextMetrics(hDC, &tm);
char buf[256];
int y = 0;
buf[0] = 0;
sprintf(buf, "Mode: %s", m_modeStr[mode].c_str());
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
y += tm.tmHeight;
buf[0] = 0;
sprintf(buf, "FPS: %2.1f", fps);
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
y += tm.tmHeight;
buf[0] = 0;
sprintf(buf, "OpenCL device: %s", oclDevName.c_str());
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
::SelectObject(hDC, hOldFont);
}
r = pSurface->ReleaseDC(hDC);
return;
}
int render()
{
try
{
if (m_shutdown)
return 0;
HRESULT r;
LPDIRECT3DSURFACE9 pSurface;
r = get_surface(&pSurface);
if (FAILED(r))
{
return -1;
}
switch (m_mode)
{
case 0:
// no processing
break;
case 1:
{
// process video frame on CPU
D3DLOCKED_RECT memDesc = { 0, NULL };
RECT rc = { 0, 0, m_width, m_height };
r = pSurface->LockRect(&memDesc, &rc, 0);
if (FAILED(r))
{
return -1;
}
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on CPU
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7));
}
r = pSurface->UnlockRect();
if (FAILED(r))
{
return -1;
}
break;
}
case 2:
{
// process video frame on GPU
cv::UMat u;
cv::directx::convertFromDirect3DSurface9(pSurface, u);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on GPU with OpenCL
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7));
}
cv::directx::convertToDirect3DSurface9(u, pSurface);
break;
}
} // switch
print_info(pSurface, m_mode, getFps(), m_oclDevName);
// traditional DX render pipeline:
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
r = m_pD3D9Dev->StretchRect(pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE);
if (FAILED(r))
{
return -1;
}
// present the back buffer contents to the display
r = m_pD3D9Dev->Present(NULL, NULL, NULL, NULL);
if (FAILED(r))
{
return -1;
}
}
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
return 0;
}
int cleanup(void)
{
SAFE_RELEASE(m_pSurface);
SAFE_RELEASE(m_pBackBuffer);
SAFE_RELEASE(m_pD3D9Dev);
SAFE_RELEASE(m_pD3D9);
return 0;
}
private:
bool m_shutdown;
int m_mode;
cv::String m_modeStr[3];
int m_disableProcessing;
LPDIRECT3D9 m_pD3D9;
LPDIRECT3DDEVICE9 m_pD3D9Dev;
LPDIRECT3DSURFACE9 m_pBackBuffer;
LPDIRECT3DSURFACE9 m_pSurface;
cv::VideoCapture m_cap;
cv::Mat m_frame_bgr;
cv::Mat m_frame_rgba;
cv::ocl::Context m_oclCtx;
cv::String m_oclPlatformName;
cv::String m_oclDevName;
};
using namespace cv;
int main(int argc, char** argv)
{
cv::VideoCapture cap;
if (argc > 1)
{
cap.open(argv[1]);
}
else
cap.open(0);
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH);
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT);
std::string wndname = "D3D9 Window";
D3D9WinApp app(width, height, wndname, cap);
try
{
app.Create();
return app.run();
}
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
catch (...)
{
std::cerr << "FATAL ERROR: Unknown exception" << std::endl;
return 11;
}
}
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d3d9.h>
#pragma comment (lib, "d3d9.lib")
#define USE_D3DEX
#define WINDOW_NAME "OpenCV Direct3D 9 Ex Sample"
#include "opencv2/core.hpp"
#include "opencv2/core/directx.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "d3dsample.hpp"
IDirect3D9Ex *pD3D = NULL;
IDirect3DDevice9Ex *dev = NULL;
IDirect3DSurface9 *pBackBuffer = NULL;
IDirect3DSurface9 *pCPUWriteSurface = NULL; // required name
IDirect3DSurface9 *pReadOnlySurface = NULL; // required name
HANDLE readOnlySurfaceShared = 0; // required name
IDirect3DSurface9 *pSurface = NULL; // required name
HANDLE surfaceShared = 0; // required name
#pragma comment (lib, "d3d9.lib")
#include "d3d_base.inl.hpp"
bool initDirect3D(void)
using namespace std;
using namespace cv;
class D3D9ExWinApp : public D3DSample
{
if (FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D)))
{
return false;
}
D3DDISPLAYMODEEX ddm;
ZeroMemory(&ddm, sizeof(ddm));
ddm.Size = sizeof(D3DDISPLAYMODEEX);
D3DDISPLAYROTATION rotation;
if (FAILED(pD3D->GetAdapterDisplayModeEx(D3DADAPTER_DEFAULT, &ddm, &rotation)))
{
return false;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_NOWINDOWCHANGES
| D3DCREATE_MULTITHREADED;
d3dpp.Windowed = true;
d3dpp.Flags = 0;
d3dpp.BackBufferCount = 0;
d3dpp.BackBufferFormat = ddm.Format;
d3dpp.BackBufferHeight = HEIGHT;
d3dpp.BackBufferWidth = WIDTH;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
if (FAILED(pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, flags, &d3dpp, NULL, &dev)))
{
return false;
}
public:
D3D9ExWinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
D3DSample(width, height, window_name, cap) {}
~D3D9ExWinApp() {}
if (FAILED(dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)))
int create(void)
{
return false;
}
// base initialization
D3DSample::create();
return true;
}
// initialize DirectX
HRESULT r;
bool initDirect3DTextures()
{
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pSurface, &surfaceShared)))
{
std::cerr << "Can't create surface for result" << std::endl;
return false;
}
r = ::Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9Ex);
if (FAILED(r))
{
return -1;
}
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pReadOnlySurface, &readOnlySurfaceShared)))
{
std::cerr << "Can't create read only surface" << std::endl;
return false;
}
else
{
IDirect3DSurface9* pTmpSurface;
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pTmpSurface, NULL)))
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING |
D3DCREATE_PUREDEVICE |
D3DCREATE_NOWINDOWCHANGES |
D3DCREATE_MULTITHREADED |
D3DCREATE_FPU_PRESERVE;
D3DPRESENT_PARAMETERS d3dpp;
::ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
d3dpp.Windowed = true;
d3dpp.Flags = 0;
d3dpp.BackBufferCount = 0;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferHeight = m_height;
d3dpp.BackBufferWidth = m_width;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = m_hWnd;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
r = m_pD3D9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, NULL, &m_pD3D9DevEx);
if (FAILED(r))
{
return -1;
}
r = m_pD3D9DevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer);
if (FAILED(r))
{
std::cerr << "Can't create temp surface for CPU write" << std::endl;
return false;
return -1;
}
D3DLOCKED_RECT memDesc = {0, NULL};
RECT rc = {0, 0, WIDTH, HEIGHT};
if (SUCCEEDED(pTmpSurface->LockRect(&memDesc, &rc, 0)))
r = m_pD3D9DevEx->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pSurface, NULL);
if (FAILED(r))
{
cv::Mat m(cv::Size(WIDTH, HEIGHT), CV_8UC4, memDesc.pBits, (int)memDesc.Pitch);
getInputTexture().copyTo(m);
pTmpSurface->UnlockRect();
dev->StretchRect(pTmpSurface, NULL, pReadOnlySurface, NULL, D3DTEXF_NONE);
std::cerr << "Can't create surface for result" << std::endl;
return -1;
}
else
// initialize OpenCL context of OpenCV lib from DirectX
if (cv::ocl::haveOpenCL())
{
std::cerr << "Can't LockRect() on surface" << std::endl;
m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9DevEx);
}
pTmpSurface->Release();
}
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pCPUWriteSurface, NULL)))
m_oclDevName = cv::ocl::useOpenCL() ?
cv::ocl::Context::getDefault().device(0).name() :
"No OpenCL device";
return 0;
} // create()
// get media data on DX surface for further processing
int get_surface(LPDIRECT3DSURFACE9* ppSurface)
{
std::cerr << "Can't create surface for CPU write" << std::endl;
return false;
}
HRESULT r;
return true;
}
if (!m_cap.read(m_frame_bgr))
return -1;
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA);
void render(void)
{
// check to make sure you have a valid Direct3D device
CV_Assert(dev);
D3DLOCKED_RECT memDesc = { 0, NULL };
RECT rc = { 0, 0, m_width, m_height };
renderToD3DObject();
r = m_pSurface->LockRect(&memDesc, &rc, 0);
if (FAILED(r))
{
return r;
}
if (g_sampleType == 0)
{
// nothing
}
else if (g_sampleType == 1)
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch);
// copy video frame data to surface
m_frame_rgba.copyTo(m);
r = m_pSurface->UnlockRect();
if (FAILED(r))
{
return r;
}
*ppSurface = m_pSurface;
return 0;
} // get_surface()
// process and render media data
int render()
{
if (FAILED(dev->StretchRect(pCPUWriteSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE)))
try
{
std::cerr << "Can't StretchRect()" << std::endl;
if (m_shutdown)
return 0;
HRESULT r;
LPDIRECT3DSURFACE9 pSurface;
r = get_surface(&pSurface);
if (FAILED(r))
{
return -1;
}
switch (m_mode)
{
case MODE_NOP:
// no processing
break;
case MODE_CPU:
{
// process video frame on CPU
D3DLOCKED_RECT memDesc = { 0, NULL };
RECT rc = { 0, 0, m_width, m_height };
r = pSurface->LockRect(&memDesc, &rc, 0);
if (FAILED(r))
{
return -1;
}
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on CPU
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7));
}
r = pSurface->UnlockRect();
if (FAILED(r))
{
return -1;
}
break;
}
case MODE_GPU:
{
// process video frame on GPU
cv::UMat u;
cv::directx::convertFromDirect3DSurface9(pSurface, u);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on GPU with OpenCL
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7));
}
cv::directx::convertToDirect3DSurface9(u, pSurface);
break;
}
} // switch
print_info(pSurface, m_mode, getFps(), m_oclDevName);
// traditional DX render pipeline:
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
r = m_pD3D9DevEx->StretchRect(pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE);
if (FAILED(r))
{
return -1;
}
// present the back buffer contents to the display
r = m_pD3D9DevEx->Present(NULL, NULL, NULL, NULL);
if (FAILED(r))
{
return -1;
}
} // try
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
}
else
return 0;
} // render()
void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName)
{
if (FAILED(dev->StretchRect(pSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE)))
HDC hDC;
HRESULT r = pSurface->GetDC(&hDC);
if (FAILED(r))
{
std::cerr << "Can't StretchRect()" << std::endl;
return;
}
HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT);
HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont);
if (hOldFont)
{
TEXTMETRIC tm;
::GetTextMetrics(hDC, &tm);
char buf[256];
int y = 0;
buf[0] = 0;
sprintf(buf, "Mode: %s", m_modeStr[mode].c_str());
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
y += tm.tmHeight;
buf[0] = 0;
sprintf(buf, "FPS: %2.1f", fps);
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
y += tm.tmHeight;
buf[0] = 0;
sprintf(buf, "OpenCL device: %s", oclDevName.c_str());
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
::SelectObject(hDC, hOldFont);
}
}
if (SUCCEEDED(dev -> BeginScene()))
r = pSurface->ReleaseDC(hDC);
return;
} // print_info()
int cleanup(void)
{
// end the scene
dev -> EndScene();
}
SAFE_RELEASE(m_pSurface);
SAFE_RELEASE(m_pBackBuffer);
SAFE_RELEASE(m_pD3D9DevEx);
SAFE_RELEASE(m_pD3D9Ex);
D3DSample::cleanup();
return 0;
} // cleanup()
// present the back buffer contents to the display
dev->Present(NULL, NULL, NULL, NULL);
}
private:
LPDIRECT3D9EX m_pD3D9Ex;
LPDIRECT3DDEVICE9EX m_pD3D9DevEx;
LPDIRECT3DSURFACE9 m_pBackBuffer;
LPDIRECT3DSURFACE9 m_pSurface;
cv::ocl::Context m_oclCtx;
cv::String m_oclPlatformName;
cv::String m_oclDevName;
};
void cleanUp (void)
{
SAFE_RELEASE(pCPUWriteSurface);
SAFE_RELEASE(pReadOnlySurface);
SAFE_RELEASE(pSurface);
SAFE_RELEASE(pBackBuffer);
SAFE_RELEASE(dev);
SAFE_RELEASE(pD3D);
}
// main func
ENTRY_POINT(D3D9ExWinApp, "D3D9Ex interop sample");
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d3d9.h>
#include <string>
#include <iostream>
#include <queue>
#include "opencv2/core.hpp"
#include "opencv2/core/directx.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "winapp.hpp"
#pragma comment (lib, "d3d9.lib")
class D3D9ExWinApp : public WinApp
{
public:
D3D9ExWinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
WinApp(width, height, window_name)
{
m_shutdown = false;
m_mode = 0;
m_modeStr[0] = cv::String("No processing");
m_modeStr[1] = cv::String("Processing on CPU");
m_modeStr[2] = cv::String("Processing on GPU");
m_disableProcessing = false;
m_cap = cap;
}
~D3D9ExWinApp() {}
int onClose(void)
{
m_shutdown = true;
cleanup();
::DestroyWindow(m_hWnd);
return 0;
}
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CHAR:
if (wParam >= '0' && wParam <= '2')
{
m_mode = (char)wParam - '0';
return 0;
}
else if (wParam == VK_SPACE)
{
m_disableProcessing = !m_disableProcessing;
return 0;
}
else if (wParam == VK_ESCAPE)
{
return onClose();
}
break;
case WM_CLOSE:
return onClose();
case WM_DESTROY:
::PostQuitMessage(0);
return 0;
}
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
static float getFps()
{
static std::queue<int64> time_queue;
int64 now = cv::getTickCount();
int64 then = 0;
time_queue.push(now);
if (time_queue.size() >= 2)
then = time_queue.front();
if (time_queue.size() >= 25)
time_queue.pop();
return time_queue.size() * (float)cv::getTickFrequency() / (now - then);
}
int init(void)
{
HRESULT r;
r = ::Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9Ex);
if (FAILED(r))
{
return -1;
}
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING |
D3DCREATE_PUREDEVICE |
D3DCREATE_NOWINDOWCHANGES |
D3DCREATE_MULTITHREADED |
D3DCREATE_FPU_PRESERVE;
D3DPRESENT_PARAMETERS d3dpp;
::ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
d3dpp.Windowed = true;
d3dpp.Flags = 0;
d3dpp.BackBufferCount = 0;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferHeight = m_height;
d3dpp.BackBufferWidth = m_width;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = m_hWnd;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
r = m_pD3D9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, NULL, &m_pD3D9DevEx);
if (FAILED(r))
{
return -1;
}
r = m_pD3D9DevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer);
if (FAILED(r))
{
return -1;
}
r = m_pD3D9DevEx->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pSurface, NULL);
if (FAILED(r))
{
std::cerr << "Can't create surface for result" << std::endl;
return -1;
}
if (cv::ocl::haveOpenCL())
{
m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9DevEx);
}
m_oclDevName = cv::ocl::useOpenCL() ?
cv::ocl::Context::getDefault().device(0).name() :
"No OpenCL device";
return 0;
} // init()
int get_surface(LPDIRECT3DSURFACE9* ppSurface)
{
HRESULT r;
if (!m_cap.read(m_frame_bgr))
return -1;
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA);
D3DLOCKED_RECT memDesc = { 0, NULL };
RECT rc = { 0, 0, m_width, m_height };
r = m_pSurface->LockRect(&memDesc, &rc, 0);
if (FAILED(r))
{
return r;
}
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch);
// copy video frame data to surface
m_frame_rgba.copyTo(m);
r = m_pSurface->UnlockRect();
if (FAILED(r))
{
return r;
}
*ppSurface = m_pSurface;
return 0;
}
void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName)
{
HDC hDC;
HRESULT r = pSurface->GetDC(&hDC);
if (FAILED(r))
{
return;
}
HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT);
HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont);
if (hOldFont)
{
TEXTMETRIC tm;
::GetTextMetrics(hDC, &tm);
char buf[256];
int y = 0;
buf[0] = 0;
sprintf(buf, "Mode: %s", m_modeStr[mode].c_str());
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
y += tm.tmHeight;
buf[0] = 0;
sprintf(buf, "FPS: %2.1f", fps);
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
y += tm.tmHeight;
buf[0] = 0;
sprintf(buf, "OpenCL device: %s", oclDevName.c_str());
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
::SelectObject(hDC, hOldFont);
}
r = pSurface->ReleaseDC(hDC);
return;
}
int render()
{
try
{
if (m_shutdown)
return 0;
HRESULT r;
LPDIRECT3DSURFACE9 pSurface;
r = get_surface(&pSurface);
if (FAILED(r))
{
return -1;
}
switch (m_mode)
{
case 0:
// no processing
break;
case 1:
{
// process video frame on CPU
D3DLOCKED_RECT memDesc = { 0, NULL };
RECT rc = { 0, 0, m_width, m_height };
r = pSurface->LockRect(&memDesc, &rc, 0);
if (FAILED(r))
{
return -1;
}
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on CPU
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7));
}
r = pSurface->UnlockRect();
if (FAILED(r))
{
return -1;
}
break;
}
case 2:
{
// process video frame on GPU
cv::UMat u;
cv::directx::convertFromDirect3DSurface9(pSurface, u);
if (!m_disableProcessing)
{
// blur D3D9 surface with OpenCV on GPU with OpenCL
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7));
}
cv::directx::convertToDirect3DSurface9(u, pSurface);
break;
}
} // switch
print_info(pSurface, m_mode, getFps(), m_oclDevName);
// traditional DX render pipeline:
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
r = m_pD3D9DevEx->StretchRect(pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE);
if (FAILED(r))
{
return -1;
}
// present the back buffer contents to the display
r = m_pD3D9DevEx->Present(NULL, NULL, NULL, NULL);
if (FAILED(r))
{
return -1;
}
}
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
return 0;
}
int cleanup(void)
{
SAFE_RELEASE(m_pSurface);
SAFE_RELEASE(m_pBackBuffer);
SAFE_RELEASE(m_pD3D9DevEx);
SAFE_RELEASE(m_pD3D9Ex);
return 0;
}
private:
bool m_shutdown;
int m_mode;
cv::String m_modeStr[3];
int m_disableProcessing;
LPDIRECT3D9EX m_pD3D9Ex;
LPDIRECT3DDEVICE9EX m_pD3D9DevEx;
LPDIRECT3DSURFACE9 m_pBackBuffer;
LPDIRECT3DSURFACE9 m_pSurface;
cv::VideoCapture m_cap;
cv::Mat m_frame_bgr;
cv::Mat m_frame_rgba;
cv::ocl::Context m_oclCtx;
cv::String m_oclPlatformName;
cv::String m_oclDevName;
};
using namespace cv;
int main(int argc, char** argv)
{
cv::VideoCapture cap;
if (argc > 1)
{
cap.open(argv[1]);
}
else
cap.open(0);
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH);
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT);
std::string wndname = "D3D9Ex Window";
D3D9ExWinApp app(width, height, wndname, cap);
try
{
app.Create();
return app.run();
}
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
catch (...)
{
std::cerr << "FATAL ERROR: Unknown exception" << std::endl;
return 11;
}
}
//
// Don't use as a standalone file
//
#include "opencv2/core.hpp"
#include "opencv2/core/utility.hpp" // cv::format
#include "opencv2/imgproc.hpp" // cvtColor
#include "opencv2/imgproc/types_c.h" // cvtColor
#include "opencv2/highgui.hpp" // imread
#include "opencv2/core/directx.hpp"
#include "opencv2/imgcodecs.hpp"
#include <iostream>
#include <queue>
using namespace cv;
using namespace cv::directx;
static const int fontFace = cv::FONT_HERSHEY_DUPLEX;
#if !defined(USE_D3D9) && !defined(USE_D3DEX)
const cv::Scalar frameColor(255,128,0,255);
#else
const cv::Scalar frameColor(0,128,255,255); // BGRA for D3D9
#endif
#define SAFE_RELEASE(p) if (p) { p->Release(); p = NULL; }
const int WIDTH = 1024;
const int HEIGHT = 768;
HINSTANCE hInstance;
HWND hWnd;
// external declaration
bool initDirect3D(void);
bool initDirect3DTextures(void);
void render(void);
void cleanUp (void);
#define USAGE_DESCRIPTION_0 "1 - CPU write via LockRect/Map"
#define USAGE_DESCRIPTION_1 "2* - Mat->D3D"
#define USAGE_DESCRIPTION_2 "3* - D3D->UMat / change UMat / UMat->D3D"
#define USAGE_DESCRIPTION_3 "0 - show input texture without any processing"
#define USAGE_DESCRIPTION_SPACE "SPACE - toggle frame processing (only data transfers)"
static int g_sampleType = 0;
static int g_disableProcessing = false;
// forward declaration
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static bool initWindow()
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(0, IDI_APPLICATION);
wcex.hCursor = LoadCursor(0, IDC_ARROW);
wcex.hbrBackground = 0;
wcex.lpszMenuName = 0L;
wcex.lpszClassName = "OpenCVDirectX";
wcex.hIconSm = 0;
RegisterClassEx(&wcex);
RECT rc = {0, 0, WIDTH, HEIGHT};
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
hWnd = CreateWindow("OpenCVDirectX", WINDOW_NAME,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL);
if (!hWnd)
return false;
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
return true;
}
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_CHAR:
if (wParam >= '0' && wParam <= '3')
{
g_sampleType = (char)wParam - '0';
return 0;
}
else if (wParam == ' ')
{
g_disableProcessing = !g_disableProcessing;
return 0;
}
else if (wParam == VK_ESCAPE)
{
DestroyWindow(hWnd);
return 0;
}
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
static float getFps()
{
static std::queue<int64> time_queue;
int64 now = cv::getTickCount(), then = 0;
time_queue.push(now);
if (time_queue.size() >= 2)
then = time_queue.front();
if (time_queue.size() >= 25)
time_queue.pop();
return time_queue.size() * (float)cv::getTickFrequency() / (now - then);
}
static int bgColor[4] = {0, 0, 0, 0};
static cv::Mat* inputMat = NULL;
static void renderToD3DObject(void)
{
static int frame = 0;
const float fps = getFps();
String deviceName = cv::ocl::useOpenCL() ? cv::ocl::Context::getDefault().device(0).name() : "No OpenCL device";
if ((frame % std::max(1, (int)(fps / 25))) == 0)
{
String msg = format("%s%s: %s, Sample %d, Frame %d, fps %g (%g ms)",
g_disableProcessing ? "(FRAME PROCESSING DISABLED) " : "",
WINDOW_NAME, deviceName.c_str(), g_sampleType,
frame, fps, (int(10 * 1000.0 / fps)) * 0.1);
SetWindowText(hWnd, msg.c_str());
}
// 0..255
int c[4] =
{
std::abs((frame & 0x1ff) - 0x100),
std::abs(((frame * 2) & 0x1ff) - 0x100),
std::abs(((frame / 2) & 0x1ff) - 0x100),
0
};
int c1 = c[0] / 2 - 0x40 - bgColor[0];
int c2 = c[1] / 2 - 0x40 - bgColor[1];
int c3 = c[2] / 2 - 0x40 - bgColor[2];
switch (g_sampleType)
{
case 0:
#if defined(USE_D3D9) || defined (USE_D3DEX)
if (FAILED(dev->StretchRect(pReadOnlySurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE)))
{
std::cerr << "Can't StretchRect()" << std::endl;
}
#elif defined(USE_D3D10)
dev->CopyResource(pBackBufferTexture, pInputTexture);
#elif defined(USE_D3D11)
devcon->CopyResource(pBackBufferTexture, pInputTexture);
#else
#error "Invalid USE_D3D value"
#endif
break;
case 1:
{
int BOXSIZE = 50;
int x = std::abs(((frame * 1) % (2 * (WIDTH - BOXSIZE))) - (WIDTH - BOXSIZE));
int y = std::abs(((frame / 2) % (2 * (HEIGHT - BOXSIZE))) - (HEIGHT - BOXSIZE));
cv::Rect boxRect(x, y, BOXSIZE, BOXSIZE);
#if defined(USE_D3D9) || defined (USE_D3DEX)
D3DLOCKED_RECT memDesc = {0, NULL};
RECT rc = {0, 0, WIDTH, HEIGHT};
if (SUCCEEDED(pCPUWriteSurface->LockRect(&memDesc, &rc, 0)))
{
if (!g_disableProcessing)
{
Mat m(Size(WIDTH, HEIGHT), CV_8UC4, memDesc.pBits, (int)memDesc.Pitch);
inputMat->copyTo(m);
m(boxRect).setTo(Scalar(c[0], c[1], c[2], 255));
}
pCPUWriteSurface->UnlockRect();
}
else
{
std::cerr << "Can't LockRect() on surface" << std::endl;
}
#elif defined(USE_D3D10)
D3D10_MAPPED_TEXTURE2D mappedTex;
if (SUCCEEDED(pCPUWriteTexture->Map( D3D10CalcSubresource(0, 0, 1), D3D10_MAP_WRITE_DISCARD, 0, &mappedTex)))
{
if (!g_disableProcessing)
{
Mat m(Size(WIDTH, HEIGHT), CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
inputMat->copyTo(m);
m(boxRect).setTo(Scalar(c[0], c[1], c[2], 255));
}
pCPUWriteTexture->Unmap(D3D10CalcSubresource(0, 0, 1));
dev->CopyResource(pBackBufferTexture, pCPUWriteTexture);
}
else
{
std::cerr << "Can't Map() texture" << std::endl;
}
#elif defined(USE_D3D11)
D3D11_MAPPED_SUBRESOURCE mappedTex;
if (SUCCEEDED(devcon->Map(pCPUWriteTexture, D3D11CalcSubresource(0, 0, 1), D3D11_MAP_WRITE_DISCARD, 0, &mappedTex)))
{
if (!g_disableProcessing)
{
Mat m(Size(WIDTH, HEIGHT), CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch);
inputMat->copyTo(m);
m(boxRect).setTo(Scalar(c[0], c[1], c[2], 255));
}
devcon->Unmap(pCPUWriteTexture, D3D11CalcSubresource(0, 0, 1));
devcon->CopyResource(pBackBufferTexture, pCPUWriteTexture);
}
else
{
std::cerr << "Can't Map() texture" << std::endl;
}
#else
#error "Invalid USE_D3D value"
#endif
break;
}
case 2:
{
static Mat m;
if (!g_disableProcessing)
{
#if 1
cv::add(*inputMat, Scalar(c1, c2, c3, 255), m);
#else
inputMat->copyTo(m);
#endif
cv::putText(m,
cv::format("Frame %d, fps %g (%g ms)",
frame, fps, (int(10 * 1000.0 / fps)) * 0.1),
cv::Point(8, 80), fontFace, 1, frameColor, 2);
}
else
{
m.create(Size(WIDTH, HEIGHT), CV_8UC4);
}
try
{
#if defined(USE_D3D9) || defined (USE_D3DEX)
convertToDirect3DSurface9(m, pSurface, (void*)surfaceShared);
#elif defined(USE_D3D10)
convertToD3D10Texture2D(m, pBackBufferTexture);
#elif defined(USE_D3D11)
convertToD3D11Texture2D(m, pBackBufferTexture);
#else
#error "Invalid USE_D3D value"
#endif
}
catch (cv::Exception& e)
{
std::cerr << "Can't convert to D3D object: exception: " << e.what() << std::endl;
}
catch (...)
{
std::cerr << "Can't convert to D3D object" << std::endl;
}
break;
}
case 3:
{
static UMat tmp;
try
{
#if defined(USE_D3D9) || defined (USE_D3DEX)
convertFromDirect3DSurface9(pReadOnlySurface, tmp, (void*)readOnlySurfaceShared);
#elif defined(USE_D3D10)
convertFromD3D10Texture2D(pInputTexture, tmp);
#elif defined(USE_D3D11)
convertFromD3D11Texture2D(pInputTexture, tmp);
#else
#error "Invalid USE_D3D value"
#endif
}
catch (cv::Exception& e)
{
std::cerr << "Can't convert from D3D object: exception: " << e.what() << std::endl;
}
catch (...)
{
std::cerr << "Can't convert from D3D object" << std::endl;
}
static UMat res;
if (!g_disableProcessing)
{
cv::add(tmp, Scalar(c1, c2, c3, 255), res);
}
else
{
res = tmp;
}
try
{
#if defined(USE_D3D9) || defined (USE_D3DEX)
convertToDirect3DSurface9(res, pSurface, (void*)surfaceShared);
#elif defined(USE_D3D10)
convertToD3D10Texture2D(res, pBackBufferTexture);
#elif defined(USE_D3D11)
convertToD3D11Texture2D(res, pBackBufferTexture);
#else
#error "Invalid USE_D3D value"
#endif
}
catch (cv::Exception& e)
{
std::cerr << "Can't convert to D3D object: exception: " << e.what() << std::endl;
}
catch (...)
{
std::cerr << "Can't convert to D3D object" << std::endl;
}
break;
}
}
frame++;
}
static cv::Mat getInputTexture()
{
cv::Mat inputMat = cv::imread("input.bmp", cv::IMREAD_COLOR);
if (inputMat.depth() != CV_8U)
{
inputMat.convertTo(inputMat, CV_8U);
}
if (inputMat.type() == CV_8UC3)
{
cv::cvtColor(inputMat, inputMat, CV_RGB2BGRA);
}
if (inputMat.type() != CV_8UC4 || inputMat.size().area() == 0)
{
std::cerr << "Invalid input image format. Generate other" << std::endl;
inputMat.create(cv::Size(WIDTH, HEIGHT), CV_8UC4);
inputMat.setTo(cv::Scalar(0, 0, 255, 255));
bgColor[0] = -128; bgColor[1] = -128; bgColor[2] = 127; bgColor[3] = -128;
}
if (inputMat.size().width != WIDTH || inputMat.size().height != HEIGHT)
{
cv::resize(inputMat, inputMat, cv::Size(WIDTH, HEIGHT));
}
String deviceName = cv::ocl::useOpenCL() ? cv::ocl::Context::getDefault().device(0).name() : "No OpenCL device";
cv::Scalar color(64, 255, 64, 255);
cv::putText(inputMat,
cv::format("OpenCL Device name: %s", deviceName.c_str()),
cv::Point(8,32), fontFace, 1, color);
cv::putText(inputMat, WINDOW_NAME, cv::Point(50, HEIGHT - 32), fontFace, 1, color);
cv::putText(inputMat, USAGE_DESCRIPTION_0, cv::Point(30, 128), fontFace, 1, color);
cv::putText(inputMat, USAGE_DESCRIPTION_1, cv::Point(30, 192), fontFace, 1, color);
cv::putText(inputMat, USAGE_DESCRIPTION_2, cv::Point(30, 256), fontFace, 1, color);
cv::putText(inputMat, USAGE_DESCRIPTION_3, cv::Point(30, 320), fontFace, 1, color);
cv::putText(inputMat, USAGE_DESCRIPTION_SPACE, cv::Point(30, 448), fontFace, 1, color);
#if defined(USE_D3D9) || defined (USE_D3DEX)
cv::cvtColor(inputMat, inputMat, CV_RGBA2BGRA);
std::swap(bgColor[0], bgColor[2]);
#endif
// Make a global copy
::inputMat = new cv::Mat(inputMat);
return inputMat;
}
static int mainLoop()
{
hInstance = GetModuleHandle(NULL);
if (!initWindow())
CV_Error(cv::Error::StsError, "Can't create window");
if (!initDirect3D())
CV_Error(cv::Error::StsError, "Can't create D3D object");
if (cv::ocl::haveOpenCL())
{
#if defined(USE_D3D9)
cv::ocl::Context& ctx = cv::directx::ocl::initializeContextFromDirect3DDevice9(dev);
#elif defined (USE_D3DEX)
cv::ocl::Context& ctx = cv::directx::ocl::initializeContextFromDirect3DDevice9Ex(dev);
#elif defined(USE_D3D10)
cv::ocl::Context& ctx = cv::directx::ocl::initializeContextFromD3D10Device(dev);
#elif defined(USE_D3D11)
cv::ocl::Context& ctx = cv::directx::ocl::initializeContextFromD3D11Device(dev);
#else
#error "Invalid USE_D3D value"
#endif
std::cout << "Selected device: " << ctx.device(0).name().c_str() << std::endl;
g_sampleType = 2;
}
else
{
std::cerr << "OpenCL is not available. DirectX - OpenCL interop will not work" << std::endl;
}
if (!initDirect3DTextures())
CV_Error(cv::Error::StsError, "Can't create D3D texture object");
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
render();
}
}
cleanUp();
return static_cast<int>(msg.wParam);
}
int main(int /*argc*/, char ** /*argv*/)
{
try
{
return mainLoop();
}
catch (cv::Exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 10;
}
catch (...)
{
std::cerr << "FATAL ERROR: Unknown exception" << std::endl;
return 11;
}
}
#include <string>
#include <iostream>
#include <queue>
#include "opencv2/core.hpp"
#include "opencv2/core/directx.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "winapp.hpp"
#define SAFE_RELEASE(p) if (p) { p->Release(); p = NULL; }
class D3DSample : public WinApp
{
public:
enum MODE
{
MODE_NOP,
MODE_CPU,
MODE_GPU
};
D3DSample(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
WinApp(width, height, window_name)
{
m_shutdown = false;
m_mode = MODE_NOP;
m_modeStr[0] = cv::String("No processing");
m_modeStr[1] = cv::String("Processing on CPU");
m_modeStr[2] = cv::String("Processing on GPU");
m_disableProcessing = false;
m_cap = cap;
}
~D3DSample() {}
virtual int create() { return WinApp::create(); }
virtual int render() = 0;
virtual int cleanup()
{
m_shutdown = true;
return WinApp::cleanup();
}
static float getFps()
{
static std::queue<int64> time_queue;
int64 now = cv::getTickCount();
int64 then = 0;
time_queue.push(now);
if (time_queue.size() >= 2)
then = time_queue.front();
if (time_queue.size() >= 25)
time_queue.pop();
size_t sz = time_queue.size();
float fps = sz * (float)cv::getTickFrequency() / (now - then);
return fps;
}
protected:
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CHAR:
if (wParam >= '0' && wParam <= '2')
{
m_mode = static_cast<MODE>((char)wParam - '0');
return 0;
}
else if (wParam == VK_SPACE)
{
m_disableProcessing = !m_disableProcessing;
return 0;
}
else if (wParam == VK_ESCAPE)
{
return cleanup();
}
break;
case WM_CLOSE:
return cleanup();
case WM_DESTROY:
::PostQuitMessage(0);
return 0;
}
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
// do render at idle
virtual int idle() { return render(); }
protected:
bool m_shutdown;
bool m_disableProcessing;
MODE m_mode;
cv::String m_modeStr[3];
cv::VideoCapture m_cap;
cv::Mat m_frame_bgr;
cv::Mat m_frame_rgba;
};
#define ENTRY_POINT(type, title) \
static void help() \
{ \
printf( \
"\nSample demonstrating interoperability of DirectX and OpenCL with OpenCV.\n" \
"Hot keys: \n" \
" 0 - no processing\n" \
" 1 - blur DX surface on CPU through OpenCV\n" \
" 2 - blur DX surface on GPU through OpenCV using OpenCL\n" \
" ESC - exit\n\n"); \
} \
\
static const char* keys = \
{ \
"{c camera | true | use camera or not}" \
"{f file | | movie file name }" \
"{h help | false | print help info }" \
}; \
\
\
int main(int argc, char** argv) \
{ \
cv::CommandLineParser parser(argc, argv, keys); \
bool useCamera = parser.has("camera"); \
string file = parser.get<string>("file"); \
bool showHelp = parser.get<bool>("help"); \
\
if (showHelp) \
help(); \
\
parser.printMessage(); \
\
cv::VideoCapture cap; \
\
if (useCamera) \
cap.open(0); \
else \
cap.open(file.c_str()); \
\
if (!cap.isOpened()) \
{ \
printf("can not open camera or video file\n"); \
return -1; \
} \
\
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH); \
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT); \
\
std::string wndname = title; \
\
type app(width, height, wndname, cap); \
\
try \
{ \
app.create(); \
return app.run(); \
} \
\
catch (cv::Exception& e) \
{ \
std::cerr << "Exception: " << e.what() << std::endl; \
return 10; \
} \
\
catch (...) \
{ \
std::cerr << "FATAL ERROR: Unknown exception" << std::endl; \
return 11; \
} \
}
......@@ -5,8 +5,6 @@
#define WINCLASS "WinAppWnd"
#define SAFE_RELEASE(p) if (p) { p->Release(); p = NULL; }
class WinApp
{
public:
......@@ -16,14 +14,13 @@ public:
m_height = height;
m_window_name = window_name;
m_hInstance = ::GetModuleHandle(NULL);
m_hWnd = 0;
}
virtual ~WinApp()
{
::UnregisterClass(WINCLASS, m_hInstance);
}
virtual ~WinApp() {}
int Create()
virtual int create()
{
WNDCLASSEX wcex;
......@@ -41,9 +38,12 @@ public:
wcex.hIconSm = 0;
ATOM wc = ::RegisterClassEx(&wcex);
if (!wc)
return -1;
RECT rc = { 0, 0, m_width, m_height };
::AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
if(!::AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false))
return -1;
m_hWnd = ::CreateWindow(
(LPCTSTR)wc, m_window_name.c_str(),
......@@ -58,10 +58,9 @@ public:
::UpdateWindow(m_hWnd);
::SetFocus(m_hWnd);
return init();
}
return 0;
} // create()
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) = 0;
int run()
{
......@@ -78,23 +77,32 @@ public:
}
else
{
render();
idle();
}
}
return static_cast<int>(msg.wParam);
}
} // run()
virtual int cleanup()
{
::DestroyWindow(m_hWnd);
::UnregisterClass(WINCLASS, m_hInstance);
return 0;
} // cleanup()
protected:
// dispatch message handling to method of class
static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WinApp* pWnd;
if (message == WM_NCCREATE)
{
LPCREATESTRUCT pCreateStruct = ((LPCREATESTRUCT)lParam);
pWnd = (WinApp*)(pCreateStruct->lpCreateParams);
::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pWnd);
LPCREATESTRUCT pCreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
pWnd = static_cast<WinApp*>(pCreateStruct->lpCreateParams);
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pWnd));
}
pWnd = GetObjectFromWindow(hWnd);
......@@ -103,15 +111,14 @@ protected:
return pWnd->WndProc(hWnd, message, wParam, lParam);
else
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
} // StaticWndProc()
inline static WinApp* GetObjectFromWindow(HWND hWnd)
{
return (WinApp*)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
}
inline static WinApp* GetObjectFromWindow(HWND hWnd) { return (WinApp*)::GetWindowLongPtr(hWnd, GWLP_USERDATA); }
virtual int init() = 0;
virtual int render() = 0;
// actual wnd message handling
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) = 0;
// idle processing
virtual int idle() = 0;
HINSTANCE m_hInstance;
HWND m_hWnd;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment