I have an image acquisition thread that is updating GUI per each grab in a 64-bit Qt 5.6.0 application compiled with Visual Studio 2015. Unless user does not resize or move the GUI window, the application is working fine. But if the window is moved or resized, it randomly crashes. Code summary is following.
According to debugging information, the crash happens because of access violation in QImage::convertToFormat_helper
Anybody knows why this is happening and how it can be fixed?
Initialization: `
auto thread = new KinectThread();
connect(thread,SIGNAL(OnRgbImage(QImage)),this,SLOT(rgbImageReady(QImage)));
thread->start();
`
Worker thread: `
void KinectThread::run()
{
kinect = new Kinect();
while(true)
{
auto img = kinect->getRgb();
QImage imgIn= QImage((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
emit OnRgbImage(imgIn);
QThread::msleep(20);
}
delete kinect;
}
`
GUI Update:
void MainWindow::rgbImageReady(QImage image)
{
if (!image.isNull())
{
QGraphicsView* view = ui->graphicsView;
auto width = image.width();
auto height = image.height();
m_pScene->setSceneRect(0, 0, width, height);
auto pixmap = QPixmap::fromImage(image);
m_pixmapItem->setPixmap(pixmap);
view->show();
}
}
The QImage
constructors taking uchar *data
for the image data do not create a copy of the data, meaning that they require the uchar *
buffer to live at least as long as the QImage instance.
Additionally, QImage
is implicitly shared , meaning that copying a QImage
does not copy the image data either, but still accesses the original buffer.
That is good in the way that copying the image and passing it through the signal is fast. But it also means that the image data from the kinect->getRgb()
call must live until the signal event has been passed through the event queue to MainWindow::rgbImageReady
and until this has finished using the data. It also means that if the Kinect
class changes the existing buffer that has been passed to rgbImageReady
, while you create a pixmap from the image with QPixmap::fromImage(image)
, you'll get a mess. And you'll get an access violation if the Kinect
class deletes the existing buffer (for example because it allocates a larger buffer because the window size changed) before rgbImageReady
finished with the previous buffer.
By considering @E4Z9's hint that QImage does not take ownership of its data, it was then obvious that destruction of the QImage data was immature in the second thread. Thus, passing deep copy of the QImage
into the signal fixed the problem.
emit OnRgbImage(imgIn.copy());
So it was a problem of immature object destruction which was exposed with unrelated resizing and moving of window.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.