IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Traitement sur capture de webcam (sans DirectShow et openCV)


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2010
    Messages
    38
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2010
    Messages : 38
    Points : 50
    Points
    50
    Par défaut Traitement sur capture de webcam (sans DirectShow et openCV)
    Bonjour,

    Aujourd'hui j'ai voulu réaliser une application C++ visant à modifier en temps réel le flux vidéo de ma webcam.

    Pour ça j'utilise une méthode callback visant à récupérer le buffer de la frame précédente avant que celle-ci ne remplace la frame courante (si j'ai bien lu la doc).

    Voici l'aperçu de cette fonction.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    LRESULT CALLBACK capVideoStreamCallback(HWND hWnd, LPVIDEOHDR lpVHdr)
    Donc comme paramètre je récupère une structure VIDEOHDR (Aperçu ci-dessous).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    typedef struct videohdr_tag {
      LPBYTE    lpData;
      DWORD     dwBufferLength;
      DWORD     dwBytesUsed;
      DWORD     dwTimeCaptured;
      DWORD_PTR dwUser;
      DWORD     dwFlags;
      DWORD_PTR dwReserved[4];
    } VIDEOHDR, *PVIDEOHDR, *LPVIDEOHDR;
    Je récupère donc le pointer lpData qui contient les données de la frame.

    Mais le problème vient du faite que ces données sont déjà compressée au format supporté par les drivers de la webcam (ici j'ai 2 format supporté: YUY2 et MJPG)

    Donc en théorie je devrais m'adapter par rapport au format ou passer sur un format RGB pour traiter les données plus les renvoyé dans le bon format.

    En faite, c'est à cette partie là que je coince. Le mieux serait que je puisse passer au format RGB peut importe le format de base. Il y avait une
    solution qui consistait entre la réception de message(PeekMessage) de créer un bitmap à partir du contexte d'affichage (code ci-dessous).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    void captureFrame()
    {
    	HDC hdcWin = GetDC(hWindow); // Contexte d'affichage de la fenêtre
    	HDC hdc = GetDC(hWebcam); // Contexte d'affichage de la webcam
    	HDC hdcMem = CreateCompatibleDC(hdc);	// Contexte de données
     
    	// Donne les infos sur le bitmap
    	BITMAPINFO bmpinfo;
    	bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    	bmpinfo.bmiHeader.biWidth = 320;
    	bmpinfo.bmiHeader.biHeight = 240;
    	bmpinfo.bmiHeader.biPlanes = 1;
    	bmpinfo.bmiHeader.biBitCount = 32;
    	bmpinfo.bmiHeader.biCompression = BI_RGB;
    	bmpinfo.bmiHeader.biSizeImage = 0;
    	bmpinfo.bmiHeader.biXPelsPerMeter = 0;
    	bmpinfo.bmiHeader.biYPelsPerMeter = 0;
    	bmpinfo.bmiHeader.biClrUsed = 0;
    	bmpinfo.bmiHeader.biClrImportant = 0;
     
    	// Création du bitmap
    	void *pBits;
    	HBITMAP hbmp = CreateDIBSection(hdc, &bmpinfo, DIB_PAL_COLORS, &pBits, NULL, 0);
     
    	// Sélection du bitmap
    	SelectObject(hdcMem, hbmp);
     
    	// Copie l'image
    	BitBlt(hdcMem, 0, 0, 320, 240, hdc, 0, 0, SRCCOPY);
     
    	// Initialisation du tableau de pixels
    	int len = 320 * 240 * 4;
    	BYTE *pixels = new BYTE[len];
     
    	// Récupère les pixels
    	GetDIBits(hdcMem, hbmp, 0, 240, pixels, &bmpinfo, DIB_RGB_COLORS);
     
    	// Traitement sur les pixels
    	for (int i = 0; i < len; i++)
    		pixels[i] = 255 - pixels[i];
     
    	// Afficher l'image
    	SetDIBitsToDevice(hdcWin, 320, 0, 320, 240, 0, 0, 0, 240, pixels, &bmpinfo, DIB_RGB_COLORS);
     
    	// Vidage mémoire
    	delete[] pixels;
    	DeleteDC(hdcMem);
    	DeleteDC(hdc);
    }
    Je sais pas si il est fonctionnel mais c'était pour vous faire une idée. Cette méthode fonctionne mais après le problème est que je n'arrive pas à afficher seulement le rendu final de la capture. Je suis obliger de la laisser la preview de la webcam donc je me retrouve constamment avec rendu.

    Y a-t-il un moyen d'avoir que le rendu final après le traitement de l'image (en modifiant directement le buffer ?) ou d'utiliser la technique décrite ci-dessus mais en affichant que le rendu final ?

    Voici le code de mon application !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
     
    #include <Windows.h>
    #include <Vfw.h>
     
    const int widthCapture = 640;
    const int heightCapture = 480;
     
    HWND hWebcam;
     
    LRESULT CALLBACK capVideoStreamCallback(HWND hWnd, LPVIDEOHDR lpVHdr)
    {
    	// C'est ici que je récupère le buffer de la frame avant que celle-ci ne s'affiche
    	return 0;
    }
     
    LRESULT CALLBACK winProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    	switch(uMsg)
    	{
    		case WM_CREATE:
    		{
    			hWebcam = capCreateCaptureWindow("Webcam capture", WS_CHILD | WS_VISIBLE, 0, 0, widthCapture, heightCapture, hwnd, 0);
     
    			if (SendMessage(hWebcam, WM_CAP_DRIVER_CONNECT, 0, 0))
    			{
    				//SendMessage(hWebcam, WM_CAP_DLG_VIDEOFORMAT, 0, 0);
    				SendMessage(hWebcam, WM_CAP_SET_CALLBACK_FRAME, 0, (LPARAM)&capVideoStreamCallback);
    				SendMessage(hWebcam, WM_CAP_SET_PREVIEWRATE, 33, 0);
    				SendMessage(hWebcam, WM_CAP_SET_PREVIEW, true, 0);
    			}
    			else SendMessage(hwnd, WM_DESTROY, 0, 0);
    			break;
    		}
     
    		case WM_DESTROY:
    		{
    			SendMessage(hWebcam, WM_CAP_SET_PREVIEW, false, 0);
    			SendMessage(hWebcam, WM_CAP_SET_CALLBACK_FRAME, 0, NULL);
    			SendMessage(hWebcam, WM_CAP_DRIVER_DISCONNECT, 0, 0);
     
    			PostQuitMessage(0);
    			break;
    		}
     
    		default:
    			return DefWindowProc(hwnd, uMsg, wParam, lParam);
    	}
     
    	return 0;
    }
     
    int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
    	WNDCLASS wc;
    	memset(&wc, 0, sizeof(WNDCLASS));
     
    	wc.style = CS_HREDRAW | CS_VREDRAW;
    	wc.lpfnWndProc = winProc;
    	wc.hInstance = hInstance;
    	wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    	wc.lpszClassName = "classOfWindow";
     
    	RegisterClass(&wc);
     
    	HWND hWindow = CreateWindow(wc.lpszClassName, "Rectangle reconizer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, widthCapture + 20, heightCapture + 40, NULL, NULL, NULL, NULL);
     
    	ShowWindow(hWindow, SW_SHOW);
    	UpdateWindow(hWindow);
     
    	MSG msg;
     
    	while (GetMessage(&msg, NULL, 0, 0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
     
    	DestroyWindow(hWindow);
     
    	return msg.wParam;
    }
    Je ne sais pas jusqu'où je peux aller pour avoir quelque chose qui puissent être rapide et qui ne surcharge pas trop la machine.

    Merci d'avance pour vos réponses !

    Cordialement,

    firepolo

  2. #2
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Bonjour

    Ta question est très spécifique, pas sur que arrive à trouver de l'aide ici. Demande peut être dans le forum programmation système.
    Pourquoi pas OpenCV ? Fais peut être une première version avec OpenCV, puis modifie quand ça fonctionne par du code perso. Tu peux également t'inspirer du code source d'OpenCV

    Bon courage

  3. #3
    Expert éminent sénior

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 045
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 045
    Points : 11 368
    Points
    11 368
    Billets dans le blog
    10
    Par défaut
    Si je me souviens bien (et si j'ai bien compris que tu utilises VideoForWindows), tu peux créer une fenêtre de capture que tu n'affiches pas (grâce à la fonction capCreateCaptureWindow).

    Ensuite, que tu utilises ou pas le mode preview (je ne l'utilise pas, je mets un timer pour charger les frames) tu peux traiter la frame (donc soit récupérée via la callback soit par capGrabFrame) et n'afficher que celle que tu traites toi-même.

    Par contre la compression, il faut que ce soit toi qui la gères. En YUY2 il y a pas mal de sources qui traînent traitant de la conversion vers RGB, mais le MJPG est plus tordu, je suis passé par LibJPEG qui donne d'excellents résultats.
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

Discussions similaires

  1. Traitement sur un selectedIndex inexistant ?
    Par 10-nice dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 22/08/2005, 11h33
  2. [C#] [.NET 1.1] [VSTUDIO 2003] Traitement sur les fontes
    Par stailer dans le forum Windows Forms
    Réponses: 4
    Dernier message: 04/08/2005, 20h53
  3. [VB.NET] Traitement sur chaine (simple)
    Par Tempotpo dans le forum Windows Forms
    Réponses: 4
    Dernier message: 24/03/2005, 14h20
  4. [FLASH MX 2004] Traitements sur le resultat d'un AS.
    Par Med_Prog dans le forum Flash
    Réponses: 8
    Dernier message: 21/11/2004, 14h59
  5. lire/écrire sur un port com sans le monopoliser
    Par totofweb dans le forum Windows
    Réponses: 4
    Dernier message: 26/07/2004, 14h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo