Ask Your Question
-1

Display webcam input in window

asked 2015-11-02 02:02:55 -0600

Aj-611 gravatar image

updated 2015-11-03 06:16:06 -0600

pklab gravatar image

I'd done build a window to display input image using multithreading. But now I'm stuck, how can I display image in this window (as in figure attached here) since I'm using OpenCV.

image description

EDIT 3/11/15

LRESULT CALLBACK SmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam);

int OnGrab(void);
DWORD StopThread(LPDWORD lpdwParam);
DWORD ImaqThread(LPDWORD lpdwParam);
static HANDLE HStopThread, HStopEvent, HThread;
static HINSTANCE hInst;
static HWND SmplHwnd;
static HWND HStop, HGrab, HQuit;
static BOOL StopGrab; 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
    CHAR        SmplClassName[] = "Sample";
    WNDCLASS            SmplClass;
    MSG         msg;

    hInst = hInstance;
    if (!hPrevInstance)
    {
        SmplClass.style             = CS_HREDRAW | CS_VREDRAW;
        SmplClass.lpfnWndProc       = (WNDPROC)SmplProc;
        SmplClass.cbClsExtra        = 0;
        SmplClass.cbWndExtra        = 0;
        SmplClass.hInstance         = hInstance;
        SmplClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        SmplClass.hCursor           = LoadCursor(NULL, IDC_ARROW);
        SmplClass.hbrBackground     = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
        SmplClass.lpszMenuName      = 0;
        SmplClass.lpszClassName     =SmplClassName;
        if (!RegisterClass(&ImaqSmplClass))
            return (0);
    }
    SmplHwnd = CreateWindow(SmplClassName, "LLGrab", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 1180, 740, NULL, NULL, hInstance, NULL);

    if (!(HGrab = CreateWindow("Button", "Grab", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER, 1050, 72, 80, 40, SmplHwnd, (HMENU)PB_GRAB, hInstance, NULL))) 
        return (FALSE);
    if (!(HStop = CreateWindow("Button", "Stop", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER, 1050, 112, 80, 40, SmplHwnd, (HMENU)PB_STOP, hInstance, NULL))) 
        return (FALSE);

    EnableWindow(HStop, FALSE);

    if (!(HQuit = CreateWindow("Button", "Quit", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER, 1050, 152, 80, 40, SmplHwnd, (HMENU)PB_QUIT, hInstance, NULL)))
        return (FALSE);

    ShowWindow(SmplHwnd, SW_SHOW);
    UpdateWindow(SmplHwnd);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    WaitForSingleObject(HStopThread, INFINITE);
    return (int)(msg.wParam);
}

LRESULT CALLBACK SmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam)
{
    WORD wmID;


    switch (iMessage)
    {
        case WM_COMMAND:
            wmID = LOWORD(wParam);
            switch (wmID)
            {
            case PB_QUIT:
                PostQuitMessage(0);
                break;

            case PB_GRAB:

                OnGrab();
                break;

            case PB_STOP:

                SetEvent(HStopEvent);
                break;

            }
            break;
        case WM_DESTROY:

            SetEvent(HStopEvent);
            PostQuitMessage(0);

        default:

            return DefWindowProc(hWnd, iMessage, wParam, lParam);
            break;

    }
    return 0;
}

int OnGrab(void)
{
    DWORD dwThreadId;

    HStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!HStopEvent)
        return 0;
    HStopThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StopThread, (LPWORD)&HStopEvent, 0, &dwThreadId);
    if (!HStopThread)
        return 0;
    StopGrab = FALSE;
    HThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread, (LPDWORD*)&StopGrab, 0, &dwThreadId);
    if (HThread == NULL)
        return 0;
    EnableWindow(HStop, TRUE);
    EnableWindow(HGrab, FALSE);
    EnableWindow(HQuit, FALSE);
    return 0;
}

DWORD Thread(LPDWORD lpdwParam)
{
    BOOL* volatile stop = (BOOL*)lpdwParam;
    VideoCapture captures;
    captures.open("2pm.avi");

    while (!*stop)
    {
        //display video here
    }
    return 0;
}

DWORD StopThread(LPDWORD lpdwParam)
{
    DWORD dwResult;

    HANDLE event = *((HANDLE*)lpdwParam);

    dwResult = WaitForSingleObject(event, INFINITE);
    if (dwResult != WAIT_FAILED)
    {
        CloseHandle(event);
        event = NULL;
    }
    EnableWindow(HStop, FALSE);
    EnableWindow(HGrab, TRUE);
    EnableWindow(HQuit, TRUE);
    return 0;
}
edit retag flag offensive close merge delete

Comments

What GUI you are using ? please show the code. In general, imshow shows a cv::Mat into a cv own window. If you want to show a cv::Mat into your application window you have to map a cv::namedwindow into your window or copy the Mat into window device context. See here and here for some example

pklab gravatar imagepklab ( 2015-11-02 05:24:13 -0600 )edit

@pklab@berak I'd included the code.

Aj-611 gravatar imageAj-611 ( 2015-11-02 20:46:03 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
4

answered 2015-11-03 06:10:34 -0600

pklab gravatar image

updated 2015-11-11 05:18:06 -0600

With Win32 GUI (and MFC) you can use one of below:

  1. to draw the cv::Mat into dc memory context of a static control: see here
  2. or to map a cv::window as child of some static control: see cvWin2MfcControl below for a complete example

In both cases you have to define a static control that will holds the image from opencv.

Some note about thread control:

  • May be your code is incomplete but the grabbing thread will be never stopped because stop (pointer to StopGrab) variable is never set to true.

  • Doing StopGrab=true in StopThread you will have a race condition because 2 threads can access to StopGrab. In general, to stop a thread you should use an event or a control var under a mutex or a critical section to protect the var from a shared access. In this case you can use atomic<bool> that is lock free and faster than mutex or critical section.

For you and other user, here is correct code using 2nd method and atomic<bool>.

EDIT: because atomic<bool> is C++11 and isn't available in VS2008, a very simple class that defines a protected shared variable has been provided

#include <opencv2/opencv.hpp>
#if __cplusplus >= 199711L //is C++11 available ?
    // Use std::atomic<bool> because is lock free
    #include <atomic>
    std::atomic<bool>StopGrab; //needed to protect the grab loop on/off flag
#else 
    // With old C++ compiler we create a very simple class to define
    // a protected shared variable using CriticalSection
    template<class T>  class AtomicSimple
    {
    public:
        AtomicSimple(){
            InitializeCriticalSection(&CriticalSection);
        };
        AtomicSimple(T newVal) {
            InitializeCriticalSection(&CriticalSection); 
            store(newVal);
        }
        ~AtomicSimple(){
            DeleteCriticalSection(&CriticalSection);
        };
        T load()
        {
            T curVal;
            EnterCriticalSection(&CriticalSection);
            curVal = val;
            LeaveCriticalSection(&CriticalSection);
            return curVal;
        }
        void store(T newVal)
        {
            EnterCriticalSection(&CriticalSection);
            val = newVal;
            LeaveCriticalSection(&CriticalSection);
            }
    private:
        T val;
        CRITICAL_SECTION CriticalSection;
    };
    AtomicSimple<bool>StopGrab; //needed to protect the grab loop on/off flag
#endif
HANDLE HStopThread, HStopEvent, HThread;
HINSTANCE hInst;
HWND SmplHwnd, GrabHwnd;
HWND HStop, HGrab, HQuit;
const char * WIN_NAME_CV = "OCV Image Display";

LRESULT CALLBACK SmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam);
int OnGrabClick(void);  

/** ------------------------------------------------------------------------------------------
    \brief Map an OpenCV window over a MFC/Win32 control
    \param parentWnd the handle of MFC/Win32 static control
*/
bool cvWin2MfcControl(HWND parentWnd)
{
    cv::namedWindow(WIN_NAME_CV, CV_WINDOW_KEEPRATIO);  // create an OpenCV win
    HWND cvWnd = (HWND)cvGetWindowHandle(WIN_NAME_CV);  // get the handle of OpenCV Window
    if (!cvWnd) return false;

    HWND hOldParent = ::GetParent(cvWnd);
    ::SetParent(cvWnd, parentWnd);     // move the OpenCV window to the new parent (your static control)
    ::ShowWindow(hOldParent, SW_HIDE); // hide the old parent window

    // Resize the OpenCV window to fit your static control
    RECT parentRect;
    ::GetClientRect(parentWnd, &parentRect);
    cvResizeWindow(WIN_NAME_CV, parentRect.right, parentRect.bottom);
    return true;
}
//------------------------------------------------------------------------------------------
DWORD GrabThread(LPDWORD lpdwParam)
{
    cv::VideoCapture captures;
    captures.open(0);
    if (!captures.isOpened())
            return -1;
    cv::Mat frame;
    EnableWindow(HStop, TRUE);
    EnableWindow(HGrab, FALSE);
    EnableWindow(HQuit, FALSE);
    while (!StopGrab.load())
    {
        captures >> frame;
        cv::imshow(WIN_NAME_CV, frame); //display video here
        //cvWaitKey(1); not needed 
    }
    EnableWindow(HStop, FALSE);
    EnableWindow(HGrab, TRUE);
    EnableWindow(HQuit, TRUE);
    return 0;
}
//------------------------------------------------------------------------------------------
DWORD StopThread(LPDWORD lpdwParam)
{
    DWORD dwResult;
    HANDLE ...
(more)
edit flag offensive delete link more

Comments

Thanks @pklab . But when I click 'Grab' button, the program exited. I wonder if this thing just happen to my machine or what.

Aj-611 gravatar imageAj-611 ( 2015-11-09 08:03:09 -0600 )edit

My code works fine on my machine... did you try a break point in OnGrabClick ? what's happens ? some error code ?

pklab gravatar imagepklab ( 2015-11-09 09:42:25 -0600 )edit

@pklab. Ya I'd tried. And there is no error.

But there are some outputs like this:

'ConsoleApplication2.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ntdll.dll'. Cannot find or open the PDB file.

And end up with this output when I click 'Grab':

The thread 0x1f24 has exited with code 0 (0x0).
The thread 0x20c0 has exited with code 0 (0x0).
The thread 0xf7c has exited with code 0 (0x0).
The program '[10004] ConsoleApplication2.exe' has exited with code 0 (0x0).
Aj-611 gravatar imageAj-611 ( 2015-11-10 00:37:47 -0600 )edit

PDB files are for debugging object files ... in this case ntdll.dll...sure you don't want to debug it. As I said my code works fine... if you make some changes debug your code/flow... what's happens in details when you click 'Grab' button ? for example is captures.isOpened()=true in GrabThread ? The StopThread function is waiting correctly for HStopEvent ?

pklab gravatar imagepklab ( 2015-11-10 03:31:44 -0600 )edit

@pklab , I'd solved the problem. There is a header file that I should include in the coding. Thank you very much. But can I ask about the <atomic> ? Actually in my pc I'm running with Visual Studio version 2008 because I'm using some library that only work with old version of Visual Studio. So this old version does not provide this new class. So is there any others solution for that?

Aj-611 gravatar imageAj-611 ( 2015-11-10 22:28:32 -0600 )edit

ok atomic is C++11 and isn't available in VS2008 look at EDIT and AtomicSimple class in my answer. If it's works please accept the ansewer.

pklab gravatar imagepklab ( 2015-11-11 05:20:34 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2015-11-02 02:02:55 -0600

Seen: 3,362 times

Last updated: Nov 11 '15