JPG,PNG,GIF(Beweglich/Unbeweglich) Skalieren und drechen

Alles rund um die Programmierung mit Qt
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Uff... 100000x100000...
Du solltest eher darüber nachdenken, das Bild zu zerstückeln (100x100, o.Ä.) und diese tiles dann zeichen.

Einen Bildausschnitt kriegst du mit QImage::copy() bzw. QPixmap::copy().
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Vielleicht wäre es auch mal nicht schlecht, die Grundrechenarten zu lernen:

100000*100000*4/(1024^3)

Und wer das jetzt noch in seinen Arbeitsspeicher reinkriegt, (am besten noch auf einer 32Bit-Maschine) kann mir die Maschine ja mal zeigen.
Experimentierer
Beiträge: 18
Registriert: 1. Mai 2011 12:06

Beitrag von Experimentierer »

Es muss ja nicht das ganze Bild in den Speicher geladen werden. Die Idee ist ja das Bild zu vergrößern und zu Teilen das ich nur den sichbaren teil + ca 20% Skaliere und wen weiter Skaliert wird weiter teile. Skaliert soll nur der Bereich den ich anzeigen will + ca. 20% als Puffer damit ich das Bild ruckelfrei bewegen kann. Wie ich so was realisiere weiß ich jedoch leider nicht. Bis einer Auflösung von 9500*9500 konnte ich mein Bild komplett rückefrei bewegen. Da kann ich mir vorstellen das man das Bild immer in 1000*1000 Teile teilt und nur die aktuell benötigten zusammen fügt und Skaliert.
Soweit ich das das sehe sind 3 Dinge entstanden für die ich keine Idee habe bzw. keine Ahnung wie das genau zu meistern ist.
1. Kann nicht ganz nachvollziehen wie genau ich das Bild "verwalte".
2. Ich muss das Bild Teilen, aber wie stelle ich das an das ich das Bild in 4 Teile teile, Teil 1 stark vergrößerte so das ich dieses auch teilen muss und danach bewege ich das Bild und muss an die nicht Skalierten Teile ran :?:.
3. Wie ich so ein Bild drehe. Dabei habe ich es noch nicht mal hinbekommen ein nicht Skaliertes Bild zu drehen ohne das es aus dem sichbaren Bereich gekommen ist.

Sollte mein vorhaben jedoch zu kompliziert sein wäre es auch ok wen ich die Bilder nur bis 10000*10000 Skaliere. Aber auch bei dieser Größe sollte ich wohl Teilen. Drehen möchte ich auch :oops:.

Hoffe ihr habt ein paar ideen für mich.

PS falls ich mich undeutlich ausdrücke oder ihr meinen fahl nicht ganz nachvollziehen könnt kann ich euch auch meinen bisherigen Quellcode per EMail als rar zuschicken damit ihr mir besser weiterhelfen könnt.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Das Bild sollst du natürlich VOR Programmstart schon in Einzelteilen auf Festplatte speichern! Wenn du willst, kannst du auch gleich mehrere Varianten in verschiedenen Auflösungen erzeugen, damit du bei der Gesamtansicht nicht wieder Gefahr läufst, dass dein Speicher ausgeht...
Siehe z.B. imagemagick (convert -crop) wie sowas automatisiert werden kann.
Die Umrechnung von Zoomfaktor, Rotation und aktueller Anzeigebereich in die notwendigen Einzelteile bleibt dir überlassen :P Sollte nicht wirklich tragisch sein. Setz dich mit Papier und Stift hin, und versuch dich an deine Mathekenntnisse zu erinnern (sin/cos, z.B.)
Du solltest problemlos die doppelte Größe deines Anzeigebereichs laden können. Wenn der User sich (z.B.) 30% an den Rand nähert, kannst du schonmal die Bilder laden, die in der Richtung weitergescrollt sich anschließen. Denk aber dran, dass du irgendwann die Bilder wieder entladen solltest, wenn sich der User zu weit davon entfernt hat (z.B. 200% der angezeigten Breite/Höhe).
Experimentierer
Beiträge: 18
Registriert: 1. Mai 2011 12:06

Beitrag von Experimentierer »

Das Programm soll Bilder Anzeigen, dabei kann ich ein Bild mit diesem Programm Starten oder danach hinzufügen. Ich kann also nicht erst das Bild Teilen und danach erst das Programm Starten. Mein Programm soll die Originalen Bilder nur Temporär verändern, nicht speichern. Heutzutage haben die meisten 2, 4 und viel mehr Arbeitsspeicher, selbst mein Lappi hat 4. Deswegen denke ich kann mein Programm im schlimmsten Fall auch bis zu 2GB nutzen. Hoffe jedoch das so hinzubekommen das ich das auf max 250MB beschränken kann. Indem ich es hinkriege das jeweils aktuelle Bild zu teilen sobald das 200% des sichbaren erreicht.

Beispiel ein Bild 1000X800 auf einem Bildschirm 1600x900 soll 20 mal vergrößert werden. Das Bild wird vergrößert und erreicht eine Größe von 3200x1800 (200%), hier soll es in 36 teile geteilt werden. Nur die notwendigen teile + Puffer bleiben im Speicher und werden angezeigt, Rest verwerfen. Wird weiter vergrößert widerholt es sich. Wird jetzt das Bild im Fenster bewegt so das der Bereich der im Puffer ist angezeigt werden soll sucht das Programm schon mal den teil der danach in die selbe Richtung kommen sollte und skaliert diesen Bereich auf die selbe Größe. Das was jetzt außerhalb des sichbaren + Puffers ist wird verworfen. Beim verkleinern oder drehen funktioniert das nach dem selben prinzip :wink:.

Doch glaube ich nicht das ich so was ohne größere Unterstützung hinkriege da ich ja schon beim drehen versage. Den sobald ich versuche zu drehen verschwindet das Bild aus dem sichbaren und mein bewegen des Bildes funktioniert spiegelverkehrt. Oder das Bewegen ist danach schief. Das Bild kriege ich auch nicht genau in den sichbaren Bereich :cry:.

Wie ich imagemagick in meinem Programm nutzen könnte habe ich auch nicht verstanden.

Da ich vermute das ich damit wohl sehr viel von demjenigen verlange der mir dabei helfen sollte, bitte ich das mir einer dabei hilft das Drehen zu realisieren (das in Verbindung mit der Bewegung des Bildes).
Experimentierer
Beiträge: 18
Registriert: 1. Mai 2011 12:06

Beitrag von Experimentierer »

Hat den keiner mehr eine Idee ? Oder ist hier niemand der dies List ?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Verwende doch den QImageReader... Die Doku ist (fast) selbsterklärend, wenn man sich lange genug davor setzt.
Dein Fehler: Du versuchst ALLES mit einem Widget zu erschlagen, und das gleich mit allen möglichen und unmöglichen Bildformaten und vor allem Bildgrößen. Für einen Anfänger läuft das auf Überforderung und zügigem Fail hinaus.

Tip 1:
Fang langsam an, beschränke dich zuerst auf ein bestimmtes Feature (entweder große Dateien oder animierte gifs oder Drehen/Verschieben)
Schreib dir dazu eine einfache Klasse, die nur das kann.
Danach kümmerst du dich in separaten Tests (!) um die anderen Features.
Wenn du mit den einzelnen Sachen zurecht kommst, mach dich an das Zusammenfügen.

Tip 2:
Nicht Laden und Anzeige in eine Klasse. Lager das Laden in eine andere Klasse aus, die dann von dem Widget benutz wird, um die Bilder zu malen. Du kannst dabei wunderbar per SIGNAL/SLOT einzelne Bilder/Bildausschnitte "rüberfunken", wenn du das willst.

Wg. großen Bildern hier gleich mal der Tip:
QImageReader kann per setClipRect() angewiesen werden, nur einen Auschnitt aus dem ganzen zu lesen. Das sollte speicherschonend sein. Das rect musst du natürlich entsprechend dem Ausschnitt, den das Widget malen will, setzen.

Wg. Drehen:
Du hast einen Koordinatenursprung, um den herum gedreht wird. Der ist IMMER links oben. Wenn du um das aktuelle Zentrum herum drehen willst, musst du per translate() dem painter einen neuen Ursprung zuweisen.

Ich bin gerne bereit, auch mit Code zur Seite zu stehen. Nur werd ich nicht den Anfang machen ;)
Such dir ein Problem raus, zeig uns einen Ansatz, dann kommt auch konkrete Unterstützung. Dann werd ich auch nicht der einzige Kommunikationspartner sein :P
Experimentierer
Beiträge: 18
Registriert: 1. Mai 2011 12:06

Beitrag von Experimentierer »

Hallo Franz
Vom QImageReader bin ich wider ab da er keine Animation unterstützt und sehr langsam ist. Den nutze ich nur noch im mir die Bildformate auszugeben die unterstützt werden.
Mir geht es aber genau darum ein Widget zu finden auf dem ich ALLE Bilder Anzeigen kann. Um alle gleich zu behandeln und die gleichen Möglichkeiten zu bieten.

Eine vorübergehende Möglichkeit habe ich gefunden. Den mir ist aufgefallen das die QGraphicsView so was ähnliches kann was ich gesucht habe. Diese Skaliert nur einen Bereich der QGraphicsScene so dass das Bild nicht immer mehr Speicher frisst und ich trotzdem stark Skalieren kann. Zudem bietet sie auch eine Möglichkeit zu Drehen :D.

Die QGraphicsView schränkt mich leider aber auch ein den ich kann das Bild nicht mehr "frei" Bewegen und kann auch nicht einfach Rahmen und Hintergrund ausblenden um NUR noch das Bild zu sehen.
Den selbst wen ich this->setWindowFlags(Qt::FramelessWindowHint); und this->setAttribute(Qt::WA_TranslucentBackground);
anwende wie sonst auch. Der Fensterrahmen verschwindet zwar aber der Hintergrund und ein dünner Rand drumherum bleibt.

Das einlesen braucht bei Ordnern über 1000 Dateien wirklich eine weile. Wen ich das in einen Separaten Prozess auslagern könnte wäre das wirklich toll jedoch weiß ich nicht wie das funktioniert. über ein kleines Beispiel würde ich mich freuen :roll:.

Für den Hinweis mir dem translate() danke ich dir. Werde es mal probieren.

Den Code habe ich bereits angeboten vor 5 Posts. Einzelne teile sind schwierig da bei mir das meiste kreuz und qwer geht so das meist nicht ersichtlich ist was wohin geht. Jetzt ist es noch schlimmer geworden da ich es in 3 Klassen habe. Eine "Bedienung", ein "Sichtfenster" und eine die sich um die Bilder kümmert. Dabei ist die mit den Bildern die wo alles drübergehtund zusammen kommt.

Aktuell habe ich also die wichtigsten Probleme gelöst wen auch nicht unbedingt optimal. Funktioniert nicht alles wie gewünscht und ist zu träge.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Experimentierer hat geschrieben:Vom QImageReader bin ich wider ab da er keine Animation unterstützt und sehr langsam ist.
1) KANN QImageReader mit Animationen umgehen! Hab ich oft, gesagt, werds auch noch oft tun. Wenn du mir nicht glaubst, schau dir an was QMovie so treibt (die sourcen liegen ja offen).
2) QImage::load() macht was? Genau - Bild mit QImageReader laden.
Eine vorübergehende Möglichkeit habe ich gefunden. Den mir ist aufgefallen das die QGraphicsView so was ähnliches kann was ich gesucht habe. Diese Skaliert nur einen Bereich der QGraphicsScene so dass das Bild nicht immer mehr Speicher frisst und ich trotzdem stark Skalieren kann. Zudem bietet sie auch eine Möglichkeit zu Drehen :D.
Wie zeigst du da das Bild an? Mit einem QGraphicsPixmapItem. Und wie bekommt der das Bild? per setPixmap(). Und wie schaffst du es HIER, das Pixmap als komplettes Bild zu übergeben, ohne dass es den ganzen Speicher frisst?
Movies kann es mMn. auch nicht.
Das einlesen braucht bei Ordnern über 1000 Dateien wirklich eine weile. Wen ich das in einen Separaten Prozess auslagern könnte wäre das wirklich toll jedoch weiß ich nicht wie das funktioniert. über ein kleines Beispiel würde ich mich freuen :roll:.
QPixmap über mehrere Threads bearbeiten geht AFAIK nicht, da brauchst du QImage.
Schau dir mal das mandelbrot-example in den Qt-Sourcen an, da gibts ein fettes Beispiel mit QImage und Threads ;)
Experimentierer
Beiträge: 18
Registriert: 1. Mai 2011 12:06

Beitrag von Experimentierer »

Ok vielleicht mache ich auch falsch. Ich habe es so gemacht probiert
QImageReader qirt("Bilder/Beweglich.gif");
qDebug()<<"supportsAnimation"<<qirt.supportsAnimation(); //supportsAnimation false
qDebug()<<"jumpToNextImage"<<qirt.jumpToNextImage(); //jumpToNextImage false
qDebug()<<"imageCount"<<qirt.imageCount(); //imageCount 10
qDebug()<<"loopCount"<<qirt.loopCount(); //loopCount -1
qDebug()<<"nextImageDelay"<<qirt.nextImageDelay(); //nextImageDelay 100
qDebug()<<"currentImageRect"<<qirt.currentImageRect(); //currentImageRect QRect(0,0 0x0)
und als vergleich
QMovie qm("Bilder/Beweglich.gif");
qDebug()<<"jumpToNextFrame"<<qm.jumpToNextFrame(); //jumpToNextFrame true
qDebug()<<"frameCount"<<qm.frameCount(); //frameCount 10
qDebug()<<"loopCount"<<qm.loopCount(); //loopCount -1
qDebug()<<"nextFrameDelay"<<qm.nextFrameDelay(); //nextFrameDelay 96
qDebug()<<"frameRect"<<qm.frameRect(); //frameRect QRect(0,0 425x307)
hinter // steht die ausgabe

Mit dem Bilder Anzeigen hast du mich woll falsch verstanden.
Derzeit fäuft es bei mir so.
Ich klicke auf den Buttn "Bild öffnen" und starte damit ein QFileDialog.

Code: Alles auswählen

QString fileName = QFileDialog::getExistingDirectory(this, tr("Bild Ordner"),"/home",QFileDialog::ReadOnly);
suche ein Bild aus.
Danach schikke ich es als QUrl(fileName) weiter an meine Methode, die mir alle Bilder des Ordners und deren Unterordnern in einen QVector<QFileInfo> einliest.
Danach schicke ich die Nummer des ersten Bildes an meine Methode die das Bild Auswertet.
In dieser schmeiße ich das Bild in ein QImageReader

Code: Alles auswählen

qirBild(qvqfiBilderInfos->at(iBildNr).absoluteFilePath());
dann prüfe ich ob es ein Animiertes Bild ist.
Indem ich if(qirBild.imageCount() > 1) prüfe.
Ist es true dan Lade ich das Bild in ein QMovie und Starte einen QTimer der mit der Methode nächstes Frame verbunden ist.
Diese macht tut nur den nächsten Frame in Mein QPixmap schmeisen. Erhalte ich false dann lade ich das Bild gleich in ein QPixmap.
Anschließend starte ich meine Methode Bild aktualisieren.
Diese setzt mein Bild im gewünschten Seitenverhältnis skalieren in die QGraphicsScene mit

Code: Alles auswählen

qgsBildUnterlage->addPixmap(*qpBildSklaiert);
die wiederum in meiner Abgeleiteten QGraphicsView ist.
Die QGraphicsView erlaubt mir das starke Skalieren mit this->scale(1.02, 1.02) bzw. this->scale( 0.98, 0.98 ) und Drehen mit this->rotate(355); bzw. this->rotate(5);.

Speicher verbrauche ich derzeit zwischen 20 und 100 MB.
Ich wollte nicht das Bild in mehreren Prozessen Bearbeiten sondern das einlesen der Bilder. Also die Methode die einen Ordner ausliest da die Bilder aussortiert und diese in meinen QVector<QFileInfo> abspeichert.
Das mandelbrot-example ist mir derzeit noch zu schwer das verstehe nicht nicht wirklich :oops:. Würde mich über ein kleines simples Beispiel freuen.
Antworten