[winAPI] Bitmap aus dem Clipboard (Webcam)

uhu01

Erfahrenes Mitglied
Hy!

Ich programmiere gerade ein bisschen mit einer Webcam, und stoße schon auf mein erstes Problem:
Das Bild einzulesen funktioniert perfekt, ich kopiere es dann in's Clipboard (per capEditCopy()), von dort kann ich es auch z.B. ins Paint einfügen.
Jetzt beginnt das Problem, wenn ich nun versuche das Bitmap in meinem Programm anzuzeigen ( zwei for-Schleifen ineinander, und dann SetPixel()). Lt. MSDN sollte doch genau hinter der BITMAPINFO Struktur das Bitmap in Arrayform liegen. ( ich lesen mit GetClipboardData( CF_DIB) ein) Dann speichere ich die wichtigen Informationen (Größe...), und die Adresse der BITMAPINFO+sizeof( BITMAPINFO) in einer globalen Struktur. Danach ein InvalidateRect() und das Bild neu zeichnen.
Dies geschieht eben, indem ich "Zeilen" und "Spalten" in zwei ineinandergeschachtelten for-Schleifen durchgehe, und dann die Adresse meines Pixels mit
Code:
pAktPix = pBitmap.datas + Spalte * 3 + Zeile * pBitmap.dwWidth * 3
berechen, und diesen dann per SetPixel() in mein Fenster mal.

Meine Probleme sind nun:
1. SetPixel ist viel zu langsam dafür, gibt es eine andere Möglichkeit?
2. Das Bild ist vertikal gespiegelt ( kein Problem die Zeilen anders zu lesen, aber warum ist es gespiegelt?)
3. Es gibt Fehler in der linken unteren Ecke des Bildes, bzw. wenn ich ein kleines Bild nehme z.B. 5*5 Pixel sieht man nur noch irgendetwas.

Ich muss noch dazusagen, das ich momentan mein Bild aus Pain herauskopiere, weil meine Kamera noch nicht gekommen ist, und mein Schulkollegen, mit dessen Kamera ich sonst arbeite seine selbst benötigt.

Wäre toll wenn mir jemand helfen könnte

mfg
uhu01
 
Also, zum einen sind die Zeilen von Bitmap-Daten auf 2 Byte (16 bit) gepaddet. Das kommt weiter unten zum Tragen.
Wenn du den Bitmapheader überprüfst, müsste die Höhe positiv sein. Das heisst bei Windows tatsächlich, dass die Bitmap vertikal gespiegelt ist. Wenn die Höhe negativ ist, ist es richtig rum. War wahrscheinlich vor 50 Jahren mal aus irgend einem Grund sinnvoll und ist aus Kompatibilitätsgründen beibehalten worden.

Zur Geschwindigkeit:
Wie du gemerkt hast, ist SetPixel absolut ungeeignet für sowas. Bastel dir am besten ein HBITMAP über CreateDIBSection. Dort kannst du a) genau deine Lieblingsfarbtiefe angeben (tunlichs die gleiche, wie von der Kamera kommt, dann kannst du direkt reinkopieren) und b) hast dann einen Pointer auf die Bitmapdaten.
Es ist dann ein Leichtes, per memcpy die einzelnen Zeilen (wegen dem Padding, sonst könntest du alles auf einen Rutsch kopieren!) rüberzuschieben. Für die DibSection gilt dann das übliche Darstellen: In DC selektieren, BitBlt und fertig.
 
Hy!

Soweit mal alles klar, hab gerade versucht das Bitmap 1:1 ins Fenster zu bekommen, um mir die memcpy's mal zu sparen ( schrittweise an die Lösung herantasten).
Mit CreateDIBSection habe ich mir ein HBITMAP gemacht, dann mit CreateCompatibleDC einen neuen DC, und dann mit BitBlt den alten und den neuen DC blitten.
Wie jedoch bekomme ich nach dem erstellen des neuen DC das Bitmap in den DC, und welchen Parameter muss ich bei BitBlt als dwRop verwenden, liege ich richtig mit SRCCPY.
Das Selektieren mach ich momentan mit SelectObject( hDCBack, hBitmap);

Habe bis jetzt noch nicht mit BitBlt gearbeitet.

mfg
uhu01
 
moin


Ansttat das so umständlich mit dem Pixeln zu machen könntest doch einfach ein kompatibles Bitmap erstelle (als Quelle das Clipboard) dann kannst dir das ganze Zeug mit dem Bitmapinfo sparen.

Wenn du interesse hast poste ich mal ein Beispiel.


mfg
umbrasaxum
 
Hy!

Hört sich interessant an, bitte um das Beispiel.
Trotzdem nochmal die Frage wie ich das HBITMAP in meinen DC zum blitten bekomme.

EDIT:
Momentan sieht das ganze so aus
Code:
void *vpBitmap = pBitmapInfo + pBitmapInfo->bmiHeader.biSize;
HBITMAP hBitmap = CreateDIBSection( hDC, pBitmapInfo, DIB_RGB_COLORS,
                                    &vpBitmap,	NULL, NULL);
BITMAP bmBitmap;
GetObject( hBitmap, sizeof( BITMAP), &bmBitmap);
HDC hDCBack = CreateCompatibleDC( hDC);
SelectObject( hDCBack, hBitmap);
BitBlt( hDC, 10, 10, pBitmapInfo->bmiHeader.biWidth,
          pBitmapInfo->bmiHeader.biHeight,
          hDCBack, 0, 0, SRCCOPY);
DeleteDC( hDCBack);
DeleteObject( hBitmap);
pBitmapInfo ist ein Pointer auf die BitmapInfo Struktur aus dem Clipboard, hDC mein DC

mfg
uhu01
 
Zuletzt bearbeitet:
moin


Code:
	case WM_PAINT:
		{
			HDC hDC;
			PAINTSTRUCT ps;

			HDC hDesktopDC = GetDC(hDesktop);

			HDC hMemDC = CreateCompatibleDC(hDesktopDC);
			HBITMAP hBM = CreateCompatibleBitmap(hDesktopDC, rectTotal.right, rectTotal.bottom);
			SelectObject(hMemDC, hBM);

			hDC = BeginPaint(hWnd, &ps);
			{
				BitBlt(hMemDC, 0, 0, rectTotal.right, rectTotal.bottom,
					hDesktopDC, koord.x - rectTotal.right / 2,
					koord.y - rectTotal.bottom / 2, SRCCOPY);

				BitBlt(hDC, 0, 0, rectTotal.right, rectTotal.bottom,
					hMemDC, 0, 0, SRCINVERT);
			}
			EndPaint(hWnd, &ps);
			ReleaseDC(hDesktop, hDesktopDC);
			DeleteDC(hMemDC);
			DeleteObject(hBM);

			return 0;
		}


mfg
umbrasaxum
 
Hy!

Wenn ich das richtig verstanden habe, macht mir CreateCompatibleBitmap einen "Screenshot" vom angegebenen DC, wie krieg ich mein Bild in den DC rein?
Oder hab ich da was falsch verstanden?

mfg
uhu01
 
moin


Ich weiss leider nciht genau was ich da gemacht habe, aber es hat funktioniert.
Ich hatte das Problem das mein Bild immer geflackert hat, mit dem oben stehenden Code war das kein Problem mehr.

Also hDC ist das Ziel DC, also das Ausgabefenster.
Bei GetDC(hDesktop) habe ich mir weiter oben ein HWND des Desktops geholt und hole mir dann den DC, also müsstest du den DesktopDC durch einen DC von Clipboard ersetzen.


mfg
umbrasaxum
 
Hy!

Blöde Frage: Wie komme ich an den DC des Clipboards?
Will nicht damit nerven, aber warum funktioniert mein Code oben nicht?

mfg
uhu01
 
moin


Ja wie kriegt man den DC? Keine Ahnung!
Ich guck mal eben ob ich was finde.

In der zwischenzeit könntest du mir sagen wie man einer ProgresBar nen Wert zuweisst.


mfg
umbrasaxum
 
Zurück