Как решить QPixmap :: fromImage утечка памяти? - PullRequest
2 голосов
/ 17 ноября 2009

У меня проблема с Qt.

Вот часть кода, которая меня беспокоит:

    void FullScreenImage::QImageIplImageCvt(IplImage *input)
{
    help=cvCreateImage(cvGetSize(input), input->depth, input->nChannels);
    cvCvtColor(input, help, CV_BGR2RGB);
    QImage tmp((uchar *)help->imageData, help->width, help->height, help->widthStep, QImage::Format_RGB888);
    this->setPixmap(QPixmap::fromImage(tmp).scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
    cvReleaseImage(&help);
}


void FullScreenImage::hideOnScreen() {
    this->hide();
    this->clear();
}

void FullScreenImage::showOnScreen(IplImage *slika, int delay) {
    QImageIplImageCvt(slika);
    this->showFullScreen();
    if(delay>0)
 QTimer::singleShot(delay*1000, this, SLOT(hideOnScreen()));
}

Итак, метод showOnScreen использует закрытый метод QImageIplImageCvt для создания QImage из IplImage (который используется OpenCV), который затем используется для создания QPixmap, чтобы показать изображение в полноэкранный. FullScreenImage класс наследует QLabel.

После некоторой задержки полноэкранное изображение должно быть скрыто, поэтому я использую QTimer, чтобы вызвать событие после некоторой задержки. Обработчик событий - это метод hideOnScreen, который скрывает метку и должен очистить память.

Проблема заключается в следующем:

Всякий раз, когда я вызываю QPixmap::fromImage, он выделяет память для данных растрового изображения и копирует данные из буфера памяти QImage в буфер памяти QPixmap. После того как метка скрыта, данные QPixmap по-прежнему остаются выделенными, и, что еще хуже, после нового вызова QPixmap::fromImage новый фрагмент памяти выделяется для нового изображения, а старые данные не освобождаются из памяти. Это вызывает утечку памяти (около 10 МБ на вызов метода с моими тестовыми изображениями). Как я могу решить эту утечку?

Я даже пытался создать личную переменную QPixmap, сохранить для нее растровое изображение, созданное QPixmap::fromImage, а затем попытался вызвать его деструктор в методе hideOnScreen, но это не помогло.

Существует ли нестатический способ создания QPixmap из QImage? Или еще лучше, есть ли способ создать QPixmap прямо из IplImage*?

Заранее благодарю за ответы.

Ответы [ 4 ]

1 голос
/ 26 марта 2010

Нет способа создать QPixmap непосредственно из IplImage* (а также не из cv::Mat). Однако ваше решение - воздержаться от записи всего в одну строку и работать с указателем, который вы освобождаете сами.

например:.

if (this->mypixmap)
    delete this->mypixmap;
this->mypixmap = new QPixmap(QPixmap::fromImage(tmp).scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
this->setPixmap(this->mypixmap);

Не забудьте установить mypixmap(NULL) в конструкторе.

0 голосов
/ 29 января 2019

Использование перегруженного метода решило проблему для меня:

QPixmap::fromImage(const QImage && image,..)

Вы можете позвонить с помощью:

QPixmap::fromImage(std::move(tmp))
0 голосов
/ 04 февраля 2011

У меня была похожая проблема, однако мой код был другим, поэтому его не стоит здесь размещать. Если взять ваш код и объединить с моим методом, вы получите:

void FullScreenImage::QImageIplImageCvt(IplImage *input)
{
    help=cvCreateImage(cvGetSize(input), input->depth, input->nChannels);
    cvCvtColor(input, help, CV_BGR2RGB);
    QImage* tmp = new QImage((uchar *)help->imageData, help->width, help->height, help->widthStep, QImage::Format_RGB888);
    this->setPixmap(QPixmap::fromImage(*tmp).scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
    delete tmp;
    cvReleaseImage(&help);
}
0 голосов
/ 17 ноября 2009

Вы должны иметь возможность использовать QPixmap::loadFromData для непосредственного создания QPixmap. Так что может работать что-то вроде следующего:

QPixmap p;
p.loadFromData((uchar *)help->imageData, help->width * help->height);

Не зная ничего об OpenCV или IplImage, я не могу гарантировать, что приведенный выше фрагмент верен, но, надеюсь, он направит вас по правильному пути.

...