Précédent   Forum du club des développeurs et IT Pro > C et C++ > C++
C++ Forum d'entraide technique sur le langage C++. Avant de poster -> F.A.Q C++
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 01/01/2013, 21h06   #1
firepolo
Futur Membre du Club
 
Anthony Pasche
Inscription : juin 2010
Messages : 30
Détails du profil
Informations personnelles :
Nom : Anthony Pasche

Informations forums :
Inscription : juin 2010
Messages : 30
Points : 16
Points : 16
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 :
LRESULT CALLBACK capVideoStreamCallback(HWND hWnd, LPVIDEOHDR lpVHdr)
Donc comme paramètre je récupère une structure VIDEOHDR (Aperçu ci-dessous).
Code :
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 :
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 :
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
firepolo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/01/2013, 13h57   #2
gbdivers
Responsable C++

 
Homme Guillaume Belz
Biochimiste
Inscription : novembre 2008
Messages : 5 321
Détails du profil
Informations personnelles :
Nom : Homme Guillaume Belz
Âge : 37
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Biochimiste
Secteur : Santé

Informations forums :
Inscription : novembre 2008
Messages : 5 321
Points : 19 529
Points : 19 529
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
__________________
Vous souhaitez rejoindre l'équipe de bénévoles qui fait vivre Developpez (traduction, rédaction, modération) ? Contactez moi par MP.

Ma page personnelle avec la liste de mes articles - Mon blog sur le C++, Qt et les GPU.

Je suis régulièrement sur le chat pour les questions C++/Qt.

Apprendre Qt 5 : vidéos d'installation (YouTube), extraites du livre Créer des applications avec Qt 5.
gbdivers est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/01/2013, 14h22   #3
dragonjoker59
Membre Expert
 
Homme Sylvain DOREMUS
Développeur informatique
Inscription : juin 2005
Messages : 636
Détails du profil
Informations personnelles :
Nom : Homme Sylvain DOREMUS
Âge : 31
Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur informatique
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : juin 2005
Messages : 636
Points : 1 537
Points : 1 537
Envoyer un message via MSN à dragonjoker59
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...

Chef de projet (et unique exécutant pour l'instant) pour Castor 3D
dragonjoker59 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 16h05.


 
 
 
 
Partenaires

Hébergement Web