400 Bad Request

Bad Request

Your browser sent a request that this server could not understand.

C++ / WinAPI - Zachytávání snímků z Web kamery

C++ / WinAPI - Zachytávání snímků z Web kamery

Příspěvekod Wlezley » 24 listopad 2011 05:55:07

Po nějaké době, jsem tu opět s užitečným nástřelem (snippetem) dalšího programu. Tentokrát se naučíme, jak zobrzit ve WinAPI okně video z webové kamery, jak zachytit snímek a uložit ho do souboru BMP. Později (v jiném článku) vysvětlím, jak lze bitmapy ukládat (převádět) do jpg, png atd. Chystám také pokračování, kde se budu zabývat záznamem videa, nastavením kamery a záznamu zvuku, komprese videa atd...

Vysvětlím to na projektu pro Visual C++ 2008 Express Edition (bohužel, jiný nástroj nemám). Tak tedy... Ve Visual C++ 2008 EE si vytvořte nový Win32 Project. V průvodci vytvořením projektu zvolte možnost "empty project" (prázdný - bez souborů). Vytvořte nový soubor CPP (v umístění souboru vašeho nově vytvořeného projektu), který se bude jmenovat například "main.cpp". Vidíte tedy nový projekt s jedním vámi vytvořeným, prázdným souborem. Do tohoto budete postupně vkládat kód, který budu postupně vysvětlovat a popisovat.
Poznámka: Nastavte si Character Set u Visual C++ projektu na Use Multi-Byte Character Set !! ( Jako unicode jsem to vážně nepsal :tongue_ss: :D )


#1: Includování, linkování, definice, prototypy funkcí a globální proměnné...
Je třeba includovat tyto soubory:
Kód: Vybrat vše
#include <windows.h>
#include <vfw.h>                  // Video for Windows
#include <string>
#include <time.h>


Následně pragmou předáme preprocessoru informaci, který řekne linkeru, že chceme přilikovat knihovnu vfw.lib (Video for Windows).
Kód: Vybrat vše
#pragma comment(lib, "vfw32.lib") // Video for Windows library


V programu jsou použity tyto definice:
Kód: Vybrat vše
#define APP_TITLE_NAME          "Wlezley's WebCam TEST"
#define APP_CLASS_NAME          "wo_webcam"
#define VIDEO_SIZE_X            640
#define VIDEO_SIZE_Y            480
#define WINDOW_SIZE_X           VIDEO_SIZE_X
#define WINDOW_SIZE_Y           VIDEO_SIZE_Y + 35
#define CAPTURE_FILE_PREFIX     "Foto_"
#define CAPTURE_FILE_EXT        ".bmp"


Další věcí jsou prototypy funkcí (vysvětlení viz. dále v textu):
Kód: Vybrat vše
LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
int GetCamDriverID(bool showResult = false);


Globální proměnné:
Kód: Vybrat vše
// Identifikátor ovladače kamery
static int CamDriverID;

// Handlery oken
HWND camhwnd;       // Okno náhledu kamery
HWND hBtnStart;     // Tlačítko START
HWND hBtnStop;      // Tlačítko STOP
HWND hBtnCapture;   // Tlačítko zachycení snímku



#2: Main (hlavní) funkce
Kód: Vybrat vše
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // Ověření přítomnosti kamery a uložení identifikátoru ovladače
    if((CamDriverID = GetCamDriverID(true)) == -1) // Pokud není nainstalovaná žádná vhodná kamera...
    {
        return 1; // ...dojde k ukončení programu
    }

    HWND hwnd; // Handler hlavního okna
    MSG msg;   // Registr zpráv

    // Registrace třídy okna
    WNDCLASS wc;
    wc.style         = CS_HREDRAW|CS_VREDRAW;
    wc.lpfnWndProc   = WindowProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOWFRAME);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = TEXT(APP_CLASS_NAME);
    RegisterClass (&wc);

    // Výpočet pozice okna pro umístění doprostřed obrazovky
    RECT rcDesktop; GetWindowRect(GetDesktopWindow(), &rcDesktop);      // Zjistí rozlišení pracovní plochy windows
    int iWindow_Pos_X = (rcDesktop.right  / 2) - ((WINDOW_SIZE_X) / 2); // Výpočet počátečního bodu X
    int iWindow_Pos_Y = (rcDesktop.bottom / 2) - ((WINDOW_SIZE_Y) / 2); // Výpočet počátečního bodu Y

    // Vytvoření hlavního okna
    hwnd = CreateWindow(TEXT(APP_CLASS_NAME), TEXT(APP_TITLE_NAME),
                        WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
                        iWindow_Pos_X, iWindow_Pos_Y,
                        WINDOW_SIZE_X, WINDOW_SIZE_Y,
                        0, 0, hInstance, 0);

    // Vytvoření tlačítek hlavního okna
    hBtnStart   = CreateWindowEx(0, TEXT("BUTTON"), TEXT("Zapnout"), WS_CHILD | WS_VISIBLE,  10,  5, 100, 25, hwnd, (HMENU)1, hInstance, 0);
    hBtnStop    = CreateWindowEx(0, TEXT("BUTTON"), TEXT("Vypnout"), WS_CHILD | WS_VISIBLE,  10,  5, 100, 25, hwnd, (HMENU)2, hInstance, 0);
    hBtnCapture = CreateWindowEx(0, TEXT("BUTTON"), TEXT("Vyfotit"), WS_CHILD | WS_VISIBLE, 120,  5, 100, 25, hwnd, (HMENU)3, hInstance, 0);
    ShowWindow(hBtnStart, SW_HIDE);

    // Vytvoření okna náhledu kamery
    camhwnd = capCreateCaptureWindow(TEXT("WebCam"), WS_CHILD | WS_VISIBLE, 0, 35, VIDEO_SIZE_X, VIDEO_SIZE_Y, hwnd, 11011);

    // Připojení WebKamery a nastavení parametrů náhledu
    capDriverConnect(camhwnd, CamDriverID);
    capPreviewScale (camhwnd, true);
    capPreviewRate  (camhwnd, 33);
    capPreview      (camhwnd, true);

    // Zobrazení a aktualizace hlavního okna
    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);

    // Smyčka zpráv
    while (GetMessage(&msg,0,0,0))
    {
        if (!IsDialogMessage(hwnd, &msg))
        {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
        }
    }
    return msg.wParam;
}



#3: Procedura hlavního okna
Kód: Vybrat vše
LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
            case 1: // START
                {
                    // Překreslení tlačítek
                    ShowWindow(hBtnStart,   SW_HIDE);
                    ShowWindow(hBtnStop,    SW_SHOW);
                    ShowWindow(hBtnCapture, SW_SHOW);
                    UpdateWindow(hwnd);

                    // Připojení WebKamery a nastavení parametrů náhledu
                    capDriverConnect(camhwnd, CamDriverID);
                    capPreviewScale (camhwnd, true);
                    capPreviewRate  (camhwnd, 33);
                    capPreview      (camhwnd, true);
                    UpdateWindow(camhwnd);
                    break;
                }

            case 2: // STOP
                {
                    // Překreslení tlačítek
                    ShowWindow(hBtnStop,    SW_HIDE);
                    ShowWindow(hBtnStart,   SW_SHOW);
                    ShowWindow(hBtnCapture, SW_HIDE);
                    UpdateWindow(hwnd);

                    // Odpojení WebKamery
                    capDriverDisconnect(camhwnd);
                    UpdateWindow(camhwnd);
                    break;
                }

            case 3: // CAPTURE
                {
                    // Vytvoření jména souboru (vložení UNIX time do názvu souboru)
                    char szTime[12];
                    _itoa_s((int)time(NULL), szTime, sizeof(szTime), 10);
                    std::string sFilePath = CAPTURE_FILE_PREFIX;
                    sFilePath += szTime;
                    sFilePath += CAPTURE_FILE_EXT;

                    // Zachycení a uložení snímku do souboru
                    if(!capFileSaveDIB(camhwnd, TEXT(sFilePath.c_str())))
                    {
                        // Chybové hlášení
                        MessageBox(hwnd, TEXT("Nelze vytvořit výstupní soubor."), TEXT(APP_TITLE_NAME), MB_OK | MB_ICONERROR);
                    }
                    break;
                }
            }
            break;
        }

    // Ukončení programu || Zničení okna
    case WM_CLOSE:
    case WM_DESTROY:
        {
            capDriverDisconnect(camhwnd); // Odpojení WebKamery
            PostQuitMessage(0);           // Odeslání ukončovací zprávy hlavní funkci
            break;
        }

    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}



#4: Funkce zjišťující ID první kamery
Kód: Vybrat vše
int GetCamDriverID(bool showResult)
{
    char szDeviceName[80];
    char szDeviceVersion[80];
    int iDriver = -1;

    for(int iDriverIndex = 0; iDriverIndex < 31; iDriverIndex++)
    {
        if(capGetDriverDescription((UINT)iDriverIndex, szDeviceName, sizeof(szDeviceName), szDeviceVersion, sizeof(szDeviceVersion)))
        {
            iDriver = iDriverIndex;
            break;
        }
    }

    if(showResult && iDriver != -1)
    {
        char szCamDriverID[12];
        _itoa_s(CamDriverID, szCamDriverID, sizeof(szCamDriverID), 10);
        std::string strMsg = "Byla nalezena tato webová kamera:\n";
        strMsg += "\nID: \t\t";
        strMsg += szCamDriverID;
        strMsg += "\nDriver Name: \t";
        strMsg += szDeviceName;
        strMsg += "\nDriver Version: \t";
        strMsg += szDeviceVersion;
        MessageBox(NULL, TEXT(strMsg.c_str()), TEXT(APP_TITLE_NAME), MB_OK | MB_ICONINFORMATION);
    }

    if(iDriver == -1)
    {
        MessageBox(NULL, TEXT("Nepodařilo se najít žádnou použitelnou WebKameru."), TEXT(APP_TITLE_NAME), MB_OK | MB_ICONERROR);
    }

    return iDriver;
}


Toť vše. Program máte k vyzkoušení a stažení zde:
DOWNLOAD: http://czshare.com/2286834/WEBCAM_WIN32 ... 185%29.zip (verze 0.0.0185)

Kompletní kód programu:
Normal: http://paste.wlezley.eu/index.php/view/654655
RAW: http://paste.wlezley.eu/index.php/view/raw/654655

Omlouvám se, že jsem to moc nerozepsal. Dostanu se k tomu až později. Zatím vám musí stačit poznámky ve zdrojovém kódu. Dejte mi čas, zatím můžete zkoušet co to umí. :) :shifty:
Uživatelský avatar
Wlezley
 
Příspěvky: 316
Registrován: 24 září 2011 22:54:46
Bydliště: Plzeň
Projekt: Wlezley EU

Re: C++ / WinAPI - Zachytávání snímků z Web kamery

Příspěvekod Wlezley » 25 listopad 2011 23:41:40

Ve vlastním programu mám už i nějaký nový funkce. Hlavně zachycování AVI (volitelně s kompresí), cyklycké ukládání snímků (fotografování) v intervalech (nyní na pevno 10 sec.),
umí to formát BMP, JPEG, PNG, GIF, TIFF ... , novinkou je taky nastavení kamery, formátu AVI a kodeku. :D

Už je to složitější, na převody obrázků používám knihovnu GDI+.
Pro funkce nahrávání videa mi jako zdroj informací sloužilo MSDN - Video Capture.

Zdroják si zatím nechám pro sebe, ještě chytám mouchy. B)

Obrázek
Uživatelský avatar
Wlezley
 
Příspěvky: 316
Registrován: 24 září 2011 22:54:46
Bydliště: Plzeň
Projekt: Wlezley EU

Re: C++ / WinAPI - Zachytávání snímků z Web kamery

Příspěvekod Wlezley » 29 listopad 2011 08:09:54

Aktualizace kódu, viz. první příspěvek. Zjednodušil jsem to a zpřehlednil.
Vyhodil jsem ty funkce na vytváření bludných BMP (starej multi-format, zkrátka děs-běs...) přes schránku (clipboard).
Uživatelský avatar
Wlezley
 
Příspěvky: 316
Registrován: 24 září 2011 22:54:46
Bydliště: Plzeň
Projekt: Wlezley EU


Zpět na C/C++

Kdo je online

Uživatelé procházející toto fórum: Žádní registrovaní uživatelé a 3 návštevníků


cron