2016-12-27 51 views
0

我有一個圖像採集線程,它是在使用Visual Studio 2015編譯的64位Qt 5.6.0應用程序中每次抓取時更新GUI。除非用戶不調整或移動GUI窗口,應用程序工作正常。但如果窗口被移動或調整大小,它會隨機崩潰。代碼總結如下。第二個線程的快速更新GUI窗口通過調整窗口大小或移動窗口而崩潰

根據調試信息,碰撞發生是因爲QImage::convertToFormat_helper中的訪問衝突任何人都知道爲什麼會發生這種情況以及如何修復?

初始化: `

auto thread = new KinectThread(); 
connect(thread,SIGNAL(OnRgbImage(QImage)),this,SLOT(rgbImageReady(QImage))); 
thread->start(); 

`

工作線程: `

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更新:

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(); 
    } 
} 
+0

什麼行給你錯誤? –

+0

不確定,但可能發生這種情況的原因是,圖像顯示速度遠遠低於獲取圖像和很多圖像對象的隊列?嘗試用一些計數器或其他方法來檢查。或'kinect-> getRgb();'是慢操作?無論如何,將QImage對象發送到信號上並不是一個好主意,最好是使用一些通用的指針和線程同步。 – johngull

回答

2

QImage建設者採取uchar *data的圖像數據不創建數據的副本,這意味着它們需要uchar *緩衝至少只要QImage的情況下生活。

此外,QImageimplicitly shared,這意味着複製QImage也不復製圖像數據,但仍然訪問原始緩衝區。

這樣很好地複製圖像並通過信號傳遞快。但這也意味着來自kinect->getRgb()調用的圖像數據必須存在,直到信號事件已經通過事件隊列傳遞到MainWindow::rgbImageReady並且直到完成使用數據爲止。這也意味着,如果Kinect類更改已傳遞到rgbImageReady的現有緩衝區,而您使用QPixmap::fromImage(image)從圖像創建了一個像素圖,則會變得很糟糕。如果Kinect類在上一個緩衝區結束rgbImageReady之前刪除了現有緩衝區(例如,因爲它分配了更大的緩衝區,因爲窗口大小已更改),您將會遇到訪問衝突。

+0

如果'kinect-> getRgb()'創建了一個緩衝區的副本,那麼你是在哪裏刪除它?'QImage'沒有取得你傳遞給構造函數的緩衝區的所有權。 (儘管你可以傳遞一個清理函數,當最後一個'QImage'拷貝被銷燬時刪除緩衝區,但它看起來不像你現在這樣做)。 – E4z9

+0

QImage或緩衝區被破壞。但通過考慮你的提示,即QImage並不擁有所有權,我確定在第二個線程中QImage數據的破壞是不成熟的。因此,將QImage的深層副本傳遞給信號可以解決問題。 '發出OnRgbImage(imgIn.copy());'謝謝你一起考慮這個問題。 –

0

通過考慮@ E4Z9暗示QImage沒有取得其數據所有權,顯然在第二個線程中QImage數據的破壞是不成熟的。因此,將QImage的深層副本傳遞給信號可以解決問題。

emit OnRgbImage(imgIn.copy());

因此,它是將其用不相關的調整大小和窗口的移動露出的未成熟物體破壞的問題。