Qt C++——多线程视频帧变换
Posted
技术标签:
【中文标题】Qt C++——多线程视频帧变换【英文标题】:Qt C++ - multithread video frame transformation 【发布时间】:2015-05-06 12:46:07 【问题描述】:我必须编写一个应用程序,在一个 Widget 中显示加载的视频,拉取帧,转换它们,然后将它们放入另一个 Widget,最好是 QGraphicsView,并希望同步。同步它们对它们来说非常重要。
我写了一个测试线程,主要的肉是这样的:
void HSV::display()
Ui::MainWindow ui; //1
int j=0;
QTimer *timer = new QTimer;
for(int i=1; i<4; i++)
QString numer = QString::number(i);
QImage imageTest(numer+".jpg");
QGraphicsPixmapItem* test = new QGraphicsPixmapItem(QPixmap::fromImage(imageTest));
QGraphicsScene* sceneHSV = new QGraphicsScene;
sceneHSV->addItem(test);
//2
ui.graphicsViewKalibracjaHSV->setScene(sceneHSV);
ui.graphicsViewKalibracjaHSV->fitInView(sceneHSV->sceneRect(),Qt::KeepAspectRatio);
ui.graphicsViewKalibracjaHSV->show();
timer->start(500);
if(i==3)
i=1;
j++;
if (j>40)
break;
这不是我需要的,但这只是一个测试。如果我把文字放在那里,它会很好地通过,继续显示。但是这些图像......当到达第一行 ui 时立即崩溃( //2 )。我毫不怀疑这种做事方式非常糟糕。
如果我在 //1 删除 Ui::MainWindow ui;
,它会告诉我 ui is not declared in this scope
。
所以我的问题是,如何从单独的线程访问和修改主窗口中的 ui 元素?
编辑: 好吧,一个更实际的想法。我将简单地将视频文件 URL 从 GUI 线程传递到工作线程,在那里执行所有操作并将 2 个处理后的图像传回(对于每个视频帧),每个 QGraphicsView 一个。一个正常的,带有标记的点,一个转换的。我现在知道如何将东西从工作线程传递到 GUI 线程,但是如何将 QString 从 GUI 传递到工作线程,以及如何接收它?
【问题讨论】:
我没有看到 ui->setupUi(this); 【参考方案1】:简短的回答:你不能。
Qt 帮助:线程基础:
GUI线程和工作线程
如前所述,每个程序在启动时都有一个线程。这 线程被称为“主线程”(在 Qt 应用程序)。 Qt GUI 必须在这个线程中运行。所有小部件和 几个相关的类,例如 QPixmap,在辅助中不起作用 线程。辅助线程通常称为“工作线程” 线程”,因为它用于从主线程中卸载处理工作 线程。
你可以做什么:你可以在主线程中使用ui,通过信号/槽系统将QImage
(或其他与ui无关的数据)传递到单独的线程中,在那里处理并传回。
更新(我该怎么做?我的意思是,在线程之间来回传递 QImage 并同时连续显示两个视频?- Petersaber)
我不是视频专家,但我可以给你一些提示。假设您有一个Widget
,它接受QImage
并且必须显示它。 Processor
是一个对象,它处理图像并将其返回给 gui 线程。 Processor
应该派生自 QObject
。
Widget.h
class Widget : public QWidget, private Ui::Widget
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
void enqueueImage(const QImage &img);
signals:
void process(const QImage &img);
private:
void showNextImage();
private slots:
void onProcessed(const QImage &img);
private:
QThread *mThread;
QScopedPointer < Processor > mProcessor;
QList < QImage > mImagesPool;
;
Widget.cpp
Widget::Widget(QWidget *parent) :
QWidget(parent)
, mThread(new QThread(this))
, mProcessor(new Processor)
setupUi(this);
mProcessor->moveToThread(mThread);
connect(this, SIGNAL(process(QImage)), mProcessor, SLOT(process(QImage)));
connect(mProcessor, SIGNAL(processed(QImage)), SLOT(onProcessed(QImage)));
void Widget::enqueueImage(const QImage &img)
mImagesPool.append(img);
showNextImage();
void Widget::showNextImage()
if (mImagesPool.isEmpty())
return;
emit process(mImagesPool.first());
void Widget::onProcessed(const QImage &img)
if (mImagesPool.isEmpty())
return;
rawImage->setPixmap(QPixmap::fromImage(mImagesPool.takeFirst()));
processedImage->setPixmap(QPixmap::fromImage(img));
showNextImage();
Processor.cpp
void Processor::process(const QImage &img)
QImage newImg = img;
// Do stuff
emit processed(newImg);
【讨论】:
这是“如何从单独的线程访问和修改主窗口中的 ui 元素?”。那为什么说他不行呢? ;-) 不,这是您可以在单独的线程中处理数据的方式。您不能实际上从其他线程访问和修改 ui 元素,您必须在主线程中完成所有这些操作。可能是我有点严格:) gui 必须在主线程中运行。但这与修改或访问 ui 元素无关。这些也只是数据。可以像通过线程边界访问任何函数/数据一样访问。 我不同意。例如,当您阅读 Qt 对QImage
的帮助时,第一行中的一行写着Note: All functions in this class are reentrant.
,例如,QWidget
没有这样的注释。同样的帮助说:If a function is not marked as thread-safe or reentrant, it should not be used from different threads. If a class is not marked as thread-safe or reentrant then a specific instance of that class should not be accessed from different threads.
这意味着 您不应该从单独的线程访问 ui 数据。
什么时候函数必须是线程安全的才能从另一个线程访问?以上是关于Qt C++——多线程视频帧变换的主要内容,如果未能解决你的问题,请参考以下文章