wie mache ich Grafikfunktionen schnell?

Alles rund um die Programmierung mit Qt
Antworten
qtNiko
Beiträge: 216
Registriert: 6. April 2007 21:26
Wohnort: München

wie mache ich Grafikfunktionen schnell?

Beitrag von qtNiko »

hi,

die Aufgabe besteht darin, eine Sequenz von Bildern jeweils einzulesen, Linien einzumalen und darzustellen. Und das soll möglichst schnell sein - letztendlich unter 15ms pro Schleife. Ein erster Versuch damit war sehr ernüchternd, was die Geschwindigkeit betrifft:

Code: Alles auswählen

...
    bild = new QPixmap(768, 576);
	QPainter painter;  // zum Malen der Linien
	for (il=0; il<ANZ_LOOPS; il++)  {
		bnr = 100 +  (il % 10);  // unabhängig von ANZ_LOOPS werden immer nur 10 Bilder zyklisch dargestellt
		fname = "testbild_"  + QString::number(bnr) + ".pgm";
		bild->load(fname);   // das Bild in der Datei ist nur 256x256 Pixel groß
		painter.begin(bild);

		painter.setPen(Qt::green);
		for (i=0; i<ANZ_SLINES; i++) 
			painter.drawLine(slines[i].anfx+il,slines[i].anfy, slines[i].endx, slines[i].endy);
		
		painter.setPen(Qt::red);
		for (i=0; i<ANZ_MLINES; i++) 
					painter.drawLine(mlines[i].anfx+il, mlines[i].anfy, 	 mlines[i].endx, mlines[i].endy);
		
		painter.end();
		ZeichenBox->setPixmap(*bild);  //  ZeichenBox ist ein QLabel zur Darstellung
		QApplication::processEvents();  // damit alle Bilder zu sehen sind
	}
1. Auf meinem Athlon 3200+ dauert ein Schleifendurchlauf über 100ms! Das ist um eine Größenordnung zu lange! Kann man das nicht schneller machen, und wie?

2. Ich lese ein 256x256 großes Bild in ein 768x576 großes Pixmap und würde erwarten, dass nur ein kleines Bild links oben zu sehen ist. Tatsächlich aber füllt das eingelesene Bild die ganze Fläche aus. Wie kann ich erreichen, dass das eingelesene Bild genau so groß dargestellt wird, wie es ist?

Mein System: HP Pavillon 3237, Athlon64 3200+ , GeForce 6200, Suse Linux 10.1, Eclipse-Europa
Gruß von qtNiko

Core i5 760, GT 240, Suse Linux11.3, Eclipse-CDT-Helios, QT4.4, QT-Integration
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

1. Du lädst ein Bild (wahrscheinlich immer das selbe?). Das muß von der Platte gelesen und decodiert werden.

Du führst processEvents aus, damit wird aber nicht nur das Label neu gezeichnet.

Wieviele Linien zeichnest du, könnte man das cachen? In einem QPicture oder einem QPixmap?


2. Load & Copy
qtNiko
Beiträge: 216
Registriert: 6. April 2007 21:26
Wohnort: München

Beitrag von qtNiko »

1. Du lädst ein Bild (wahrscheinlich immer das selbe?). Das muß von der Platte gelesen und decodiert werden.
Auf der Platte steht das Bild im pgm-Format, binär. In meiner endgültigen Applikation wird es über den PCI-Bus eingelesen, was sicher schneller sein wird. Aber das Einlesen des Bildes gehört in der Schleife auf jeden Fall dazu.
Du führst processEvents aus, damit wird aber nicht nur das Label neu gezeichnet.
Wie kann ich sonst Qt dazu bringen, alle Bilder anzuzeigen, nicht nur das letzte?
Wieviele Linien zeichnest du, könnte man das cachen? In einem QPicture oder einem QPixmap?
In meinem Test sind es 230 Linien, die künftige Maximalzahl.
Wie sieht das aus, cachen? Ich male die Linien bereits auf ein QPixmap, und zwar in der Reihenfolge zuerst das Bild in das QPixmap und danach die Linien.
Wäre die Verwendung von QPicture schneller?
2. Load & Copy
Das ist mir leider zu stenografisch. Also, mit load() lade ich doch das Bild von Datei in das QPixmap. Was soll ich dann noch mit Copy?
Gruß von qtNiko

Core i5 760, GT 240, Suse Linux11.3, Eclipse-CDT-Helios, QT4.4, QT-Integration
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Du wolltest eine Begründung, warum deine Schleifen so langsam sind, ich hab dir ein paar mögliche Gründe genannt.

Und bei 15ms Wiederholrate stellt man nicht alle Bilder dar, schließlich ist es für das menschliche Auge nicht mehr erfaßbar => unnötiger Zeitverbrauch

Du hast meine Frage, bezüglich des cachen nicht beantwortet. Zeichnest du immer die selben Linien?

Ich kann jetzt auch den Grund nicht nachvollziehen, warum das Bild bei dir beim laden skaliert wird. Also in ein Separates QPixmap laden und dann ins Zielbild kopieren. Wäre ein Möglichkeit.
qtNiko
Beiträge: 216
Registriert: 6. April 2007 21:26
Wohnort: München

Beitrag von qtNiko »

Du hast meine Frage, bezüglich des cachen nicht beantwortet. Zeichnest du immer die selben Linien?
In meinem Testbeispiel sind es immer die gleichen Linien. Später aber werden es jeweils unterschiedliche und auch unterschiedlich viele sein. Damit ich sehe, ob jedesmal die Linien neu gemalt werden, lasse ich die x-Anfangskoordinate pixelweise laufen.

Und bei 15ms Wiederholrate stellt man nicht alle Bilder dar, schließlich ist es für das menschliche Auge nicht mehr erfaßbar => unnötiger Zeitverbrauch
Na ja, das Auge soll eine flüssige Bewegung sehen. Die 15 ms habe ich mal so abgeschätzt, weil später noch einiges dazukommen wird, und alles dann mit 50Hz ablaufen muss.

Ich werde noch weiter testen, aber ich vermute, dass das Malen der Linien den größten Teil der Zeit braucht. Qt hat doch auch OpenGL-Funktionen. Ich kenne sie nicht, aber wenn ich OpenGL höre, dann denke ich an Grafikkartenunterstützung. Damit müsste es doch wesentlich schneller werden, oder?
Gruß von qtNiko

Core i5 760, GT 240, Suse Linux11.3, Eclipse-CDT-Helios, QT4.4, QT-Integration
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

50Hz mit einem QImage-decode + Scale + Anzeige auf ein QWidget in der Größe von 256x256? Imho unmöglich.
2. Ich lese ein 256x256 großes Bild in ein 768x576 großes Pixmap
aha - ich würde sagen wir fangen nochmal von vorn an und schauen was wir programmiert haben.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
qtNiko
Beiträge: 216
Registriert: 6. April 2007 21:26
Wohnort: München

Beitrag von qtNiko »

aha - ich würde sagen wir fangen nochmal von vorn an und schauen was wir programmiert haben.
In meinem Originalposting steht der Code (hier noch mal verkürzt auf das Wesentliche):

Code: Alles auswählen

bild = new QPixmap(768, 576);
   QPainter painter;  // zum Malen der Linien
   for (il=0; il<ANZ_LOOPS; il++)  {
      ...
      fname = ...;
      bild->load(fname);   // das Bild in der Datei ist nur 256x256 Pixel groß 
...     Linien malen mit drawLine(...)
...
ZeichenBox->setPixmap(*bild);  //  ZeichenBox ist ein QLabel zur Darstellung
      QApplication::processEvents();  // damit alle Bilder zu sehen sind 
}
Das müsste doch so klappen?
Das Skalieren passiert vermutlich am Ende bei ZeichenBox->setPixmap(*bild)?
Das mag ja in vielen Fällen praktisch sein, wenn man nicht extra skalieren muss, um das Bild stets gefüllt zu bekommen. Aber ich bräuchte es gerade ohne Skalierung :?

Jetzt habe ich ein paar interessante Zeitmessungen:
Wenn man den Job aufteilt in a) Bild von Datei lesen, b) 230 Linien einmalen und das QPixmap an das QLabel übergeben, c) Bild darstellen mit QApplication::processEvents(), dann ergibt sich folgendes pro Schleifendurchlauf:
a+b+c: 170ms
b+c: 160ms
a+b: 30ms
b: 3ms

Das Darstellen per QApplication::processEvents() (mit allem, was sonst noch dabei passiert) frisst fast die gesamte Zeit.

Wie kann ich jedes einzelne Bild darstellen, ohne jedoch QApplication::processEvents() zu verwenden?
Gruß von qtNiko

Core i5 760, GT 240, Suse Linux11.3, Eclipse-CDT-Helios, QT4.4, QT-Integration
PeterLustig
Beiträge: 386
Registriert: 21. November 2007 20:07

Beitrag von PeterLustig »

Sie die Bilder die du lädst denn immer dieselben, oder verändern sich diese? Wenn sie die gleichen sind, musst du sie ja nicht jeden Schleifendurchlauf neu laden.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Unabhängig von der Geschwindigkeit - Du erzeugst ein Biuld mit 768*512 und dann lädst Du ein anderes - das meine ich.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Dein Problem ist nicht, daß du die Grafiken nicht schnell genug darstellen kannst, sondern daß du eine Framerate willst, die nicht sinnvoll ist.

Außerdem solltest du uns mal mitteilen, was an deiner Grafik statisch und was dynamisch ist.
qtNiko
Beiträge: 216
Registriert: 6. April 2007 21:26
Wohnort: München

Beitrag von qtNiko »

Jetzt verstehe ich: Mit "bild.load(fname)" wird das QPixmap ganz neu definiert, d.h. auch in den Abmessungen. Ich dachte, mit load() wird nur in ein bestehendes QPixmap Inhalt reingeladen. So etwas brauche ich nämlich letztendlich, dass in ein 768x576 großes Bild links oben ein kleineres Bild eingesetzt wird. Dann bleibt natürlich rechts und unten ein Rand, der dann mit alphanumerischen Daten gefüllt wird, siehe das Bildbeispiel im Anhang.
Dazu muss ich mir erst mal zusammensuchen, was es dafür gibt - hat jemand einen schnellen Tipp?
Dateianhänge
Bildbeispiel.gif
Bildbeispiel.gif (8.36 KiB) 6051 mal betrachtet
Gruß von qtNiko

Core i5 760, GT 240, Suse Linux11.3, Eclipse-CDT-Helios, QT4.4, QT-Integration
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

QPainter::drawPixmap() - aber das macht das ganze noch langsamer.
Oder gleich auf das QLabal (oder was auch immer Du benutzt) zeichnen, ggf. QGLWidget benutzen damit OpenGL benutzt wird.
D.h. einen QTimer mit 50Hz starten und dort ein Q(GL)Widget::update() auf das zu zeichnende Widget auslösen.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
qtNiko
Beiträge: 216
Registriert: 6. April 2007 21:26
Wohnort: München

Beitrag von qtNiko »

ok, danke jetzt habe ich eine Spur. Der Rest ist dann hoffentlich nur noch Fleißarbeit :)
Gruß von qtNiko

Core i5 760, GT 240, Suse Linux11.3, Eclipse-CDT-Helios, QT4.4, QT-Integration
Antworten