Rotation und Transparenz für größere Texturen
-
Hallo,
ich verzweifel gerade etwas an der GDI/GDI+ und hoffe ihr habt eine Lösung für mich.Folgende Aufgabe muss ich lösen:
1. Ich bekomme von einer (Foto-)Kamera ein HD-Bild als LiveStream und soll dann dieses auf dem Bildschirm darstellen.
2. Dieses Bild soll mit einem anderen Bild (1125x750px) transparent überlagert werden.
3. Wahlweise soll das Bild des LiveStreams um 90,180 oder 270 Grad rotiert werden.Die Kamera gibt mir ca. 10 Bilder pro Sekunde und ich schreibe eine MFC Anwendung.
Bei Verwendung von GDI komme ich ohne Rotation aber mit AlphaBlending auf 8fps bei der Anzeige. GDI kann jedoch nicht rotieren (soweit ich weiß).
Benutze ich die GDI+, kann ich problemlos das Bild rotieren und bleibe bei 8fps, habe aber erstmal keine Transparenz. Die Transparenz kann über die Verwendung der ImageAttributes bei drawImage dennoch erreicht werden. Allerdings hab ich jetzt nur nur 2-4 fps.
Ich weiß aus dem Forum, das GDI+ nicht gerade das Optimum für Grafikprogrammierung ist und nicht über die GPU geht. Aber dass es sich so arg verhält, hat mich überrascht.
Mein Ausweg, der mir jetzt nur noch einfällt, ist die Verwendung von DirectX, wobei ich die Bilder als Textur verwende und auf den Hintergrund lege. Aber es erscheint mir recht aufwändig über 3D zu gehen, damit ich eine 2D Transformation Problematik lösen kann. Seit Win7 soll es ja auch Direct2D geben, was jedoch erstmal keine Option ist, da die Anwendung auf PCs mit XP und Vista laufen soll und die Rechner mitunter 3 Jahre alt sind.Hat jemand einen Tipp für mich, wie ich die Performance verbessern kann oder bleibt mir wirklich nur die Verwendung von DirectX?
-
implementiere es selbst in software.
welche hardware ist das eigentlich mit den 8fps bzw 2fps?
-
Aber es erscheint mir recht aufwändig über 3D zu gehen, damit ich eine 2D Transformation Problematik lösen kann.
Nein, das wird bei aktuellen 2D-Spielen von Hobbyprojekten auch so gemacht.
-
Danke für die Antworten. Die 2 fps hab ich jetzt nicht mehr, sondern 5-6. Es ist schon so, dass der Rechner hier sehr lahm ist (GF6600, P4 3,6GHz).
Ich hab hier einmal einen Beispielcode, der GDI+ verwendet:
Image* imgBase = NULL; // global void CBildPerformanceMFCDlg::updateImage() { current_frame++; TRACE("Updating!\n"); RECT rect; CDC* dc = GetDlgItem(IDC_STATIC_IMAGE)->GetDC(); GetDlgItem(IDC_STATIC_IMAGE)->GetWindowRect(&rect); Graphics g(dc->GetSafeHdc()); int w_window = rect.right-rect.left; int h_window = rect.bottom-rect.top; // 1.Bild if (imgBase == NULL) { imgBase = Image::FromFile(L"base_image.bmp"); } // 2.Bild ist dynamisch Image* imgTrans; imgTrans = Image::FromFile(L"trans_image.bmp"); // Transparenz setzen FLOAT alpha = 0.7f; /* ColorMatrix ClrMatrix; REAL m[5][5] = { {1,0,0,0,0}, {0,1,0,0,0}, {0,0,1,0,0}, {0,0,0,alpha,0}, {0,0,0,0,1} }; memcpy(&ClrMatrix, &m, sizeof(m)); */ ColorMatrix ClrMatrix = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, alpha, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; ImageAttributes ImgAttr; ImgAttr.SetColorMatrix(&ClrMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap); // Hintergrundpuffer Bitmap screenBuffer(w_window, h_window); RectF rDest(0,0,w_window, h_window); Graphics gOff2(&screenBuffer); // Rotieren imgBase->RotateFlip(Rotate90FlipNone); gOff2.Clear(Color(0,0,0)); gOff2.DrawImage(imgBase, Point(0,0)); // transparent überlagern gOff2.DrawImage(imgTrans, rDest, 0,0, imgTrans->GetWidth(), imgTrans->GetHeight(), UnitPixel, &ImgAttr, 0,0); g.DrawImage(&screenBuffer, Point(0,0)); ReleaseDC(dc); }
Darin werden 2 Bilder mit Transparenzeffekt übereinandergelegt und das 1. Bild rotiert (nur damit man sieht, dass auch was passiert).
Damit komm bei meinem P4 auf 8fps.
Ein Dualcore mit 3GHz schafft 14 fps. Ist jetzt auch nicht so viel...
Die Bilder sind jeweils 1024*768 Pixel groß und werden auf einer Zeichenfläche mit einer Größe von 1300*770 Pixel gezeichnet.Ich muss zugeben, dass ich noch nicht bei C++ durchblicke, weil ich eher in Java programmiere. Wahrscheinlich kann man die Erzeugung der ImageAttributes im Code optimieren oder global auslagern, um die Performance zu steigern... weiß nur nicht wie.
Zum 2. Problem:
DirectX sieht soweit recht gut aus und mein Teapot-Objekt (zu Testzwecken) rotiert problemlos. Um nun mein LiveBild per Direct3D anzuzeigen, wollte ich ein Rechteck als Objekt erzeugen und darauf das LiveBild als Textur hinzufügen.
Nur kann ich nur eine Textur auf mein Objekt setzen und kann diese auch nicht updaten. Und auch wenn ich sie aktualisieren könnte, vermute ich mal, dass es etwas dauern würde, um das Objekt zu texturieren... oder seh ich das falsch?Falls ihr weiterhelfen könntet, wäre das super!
-
// 2.Bild ist dynamisch Image* imgTrans; imgTrans = Image::FromFile(L"trans_image.bmp");
Hab ich es mir doch gedacht ... die Probleme sind an ganz anderer Stelle zu suchen. Wenn du Performanceprobleme hast, dann setze doch bitte erstmal einen Profiler ein und schaue, was denn wirklich Zeit kostet.
Das Laden von der Festplatte braucht im Vergleich zu allem anderen unendlich lange. Warum soll es denn bei jedem Frame neue geladen werden? Es ist naemlich kein LiveStream, wie du es geschrieben hast. Benutze doch dafuer die Funktionen der beiliegenden Bibliothek der Kamera.
1. Ich bekomme von einer (Foto-)Kamera ein HD-Bild als LiveStream und soll dann dieses auf dem Bildschirm darstellen.
oder seh ich das falsch?
Ja, das siehst du falsch. Aber DirectX wird dir bei deinem Problem nicht helfen.
Zu letzt faellt auf: Wie gibst du das dynamisch erzeugte Image wieder frei?
-
knivil schrieb:
// 2.Bild ist dynamisch Image* imgTrans; imgTrans = Image::FromFile(L"trans_image.bmp");
Hab ich es mir doch gedacht ... die Probleme sind an ganz anderer Stelle zu suchen. Wenn du Performanceprobleme hast, dann setze doch bitte erstmal einen Profiler ein und schaue, was denn wirklich Zeit kostet.
Stimmt. Der Code ist hier nicht optimal. In der realen Anwendung lad ich das Bild nicht jedesmal neu von der Festplatte, sondern bekomme es schon von einem Stream, welchen ich dann aber trotzdem wieder in ein Image-Objekt schreiben muss.
Ich bin mir ziemlich sicher, dass ich das Bearbeiten des Stroms und das Zeichnen falsch mache, denn das geschieht hintereinander und ohne Nebenläufigkeit. Der Download des Bildes von der Kamera braucht schonmal 50-70ms und das Zeichnen ca. 100ms. Ich versuche dann zumindest das Zeichnen in einem Thread ablaufen zu lassen und den Zugriff auf diesen Bereich mit einer Semaphore zu schützen. Während dann gezeichnet wird, kann das neue Bild schon geladen werden.
Der Tipp mit dem Profiler ist wirklich gut. Der hätte mir den Bottleneck schon früher gezeigt. Ärgerlich nur, dass MS den Profiler nur für die VS TeamSuite Edition anbietet... ich verwende die Professional Edition und versuch nun über die Kommandozeile zu profilen.
Danke für eure Hilfe!
-
Warum hälst du das Bild nicht in einem Buffer vor und arbeitest auf dem?
Und benutzt du einen Backbuffer? Mittels BitBlip ( ist ein GDI-Call ) kannst du da eventuell noch mehr FPS herauskitzeln. Wir sind hier auch an GDI gebunden und haben die GDI+ Zeichen-Operationen per GDI-BitBlip überschrieben, da das sich als performanter herausgestellt hat.
Und der CodeAnalyst ist ein freier Profiler, der auch mit einer grafischen Oberfläche benutzt werden kan nund nicht nur auf AMD-Prozessoren läuft.Gruß Kimmi