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.
Donc comme paramètre je récupère une structure VIDEOHDR (Aperçu ci-dessous).Code:LRESULT CALLBACK capVideoStreamCallback(HWND hWnd, LPVIDEOHDR lpVHdr)
Je récupère donc le pointer lpData qui contient les données de la frame.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;
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).
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.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); }
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 !
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.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; }
Merci d'avance pour vos réponses !
Cordialement,
firepolo