1 /* 2 // Sample demonstrating interoperability of OpenCV UMat with Direct X surface 3 // At first, the data obtained from video file or camera and 4 // placed onto Direct X surface, 5 // following mapping of this Direct X surface to OpenCV UMat and call cv::Blur 6 // function. The result is mapped back to Direct X surface and rendered through 7 // Direct X API. 8 */ 9 #define WIN32_LEAN_AND_MEAN 10 #include <windows.h> 11 #include <d3d9.h> 12 13 #include "opencv2/core.hpp" 14 #include "opencv2/core/directx.hpp" 15 #include "opencv2/core/ocl.hpp" 16 #include "opencv2/imgproc.hpp" 17 #include "opencv2/videoio.hpp" 18 19 #include "d3dsample.hpp" 20 21 #pragma comment (lib, "d3d9.lib") 22 23 24 using namespace std; 25 using namespace cv; 26 27 class D3D9ExWinApp : public D3DSample 28 { 29 public: 30 D3D9ExWinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) : 31 D3DSample(width, height, window_name, cap) {} 32 33 ~D3D9ExWinApp() {} 34 35 int create(void) 36 { 37 // base initialization 38 D3DSample::create(); 39 40 // initialize DirectX 41 HRESULT r; 42 43 r = ::Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9Ex); 44 if (FAILED(r)) 45 { 46 return -1; 47 } 48 49 DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | 50 D3DCREATE_PUREDEVICE | 51 D3DCREATE_NOWINDOWCHANGES | 52 D3DCREATE_MULTITHREADED | 53 D3DCREATE_FPU_PRESERVE; 54 55 D3DPRESENT_PARAMETERS d3dpp; 56 ::ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); 57 58 d3dpp.Windowed = true; 59 d3dpp.Flags = 0; 60 d3dpp.BackBufferCount = 0; 61 d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; 62 d3dpp.BackBufferHeight = m_height; 63 d3dpp.BackBufferWidth = m_width; 64 d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; 65 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; 66 d3dpp.hDeviceWindow = m_hWnd; 67 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 68 d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; 69 70 r = m_pD3D9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, NULL, &m_pD3D9DevEx); 71 if (FAILED(r)) 72 { 73 return -1; 74 } 75 76 r = m_pD3D9DevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer); 77 if (FAILED(r)) 78 { 79 return -1; 80 } 81 82 r = m_pD3D9DevEx->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pSurface, NULL); 83 if (FAILED(r)) 84 { 85 std::cerr << "Can't create surface for result" << std::endl; 86 return -1; 87 } 88 89 // initialize OpenCL context of OpenCV lib from DirectX 90 if (cv::ocl::haveOpenCL()) 91 { 92 m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9DevEx); 93 } 94 95 m_oclDevName = cv::ocl::useOpenCL() ? 96 cv::ocl::Context::getDefault().device(0).name() : 97 "No OpenCL device"; 98 99 return 0; 100 } // create() 101 102 103 // get media data on DX surface for further processing 104 int get_surface(LPDIRECT3DSURFACE9* ppSurface) 105 { 106 HRESULT r; 107 108 if (!m_cap.read(m_frame_bgr)) 109 return -1; 110 111 cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA); 112 113 D3DLOCKED_RECT memDesc = { 0, NULL }; 114 RECT rc = { 0, 0, m_width, m_height }; 115 116 r = m_pSurface->LockRect(&memDesc, &rc, 0); 117 if (FAILED(r)) 118 { 119 return r; 120 } 121 122 cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch); 123 // copy video frame data to surface 124 m_frame_rgba.copyTo(m); 125 126 r = m_pSurface->UnlockRect(); 127 if (FAILED(r)) 128 { 129 return r; 130 } 131 132 *ppSurface = m_pSurface; 133 134 return 0; 135 } // get_surface() 136 137 138 // process and render media data 139 int render() 140 { 141 try 142 { 143 if (m_shutdown) 144 return 0; 145 146 HRESULT r; 147 LPDIRECT3DSURFACE9 pSurface; 148 149 r = get_surface(&pSurface); 150 if (FAILED(r)) 151 { 152 return -1; 153 } 154 155 switch (m_mode) 156 { 157 case MODE_NOP: 158 // no processing 159 break; 160 161 case MODE_CPU: 162 { 163 // process video frame on CPU 164 D3DLOCKED_RECT memDesc = { 0, NULL }; 165 RECT rc = { 0, 0, m_width, m_height }; 166 167 r = pSurface->LockRect(&memDesc, &rc, 0); 168 if (FAILED(r)) 169 { 170 return -1; 171 } 172 173 cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch); 174 175 if (!m_disableProcessing) 176 { 177 // blur D3D9 surface with OpenCV on CPU 178 cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); 179 } 180 181 r = pSurface->UnlockRect(); 182 if (FAILED(r)) 183 { 184 return -1; 185 } 186 187 break; 188 } 189 190 case MODE_GPU: 191 { 192 // process video frame on GPU 193 cv::UMat u; 194 195 cv::directx::convertFromDirect3DSurface9(pSurface, u); 196 197 if (!m_disableProcessing) 198 { 199 // blur D3D9 surface with OpenCV on GPU with OpenCL 200 cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); 201 } 202 203 cv::directx::convertToDirect3DSurface9(u, pSurface); 204 205 break; 206 } 207 208 } // switch 209 210 print_info(pSurface, m_mode, getFps(), m_oclDevName); 211 212 // traditional DX render pipeline: 213 // BitBlt surface to backBuffer and flip backBuffer to frontBuffer 214 r = m_pD3D9DevEx->StretchRect(pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE); 215 if (FAILED(r)) 216 { 217 return -1; 218 } 219 220 // present the back buffer contents to the display 221 r = m_pD3D9DevEx->Present(NULL, NULL, NULL, NULL); 222 if (FAILED(r)) 223 { 224 return -1; 225 } 226 227 } // try 228 229 catch (cv::Exception& e) 230 { 231 std::cerr << "Exception: " << e.what() << std::endl; 232 return 10; 233 } 234 235 return 0; 236 } // render() 237 238 239 void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName) 240 { 241 HDC hDC; 242 243 HRESULT r = pSurface->GetDC(&hDC); 244 if (FAILED(r)) 245 { 246 return; 247 } 248 249 HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT); 250 251 HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont); 252 253 if (hOldFont) 254 { 255 TEXTMETRIC tm; 256 ::GetTextMetrics(hDC, &tm); 257 258 char buf[256]; 259 int y = 0; 260 261 buf[0] = 0; 262 sprintf(buf, "Mode: %s", m_modeStr[mode].c_str()); 263 ::TextOut(hDC, 0, y, buf, (int)strlen(buf)); 264 265 y += tm.tmHeight; 266 buf[0] = 0; 267 sprintf(buf, "FPS: %2.1f", fps); 268 ::TextOut(hDC, 0, y, buf, (int)strlen(buf)); 269 270 y += tm.tmHeight; 271 buf[0] = 0; 272 sprintf(buf, "OpenCL device: %s", oclDevName.c_str()); 273 ::TextOut(hDC, 0, y, buf, (int)strlen(buf)); 274 275 ::SelectObject(hDC, hOldFont); 276 } 277 278 r = pSurface->ReleaseDC(hDC); 279 280 return; 281 } // print_info() 282 283 284 int cleanup(void) 285 { 286 SAFE_RELEASE(m_pSurface); 287 SAFE_RELEASE(m_pBackBuffer); 288 SAFE_RELEASE(m_pD3D9DevEx); 289 SAFE_RELEASE(m_pD3D9Ex); 290 D3DSample::cleanup(); 291 return 0; 292 } // cleanup() 293 294 private: 295 LPDIRECT3D9EX m_pD3D9Ex; 296 LPDIRECT3DDEVICE9EX m_pD3D9DevEx; 297 LPDIRECT3DSURFACE9 m_pBackBuffer; 298 LPDIRECT3DSURFACE9 m_pSurface; 299 cv::ocl::Context m_oclCtx; 300 cv::String m_oclPlatformName; 301 cv::String m_oclDevName; 302 }; 303 304 305 // main func 306 int main(int argc, char** argv) 307 { 308 std::string title = "D3D9Ex interop sample"; 309 return d3d_app<D3D9ExWinApp>(argc, argv, title); 310 } 311