Qt C ++ - 多线程视频帧变换 [英] Qt C++ - multithread video frame transformation

查看:817
本文介绍了Qt C ++ - 多线程视频帧变换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须编写一个应用程序,显示一个加载的视频在一个窗口小部件,拉框架,转换他们,并把这些在另一个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)。



如果我删除 Ui :: MainWindow ui; 在// 1,它告诉我 ui未在此范围中声明



如何从一个单独的线程访问和修改Mainwindow中的ui元素?



编辑:
好​​吧,一个更实用的想法。我将简单地从GUI线程传递视频文件URL到工作线程,执行所有操作,并传递2个处理的图像(每个视频帧),每个QGraphicsView一个。一个正常,有点标记,一个转换。我现在知道如何将工作线程传递给GUI线程,但是如何从GUI传递QString到工作线程,我该如何收到呢?

解决方案

简短的答案:你不能。



Qt帮助:线程基础:


GUI线程和工作线程



如前所述,每个程序在启动时都有一个线程。这个
线程被称为主线程(在
Qt应用程序中也称为GUI线程)。 Qt GUI必须在这个线程中运行。所有窗口小部件和
几个相关的类,例如QPixmap,不能在辅助
线程中工作。辅助线程通常被称为worker
线程,因为它用于从主
线程卸载处理工作。


你可以做什么:你可以在主线程中使用ui,通过 QImage (或其他数据,与ui无关)

UPDATE 我如何做到这一点?我的意思是,传递QImage在线程之间来回显示两个视频同时和持续? - Petersaber



我不是视频专家,但我可以给你暗示。让我们假设你有一个 Widget ,它接受 QImage 并显示它。 处理器是一个对象,它处理图像并将其返回到gui线程。 处理器应源自 QObject



Widget.h

  class Widget:public QWidget,private Ui :: Widget 
{
Q_OBJECT
public:
explicit Widget(QWidget * parent = 0);
void enqueueImage(const QImage& img);

信号:
void process(const QImage& img);

private:
void showNextImage();

私有插槽:
void onProcessed(const QImage& img);

private:
QThread * mThread;
QScopedPointer<处理器> 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(已处理(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);
}


I have to write an app that displays a loaded video in one Widget, pulls frames, transforms them, and puts these in another Widget, preferably QGraphicsView, and hopefully synchronized. It's pretty important for them to be synchronized.

I've written a test thread, and the main meat is this:

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;
    }
    }
}

it's not what I need, but it's just a test. If I put text there, it goes through just fine, keeps displaying. But these images... immediatly a crash when the first ui line is reached ( //2 ). I have no doubt this way of doing things is really bad.

If I remove Ui::MainWindow ui; at //1 , it tells me that ui is not declared in this scope .

So my question is, how can I access and modify ui elements in the Mainwindow from a separate thread?

edit: Okay, a more practical idea. I'm going to simply pass video file URL from the GUI thread to the worker thread, do all the operations there and pass 2 processed images back (for each video frame), one for each QGraphicsView. One normal, with points marked, and one transformed. I now know how to pass things from worker thread to GUI thread, but how do I pass QString from GUI to the worker thread, and how do I receive it?

解决方案

Short answer: you can't.

Qt Help: Threading Basics:

GUI Thread and Worker Thread

As mentioned, each program has one thread when it is started. This thread is called the "main thread" (also known as the "GUI thread" in Qt applications). The Qt GUI must run in this thread. All widgets and several related classes, for example QPixmap, don't work in secondary threads. A secondary thread is commonly referred to as a "worker thread" because it is used to offload processing work from the main thread.

What you can do: you can work with ui in main thread, pass QImage (or other data, not related with ui) into separate thread through signal/slot system, process it there and pass it back.

UPDATE (how can I do that? I mean, pass QImage back and forth between threads and display both videos simultaneously and continually? – Petersaber)

I'm not a video expert, but I can give you I hint. Let's assume, you have a Widget, which accepts QImage and have to show it. Processor is an object, which processes an image and returns it back to gui thread. Processor should be derived from 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);
}

这篇关于Qt C ++ - 多线程视频帧变换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆