QLabel setPixmap, setScaledContents(true) Speicherverbrauch

Alles rund um die Programmierung mit Qt
Antworten
AlGaN
Beiträge: 25
Registriert: 25. März 2006 12:45

QLabel setPixmap, setScaledContents(true) Speicherverbrauch

Beitrag von AlGaN »

Hallo,

ich muss einen Zoom für ein in einem QLabel anzuzeigendes jpeg-Bild implementieren und hab mich da an das imageviewer-Bsp aus dem examples-Verzeichnis von Qt gehalten.

Zunächst leite ich mein in einer QScrollArea anzuzeigendes Bild von QLabel ab:

Code: Alles auswählen

class QPicture : public QLabel
{
  Q_OBJECT
public:
  QPicture(QWidget *parent = 0);
  QPicture(const QString& filename, QWidget *parent = 0);
[...]
};
Im Konstruktor von QPicture setze ich dann wie im imageviewer-Bsp. die SizePolicy und ScaledContents-Eigenschaft von QLabel:

Code: Alles auswählen

QPicture::QPicture(QWidget *parent)
 : QLabel(parent)
{
  setMouseTracking(true);
  setFocusPolicy(Qt::StrongFocus);

  // QLabel init
  setBackgroundRole(QPalette::Base);
  setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
  setScaledContents(true);
}
In der öffentl. load()-Methode von QPicture wird dann das Bild geladen:

Code: Alles auswählen

bool QPicture::load(const QString& filename)
{
  if (!filename.isEmpty()) {
    QImage image(filename);
    if (image.isNull()) {
      qWarning("Cannot load '%s'", qPrintable(filename));
      return false;
    }
    setPixmap(QPixmap::fromImage(image));
    mScaleFactor = 1.0;
    adjustSize();
    update();
    return true;
}
Bevor ich meine eigenen Zeichenoperationen im QLabel ausführe, rufe ich entspr. in der paintEvent()-Methode von QPicture die paintEvent()-Methode von QLabel auf:

Code: Alles auswählen

void QPicture::paintEvent(QPaintEvent* e)
{
  QLabel::paintEvent(e);
  QPainter p(this);
  refreshPixmap(&p); // draw path
}
In der Methode scaleImage() wird das Bild dann skaliert (entsprechend der MouseWheel-Bewegung mit Skalierungsfaktor factor):

Code: Alles auswählen

void QPicture::scaleImage(double factor)
{
  if (!this->pixmap()) {
    qDebug() << "No Pixmap loaded!";
    return;
  }
  resize(factor * this->pixmap()->size());
}
Im Konstruktor von MainWindow, das von QMainWindow abgeleitet ist, wird die Scrollarea mit dem Label initialisiert:

Code: Alles auswählen

MainWindow::MainWindow()
  : pic(0), scrollArea(0)
{
  scrollArea = new QScrollArea;
  scrollArea->setBackgroundRole(QPalette::Dark);
  
  pic = new QPicture(scrollArea);
  scrollArea->setWidget(pic);
  setCentralWidget(scrollArea);
  resize(800,600);
}
Mein Problem nun: Beim Vergrössern/Verkleinern des jpeg-Bilds frisst das Programm jede Menge Speicher, selbst wenn ich nur ein kleines jpeg-Bild lade (~ 90 kB), belegt das Programm nach einigen Skalierungsstufen (Faktor 3-4) etwa 30 MB Speicher, größere jpeg-Bilder lassen sich gleich gar nicht mehr skalieren, ohne dass der Rechner in die Knie geht (512 MB RAM) :(

Gibt es irgendwelche Tricks beim Laden/Skalieren von jpeg-Bildern? Die Methode mit setPixmap() und resize() scheint auf jeden Fall nicht praktikabel zu sein für größere Bilder...

Danke für alle Hinweise,
AlGaN

P.S.: Die Klasse QPicture hat nichts mit der gleichnamigen Klasse von Qt zu tun, ich hab die Klasse nur zum besseren Verständnis umbenannt...
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Wenn ich es richtig gesehen habe, legst du das Bild skaliert wieder im Speicher ab. Das ist Speicherplatztechnisch etwas uneffizient. Leite halt von QWidget hab und zeichne dann im paintEvent deine Grafik skaliert.
Vrenn
Beiträge: 28
Registriert: 17. Oktober 2005 10:16

Beitrag von Vrenn »

Ich habe vermutlich das selbe Problem:
Eine von QLabel abgeleitete Klasse nimmt immer ein neues Bild (Qpixmap) entgegen und stellt es dar: setPixmap(*newPixmap);
ein delete newPixmap geht ja nicht, da es von QLabel noch verwendet wird.
Dennoch wird der Speicher von der Anwendung immer voller. (nach jedem setPixmap)
Schließe ich meine Daten und lösche die QLabels bleibt der Speicherverbrauch, schließe ich die QT-Anwendung ganz ist der Speicher wieder frei.

Kann es sein, das Qt die Pixmaps intern "hamstert"?
Volker
Beiträge: 343
Registriert: 30. Juni 2005 05:27

Beitrag von Volker »

Wenn Du setPixmap(*newPixmap); aufrufst, wird eine Kopie des Inhalts angelegt, du kannst also ohne weiteres dein newPixmap löschen.
Bitte seid so nett und ändert den Titel von Beiträgen die gelöst wurden, auf [gelöst] Beitragstitel
Vrenn
Beiträge: 28
Registriert: 17. Oktober 2005 10:16

Beitrag von Vrenn »

scheint nicht setpixmap zu sein. Habe ein eigenes speicherleck gefunden. Aber wenn ich folgendes mache:

image = new QImage( buffer, dicomimage->getWidth(), dicomimage->getHeight(), QImage::Format_RGB32);

muss ich dann buffer löschen?
( delete[] buffer; )
iaby
Beiträge: 53
Registriert: 10. Februar 2007 13:12

Beitrag von iaby »

buffer sollte eigentlich von demjenigen freigegeben werden, der ihn auch erstellt hat!
Wenn du aber ein "new" machst muss irgendwo auch wieder ein "delete" stehen! Also bei dir ein "delete image;" wenn du es nicht mehr brauchst!
Vrenn
Beiträge: 28
Registriert: 17. Oktober 2005 10:16

Beitrag von Vrenn »

Gefunden: Das war versteckt.
Ja, image muss gelöscht werden. Allerdings löscht das keinenfalls den buffer, obwohl er image übergeben wurde und dieser solange bestehen muss wie das qimage (gibt Speicherzugriffsfehler). Folgendes hat aber funktioniert:

Code: Alles auswählen

 ...
 uchar* buffer;
 ...
 buffer = new uchar[imageSize];
 ...
 image = new QImage( buffer,...

 //get rid of bufffer dependencies:
 QImage *independentImage = new QImage(*image);
 independentImage->bits();
 delete image;
 delete[] buffer;
 ...
 return independentImage;
Wobei anscheinend das bits(), wie mir ein Freund sagte dafür sorgt, dass der buffer in das qimage mit aller Verantwortung ( also auch den Bildinformationen und deren Löschung beim qimage-Destruktor) übernommen wird.
iaby
Beiträge: 53
Registriert: 10. Februar 2007 13:12

Beitrag von iaby »

Es sollte auch ein "return image;" reichen!
Schau dir mal die Doku zu bits() an: http://doc.trolltech.com/4.3/qimage.html#bits
Kannst den Befehl also getrost weglassen!
Volker
Beiträge: 343
Registriert: 30. Juni 2005 05:27

Beitrag von Volker »

Laut Doku müsste er es weglassen können. Guckt man sich den Source Code an wird in bits aber ein detach() aufgerufen, was aus der shallow copy eine deep copy macht. Weiß nicht genau ob das bei return image auch passiert. Abgesehen davon, wer löscht dann wo den Buffer?
Bitte seid so nett und ändert den Titel von Beiträgen die gelöst wurden, auf [gelöst] Beitragstitel
Zandru
Beiträge: 84
Registriert: 29. Mai 2007 15:35

Beitrag von Zandru »

Statt das Bild selbst umzurechnen, würde ich einfach Transformations benutzen:

http://doc.trolltech.com/4.3/painting-t ... tions.html
Antworten