1793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler/*
2793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Sample demonstrating interoperability of OpenCV UMat with Direct X surface
3793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Base class for Direct X application
4793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler*/
5793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <string>
6793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <iostream>
7793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <queue>
8793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
9793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/core.hpp"
10793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/core/directx.hpp"
11793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/core/ocl.hpp"
12793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/imgproc.hpp"
13793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/videoio.hpp"
14793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
15793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "winapp.hpp"
16793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
17793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define SAFE_RELEASE(p) if (p) { p->Release(); p = NULL; }
18793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
19793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
20793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerclass D3DSample : public WinApp
21793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
22793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerpublic:
23793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    enum MODE
24793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
25793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        MODE_NOP,
26793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        MODE_CPU,
27793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        MODE_GPU
28793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    };
29793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
30793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    D3DSample(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
31793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        WinApp(width, height, window_name)
32793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
33793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        m_shutdown          = false;
34793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        m_mode              = MODE_NOP;
35793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        m_modeStr[0]        = cv::String("No processing");
36793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        m_modeStr[1]        = cv::String("Processing on CPU");
37793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        m_modeStr[2]        = cv::String("Processing on GPU");
38793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        m_disableProcessing = false;
39793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        m_cap               = cap;
40793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
41793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
42793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    ~D3DSample() {}
43793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
44793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    virtual int create() { return WinApp::create(); }
45793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    virtual int render() = 0;
46793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    virtual int cleanup()
47793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
48793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        m_shutdown = true;
49793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return WinApp::cleanup();
50793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
51793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
52793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    static float getFps()
53793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
54793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        static std::queue<int64> time_queue;
55793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
56793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int64 now = cv::getTickCount();
57793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int64 then = 0;
58793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        time_queue.push(now);
59793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
60793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if (time_queue.size() >= 2)
61793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            then = time_queue.front();
62793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
63793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if (time_queue.size() >= 25)
64793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            time_queue.pop();
65793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
66793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        size_t sz = time_queue.size();
67793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
68793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        float fps = sz * (float)cv::getTickFrequency() / (now - then);
69793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
70793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return fps;
71793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
72793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
73793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerprotected:
74793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
75793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
76793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        switch (message)
77793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
78793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        case WM_CHAR:
79793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if (wParam >= '0' && wParam <= '2')
80793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
81793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                m_mode = static_cast<MODE>((char)wParam - '0');
82793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                return 0;
83793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
84793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            else if (wParam == VK_SPACE)
85793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
86793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                m_disableProcessing = !m_disableProcessing;
87793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                return 0;
88793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
89793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            else if (wParam == VK_ESCAPE)
90793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
91793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                return cleanup();
92793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
93793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            break;
94793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
95793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        case WM_CLOSE:
96793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            return cleanup();
97793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
98793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        case WM_DESTROY:
99793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            ::PostQuitMessage(0);
100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            return 0;
101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
103793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return ::DefWindowProc(hWnd, message, wParam, lParam);
104793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
105793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
106793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    // do render at idle
107793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    virtual int idle() { return render(); }
108793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
109793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerprotected:
110793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool               m_shutdown;
111793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool               m_disableProcessing;
112793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    MODE               m_mode;
113793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cv::String         m_modeStr[3];
114793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cv::VideoCapture   m_cap;
115793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cv::Mat            m_frame_bgr;
116793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cv::Mat            m_frame_rgba;
117793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler};
118793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
119793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
120793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void help()
121793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
122793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    printf(
123793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        "\nSample demonstrating interoperability of DirectX and OpenCL with OpenCV.\n"
124793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        "Hot keys: \n"
125793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        "    0 - no processing\n"
126793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        "    1 - blur DX surface on CPU through OpenCV\n"
127793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        "    2 - blur DX surface on GPU through OpenCV using OpenCL\n"
128793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        "  ESC - exit\n\n");
129793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
130793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
131793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
132793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic const char* keys =
133793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
134793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    "{c camera | true  | use camera or not}"
135793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    "{f file   |       | movie file name  }"
136793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    "{h help   | false | print help info  }"
137793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler};
138793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
139793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
140793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslertemplate <typename TApp>
141793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerint d3d_app(int argc, char** argv, std::string& title)
142793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
143793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cv::CommandLineParser parser(argc, argv, keys); \
144793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool   useCamera = parser.has("camera"); \
145793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    string file      = parser.get<string>("file"); \
146793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool   showHelp  = parser.get<bool>("help"); \
147793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
148793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (showHelp)
149793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        help();
150793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
151793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    parser.printMessage();
152793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
153793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cv::VideoCapture cap;
154793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
155793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (useCamera)
156793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cap.open(0);
157793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    else
158793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cap.open(file.c_str());
159793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
160793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (!cap.isOpened())
161793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
162793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        printf("can not open camera or video file\n");
163793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return -1;
164793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
165793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
166793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int width  = (int)cap.get(CAP_PROP_FRAME_WIDTH);
167793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT);
168793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
169793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    std::string wndname = title;
170793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
171793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    TApp app(width, height, wndname, cap);
172793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
173793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    try
174793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
175793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        app.create();
176793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return app.run();
177793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
178793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
179793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    catch (cv::Exception& e)
180793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
181793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        std::cerr << "Exception: " << e.what() << std::endl;
182793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return 10;
183793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
184793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
185793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    catch (...)
186793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
187793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        std::cerr << "FATAL ERROR: Unknown exception" << std::endl;
188793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return 11;
189793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
190793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
191