在两个不同线程之间的信号/槽调用后损坏QImage

Corrupt QImage after a signal/slot call between two different threads

本文关键字:信号 调用 QImage 损坏 之间 线程 两个      更新时间:2023-10-16

我通过信号/插槽机制发送一个QImage,在两个线程之间(后台DB线程和GUI线程)。GUI插槽接收损坏的图像(一些像素随机损坏)。我已经这样做了,从来没有任何问题。会出什么问题呢?

程序太复杂,不能在这里包括,但这里有一些相关的信息:

  1. 发送线程(DB)是一个常规的QThread,带有事件循环,运行DataBaseInterface QObject类,该类被移动到该线程
  2. 信号/槽连接在moveToThread之后完成,所以每个对象都在它的最后一个线程中。这意味着显式地使用QueuedConnection没有什么区别,因为这已经是情况了。
  3. QImage不是直接在信号/槽参数中发送的,而是在包含其他东西(三个qvector)的结构体中发送的。这个结构体是用:

    注册的
    qRegisterMetaType<MyStruct>("MyStruct");
    
  4. QImage不是使用外部缓冲区创建的,而是使用(width, height, Format)构造函数创建的。因此,图像缓冲区是内部维护的,因此隐式共享

  5. 如果我在发出信号后将图像保存到DB线程中的磁盘,这很好。如果我把它保存在槽的开始,它是损坏的。

任何想法?

谢谢!

Ok,为了使图像不损坏,您应该确保以下内容:每个包含正在发送的结构的数据必须具有复制构造函数,避免发送数据指针,如果您这样做,则确保这些数据驻留在内存堆中,这些情况下的连接类型是Qt::QueuedConnection,在建立图像上的标签您认为应该配置如下:

label->setBackgroundRole(QPalette::Base);
label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
label->setScaledContents(true);

图像或结构的插槽应该看起来像这样,在我的opencv和QT的情况下是:

void interfaz::actImagenFromVideo(cv::Mat myImage)
{
QImage image(myImage.data,myImage.cols, myImage.rows, myImage.step, QImage::Format_RGB888 );
label->setPixmap(QPixmap::fromImage(image.rgbSwapped()));
}

你的QThread的运行函数应该看起来像这样:

void THREAD::run()
{
 while(true){
 {
 QMutexLocker locker(&mutex);
 if (stopped) {
  stopped = false;
  break;
  }
  }
  cap>>videoIn;
  emit image_ready(videoIn.clone()); //the use of cv::Mat::clone() is very   important in openCV
  }
 }