Seite 1 von 1

QLabel setPixmap, setScaledContents(true) Speicherverbrauch

Verfasst: 9. Juli 2007 18:24
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...

Verfasst: 9. Juli 2007 19:16
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.

Verfasst: 26. Juli 2007 20:36
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"?

Verfasst: 26. Juli 2007 21:39
von Volker
Wenn Du setPixmap(*newPixmap); aufrufst, wird eine Kopie des Inhalts angelegt, du kannst also ohne weiteres dein newPixmap löschen.

Verfasst: 26. Juli 2007 21:59
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; )

Verfasst: 27. Juli 2007 16:59
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!

Verfasst: 27. Juli 2007 17:14
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.

Verfasst: 28. Juli 2007 15:26
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!

Verfasst: 28. Juli 2007 21:08
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?

Verfasst: 31. Juli 2007 12:01
von Zandru
Statt das Bild selbst umzurechnen, würde ich einfach Transformations benutzen:

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