How to solve QPixmap::fromImage memory leak? - qt

I have a problem with Qt.
Here is a part of code that troubles me:
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()));
}
So, the method showOnScreen uses private method QImageIplImageCvt to create QImage from IplImage (which is used by the OpenCV), which is then used to create QPixmap in order to show the image in full screen. FullScreenImage class inherits QLabel.
After some delay, the fullscreen picture should be hidden, so I use QTimer to trigger an event after some delay. The event handler is the hideOnScreen method which hides the label and should clear the memory.
The problem is the following:
Whenever I call QPixmap::fromImage, it allocates the memory for the pixmap data and copies the data from QImage memory buffer to the QPixmap memory buffer. After the label is hidden, the QPixmap data still remains allocated, and even worse, after the new QPixmap::fromImage call the new chunk of memory is allocated for the new picture, and the old data is not freed from memory. This causes a memory leak (cca 10 MB per method call with my testing pictures). How can I solve that leak?
I've even tried to create a private QPixmap variable, store pixmap created by the QPixmap::fromImage to it, and then tried to call its destructor in hideOnScreen method, but it didn't help.
Is there a non-static way to create QPixmap from QImage? Or even better, is there a way to create QPixmap directly from IplImage* ?
Thank you in advance for your answers.

There is no way to create QPixmap directly from IplImage* (and also not from cv::Mat). However, your solution there is to refrain from writing everything into one line and work with a pointer that you free yourself.
e.g.:
if (this->mypixmap)
delete this->mypixmap;
this->mypixmap = new QPixmap(QPixmap::fromImage(tmp).scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
this->setPixmap(this->mypixmap);
Don't forget to set mypixmap(NULL) in the constructor.

I had a similar problem, however my code was different so its not worth me putting here. Taking your code and merging with my method would give you:
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);
}

You should be able to use QPixmap::loadFromData to create a QPixmap directly. So something like the following might work:
QPixmap p;
p.loadFromData((uchar *)help->imageData, help->width * help->height);
Without knowing anything about OpenCV or IplImage, I can't guarantee that the above snippet is correct, but hopefully it starts you down the right path.

Using the overloaded method solved the issue for me:
QPixmap::fromImage(const QImage && image,..)
You can call it with:
QPixmap::fromImage(std::move(tmp))

Related

C++ QPixmap fromImage segmentation fault

I'm writing a program that requires frequent calls to the following slot function. This function worked normally in the beginning, but after a while, the segmentation fault appeared. img is delivered correctly and the problem happens in the fromImage function. How can I fix this?
void StitchWindow::showStitchImg(QImage img)
{
img_label->resize(img.width(), img.height());
QPixmap img_pix = QPixmap::fromImage(img);
img_label->setPixmap(img_pix)
}
QImage use an implicit data sharing. you need to detach your data by calling
img.bits()
void StitchWindow::showStitchImg(QImage img)
{
img.bits();
img_label->resize(img.width(), img.height());
QPixmap img_pix = QPixmap::fromImage(img);
img_label->setPixmap(img_pix)
}

How to run animation with blocked UI thread in Qt Widgets app?

In QML you can use Animator type to "animate on the scene graph's rendering thread even when the UI thread is blocked."
How can I achieve the same thing for Qt Widgets?
Basically, I want something like:
1) start loading screen / splash-screen
2) start GUI-blocking operation
3) stop loading screen / splash-screen
It is not possible to move the ui-blocking operation to a separate thread (Widgets are being created). I cannot modify this part.
I tried QQuickWidget and QQuickView containing the splash-screen scene with an Animator inside but it didn't work - they got blocked as well.
EDIT: In the separate thread I read the file containing the UI description. Then I recursively create hundreds of Widgets (including QQuickWidgets, QLabels for images, Web views etc.).
Point of the question was to see if there is a "workaround" for that (e.g. displaying the aforementioned QML scene in some separate window with an own event loop). Unfortunately at this point not much more can be done about the overall design of the above.
Probably the widgets you're creating do too much work. You have to specify exactly how many widgets you're creating, and how. Show some example code. In general, the GUI thread is for cooperative multitasking - if you have something that "blocks", break it down into tiny chunks. For example, suppose that you're processing some XML or json file to build the UI. You could have that task do it one widget at a time, and be invoked each time the event loop is about to block (i.e. use a zero-duration "timer" and invert control).
You should also do the maximum possible amount of work outside of the gui thread. I.e. the UI description should be read and converted to an efficient representation that encapsulates the work to be done in the main thread. This conversion has to be done asynchronously.
The simplest way to accomplish that is to encapsulate each widget's creation in a lambda that refers to some context object. Such a lambda would have the signature [...](BatchContext &ctx). The vector of those lambdas would be kept by the CreationContext object as well:
class BatchContext : public QObject {
Q_OBJECT
public:
using Op = std::function<void(CreationContext &)>;
using QObject::QObject;
// useful for Op to keep track of where things go
void push(QWidget *w) { m_stack.push_back(w); }
QWidget *pop() { return m_stack.isEmpty() ? nullptr : m_stack.takeLast(); }
QWidget *top() const { return m_stack.isEmpty() ? nullptr : m_stack.last(); }
int stackSize() const { return m_stack.size(); }
bool stackEmpty() const { return m_stack.isEmpty(); }
Q_SLOT void startExec() {
if (m_execIndex < ops.size())
m_execTimer.start(0, this);
}
template <typename F>
void addOp(F &&op) { m_ops.push_back(std::forward<F>(op)); }
...
private:
QVector<Op> m_ops;
QVector<QWidget *> m_stack;
QBasicTimer m_execTimer;
int m_execIndex = 0;
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() == m_execTimer.timerId())
if (!exec())
m_execTimer.stop();
}
/// Does a unit of work, returns true if more work is available
bool exec() {
if (m_execIndex < m_ops.size())
m_ops.at(m_execIndex++)(*this);
return m_execIndex < ops.size();
}
};
After the context is created asynchronously, it can be passed to the main thread where you can then invoke startExec() and the widgets will be created one-at-a-time. The stack is but an example of how you might implement one aspect of widget creation process - the tracking of what widget is the "current parent".

How to paint sequential image in efficient way in QQuickPaintedItem

For some reason, I needs to wrap opencv VideoCapture in a class which will be used in Qt Quick.
There are two classes, one is Camera, other is CameraView. CameraView inheritd from QQuickPaintedItem.
Camera class will get image periodically. It achieved by QObject::startTimer(int interval). (e.g. If fps of the webcam is 30, the timer interval is 1000 / 30 - 8, 8 is deviation of time). Once Camera has get image, it notifies CameraView to repaint by calling CameraView::Update().
And in CameraView::paint(QPainter *), CameraView will get an copy of image from Camera class and paints this image by call QPainter::drawImage(...).
I got some problems in process of coding:
I try to replace time event with QThread to get image from camera periodically. When I call CameraView::Update() in QThread, CameraView doesn't repaint. What is the problem?
In my laptop, when I make the CameraView painting the image in fullscreen, I found one python program slow down. Is another way to paint image with lower cost and efficient?
How can I efficiently update QML item based on QQuickPaintedItem C++
class? I delegated some preprocesssing to dedicated thread instead of
a timer on UI thread and it does not update the image in QML UI anymore.
It is a mandatory to trigger UI update from UI thread in Qt including QML. Make that CameraView to expose public slot updateImage.
class CameraView : public QQuickPaintedItem
{
Q_OBJECT
Q_DISABLE_COPY(CameraView)
public:
CameraView(QQuickItem* parent = nullptr);
public slots:
void updateImage(const QImage&);
protected:
QImage m_image;
};
CameraView should implement updateImage and paint like that:
void CameraView::updateImage(const QImage& image)
{
m_imageThumb = image; // does shallow copy of image data
update(); // triggers actual update
}
void CameraView::paint(QPainter* painter)
{
painter->drawImage(this->boundingRect(), m_image);
}
ClassOpenCvOnWorkerThread should start its worker thread and expose signalUiUpdate:
OpenCvOnWorkerThread::OpenCvOnWorkerThread()
{
this->moveToThread(&m_workerThread);
// the below will allow communication between threads
connect(this, SIGNAL(signalUiUpdate(QImage)), m_cameraView, SLOT(updateImage(QImage)));
m_workerThread.start();
}
void OpenCvOnWorkerThread::cvRead()
{
QImage image;
// OpenCV details available in your code
// cv::read
// make QImage from frame
// deliver QImage to another thread
emit signalUiUpdate(image);
}
UPDATE: In my own code for similar QML output from "camera" thread I also take care of handling the UI thread stall when it is unable to process video frames so the signal sender knows when not to post video frames. But that worth another question. Or this whole example can be reimplemented without signal and slot but with condition variable.

Qt Modeless Dialog Destruction

From what I understand to make dialog Modeless you have to allocate it on the heap. By Doing something like this:
MyDialog* dlg = new MyDialog(this);
dlg->show();
dlg->raise();
Since exec() ignores Modal Property. However now there is a memory leak since nothing deallocates memory pointed to by dlg pointer until the application is closed. I found one solution here http://tinf2.vub.ac.be/~dvermeir/manuals/KDE20Development-html/ch08lev1sec3.html#ch08list09 at the end of the page and was wondering whether there was a less cumbersome way having Modeless dialog.
You can use the attribute Qt::WA_DeleteOnClose to destroy the window when it is closed/hidden, and QWeakPointer (or QPointer) with a static variable to track the existence of the window inside the slot/function which opens it:
void MyWindow::openDialog() {
static QWeakPointer<MyDialog> dlg_;
if (!dlg_)
dlg_ = new MyDialog(this);
MyDialog *dlg = dlg_.data();
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
dlg->raise();
dlg->activateWindow();
}
I'd schedule it for deletion at the time it's work is finished by using deleteLater:
void MyDialog::MyDialog(QWidget *parent) {
// ...
connect(this, SIGNAL(finished(int)), SLOT(deleteLater)));
}
This approach will preclude you from examining it after the finished signal has been emitted (unless you can guarantee that any accesses happen before everything gets back to the event loop when the deletion is actually performed).
Personally, I would choose between either using
dlg->setAttribute(Qt::WA_DeleteOnClose);
or making the dialog a -dynamically allocated- member i.e. creating it only once:
// constructor
: dialog_(0)
// member function
{
if (! dialog_)
dialog_ = new MyDialog(this);
dialog_->show();
dialog_->raise();
}
This way the dialog is deleted when the parent dies, and only needs to be constructed once.

Displaying a second form in Qt

I know this question has been asked a few time, (http://stackoverflow.com/questions/4436511/display-a-form-in-qt)
I am trying to open an existing form in my Qt C++ project.
it needs to be a subform instead of QDialog box.
both forms have a .ui, .h and .cpp file with them.
in my mwindowtest.cpp I have
//this is used to handle the button click to open the new form
connect(btnConnect, SIGNAL(click()), this, SLOT(openNewWindow()));
for function is:
void mWindowTest::openNewWindow(){
mForm = new dialog (this);
mForm->show();
}
in my mwindowtest.cpp I have:
#include <dialog.h> //second form
class dialog;
I'm now getting the error mForm was not declared in this scope.
but I am not sure what to declare mForm as in my Header file.
any tips would be greatly appreciated.
Thanks
In your mywindowtest.hpp you have to declare the pointer first:
// mytestwindow.hpp
// ...
private:
dialog* mForm;
// ...
// mytestwindow.cpp
void mWindowTest::openNewWindow()
{
mForm = new dialog (this);
form->show();
}
Or you declare it directly in your cpp, but then it is no member and only known in openNewWindow().
void mWindowTest::openNewWindow()
{
dialog* form = new dialog (this);
form->show();
}
When you work with Qt you should know the basics of C++. This example is one of those basics. Use Google and read some stuff about pointer tutorials and dynamic memory allocation.
Hope that helps. :)
In your example you will have memory leak since each time button btnConnect is clicked you will reallocate memory for your form, without deleting the previous first.
Concerning your problem, we need to know how is declare dialog in dialog.h to be able to really help you.
In your mywindowtest.cpp you have included the file and redefined the class. Try to put
class dialog
in your hpp file and
#include <dialog.h>
in your cpp file.
Hope that helps
Edit:
In your slot:
delete mForm;
mForm = new dialog();
dialog->show();
It's the minimum to avoid memory leaks; And don't forget to delete mForm in MyWindowTest destructor too if not null;

Resources