QT用多线程实现视频转字符动画代码项目
时间: 2024-02-13 17:01:04 浏览: 70
以下是一个简单的视频转字符动画的 QT 项目示例,其中使用多线程实现视频帧转换为字符图像的过程:
mainwindow.h 文件:
```cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QTimer>
#include <QVector>
namespace Ui {
class MainWindow;
}
class VideoConverter : public QThread
{
Q_OBJECT
public:
explicit VideoConverter(QObject *parent = nullptr);
void setFileName(const QString& fileName);
signals:
void frameConverted(const QString& frame);
protected:
void run() override;
private:
QString m_fileName;
QMutex m_mutex;
QWaitCondition m_waitCond;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_selectButton_clicked();
void on_startButton_clicked();
void on_stopButton_clicked();
void on_frameConverted(const QString& frame);
void on_timer_timeout();
private:
Ui::MainWindow *ui;
VideoConverter m_converter;
QVector<QString> m_frames;
QMutex m_mutex;
QWaitCondition m_waitCond;
QTimer m_timer;
};
#endif // MAINWINDOW_H
```
mainwindow.cpp 文件:
```cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <opencv2/opencv.hpp>
VideoConverter::VideoConverter(QObject *parent) : QThread(parent)
{
}
void VideoConverter::setFileName(const QString &fileName)
{
m_fileName = fileName;
}
void VideoConverter::run()
{
cv::VideoCapture cap(m_fileName.toStdString());
if (!cap.isOpened()) {
qDebug() << "Cannot open video file";
return;
}
cv::Mat frame;
while (cap.read(frame)) {
// Convert video frame to ASCII art
QString ascii = "";
for (int y = 0; y < frame.rows; y += 5) {
for (int x = 0; x < frame.cols; x += 2) {
cv::Vec3b color = frame.at<cv::Vec3b>(y, x);
int gray = 0.2989 * color[2] + 0.5870 * color[1] + 0.1140 * color[0];
ascii += QString::fromUtf8(" .-:=+*#%@")[gray / 25];
}
ascii += "\n";
}
// Emit signal to notify main thread that a frame has been converted
m_mutex.lock();
m_waitCond.wait(&m_mutex);
emit frameConverted(ascii);
m_mutex.unlock();
}
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&m_converter, &VideoConverter::frameConverted, this, &MainWindow::on_frameConverted);
connect(&m_timer, &QTimer::timeout, this, &MainWindow::on_timer_timeout);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_selectButton_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this, "Select Video File", "", "Video Files (*.avi *.mp4)");
if (!fileName.isEmpty()) {
ui->fileNameEdit->setText(fileName);
}
}
void MainWindow::on_startButton_clicked()
{
QString fileName = ui->fileNameEdit->text();
if (fileName.isEmpty()) {
return;
}
m_converter.setFileName(fileName);
m_converter.start();
m_timer.start(100); // Show frames every 100 ms
}
void MainWindow::on_stopButton_clicked()
{
m_converter.terminate();
m_converter.wait();
m_timer.stop();
ui->frameLabel->clear();
m_frames.clear();
}
void MainWindow::on_frameConverted(const QString &frame)
{
m_mutex.lock();
m_frames.append(frame);
m_waitCond.wakeAll();
m_mutex.unlock();
}
void MainWindow::on_timer_timeout()
{
if (!m_frames.isEmpty()) {
ui->frameLabel->setText(m_frames.takeFirst());
}
}
```
在该示例中,VideoConverter 类继承自 QThread,并重写了 run() 函数,用于处理视频帧的转换工作。具体地,run() 函数中使用了 OpenCV 库读取视频文件,并将每一帧转换为 ASCII 码表示的字符图像。转换后的字符图像通过信号 frameConverted 发送给主线程。在主线程中,使用 QVector 容器存储转换好的字符图像,并使用 QTimer 控制字符图像的展示顺序。同时,在主线程中通过连接信号和槽的方式,将 VideoConverter 的 frameConverted 信号与 MainWindow 的 on_frameConverted 槽函数连接起来,以便在接收到转换好的字符图像时更新界面。
阅读全文