Qt中通过QLabel实时显示图像

Qt中的QLabel控件用于显示文本或图像,不提供用户交互功能。以下测试代码用于从内置摄像头获取图像并实时显示:

Widgets_Test.h:

cpp 复制代码
class Widgets_Test : public QMainWindow
{
    Q_OBJECT

public:
    Widgets_Test(QWidget *parent = nullptr);
    ~Widgets_Test();

private slots:
    void start_capture();
    void close_caputre();
    void update_frame(const QImage& image);

private:
    void capture();

    Ui::Widgets_TestClass ui_;
    std::thread capture_thread_{};
    std::atomic<bool> is_running_{ false };
};

Widgets_Test.cpp:

cpp 复制代码
Widgets_Test::Widgets_Test(QWidget *parent)
    : QMainWindow(parent)
{
    ui_.setupUi(this);

    connect(ui_.button_close, &QPushButton::clicked, this, &Widgets_Test::close);
    connect(ui_.open_camera, &QPushButton::clicked, this, &Widgets_Test::start_capture);
    connect(ui_.close_camera, &QPushButton::clicked, this, & Widgets_Test::close_caputre);

    connect(ui_.open_camera, &QPushButton::clicked, this, [this] {
        ui_.button_close->setEnabled(false);
    });
    connect(ui_.close_camera, &QPushButton::clicked, this, [this] {
        ui_.button_close->setEnabled(true);
    });
}

Widgets_Test::~Widgets_Test()
{}

void Widgets_Test::start_capture()
{
    is_running_.store(true);
    capture_thread_ = std::thread([this] {
        this->capture();
    });
}

void Widgets_Test::capture()
{
    cv::VideoCapture cap(0);
    if (!cap.isOpened()) {
        qWarning("failed to open camera"); // QMetaObject::invokeMethod, UI操作必须在主线程中执行
        emit ui_.close_camera->clicked();
        return;
    }

    auto w1 = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
    auto h1 = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
    auto w2 = ui_.label_show->width();
    auto h2 = ui_.label_show->height();
    qDebug() << w1 << "," << h1 << "," << w2 << "," << h2;

    cv::Mat frame{}, rgb{};
    QImage image{}, img_copy{};
    while (is_running_.load()) {
        cap >> frame;
        if (frame.empty())
            continue;

        cv::cvtColor(frame, rgb, cv::COLOR_BGR2RGB);
        cv::resize(rgb, rgb, cv::Size(w2, h2));
        image = QImage(rgb.data, rgb.cols, rgb.rows, rgb.step, QImage::Format_RGB888);
        img_copy = image.copy();
        QMetaObject::invokeMethod(this, "update_frame", Qt::QueuedConnection, Q_ARG(QImage, img_copy));

        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

void Widgets_Test::update_frame(const QImage& image)
{
    ui_.label_show->setPixmap(QPixmap::fromImage(image));
}

void Widgets_Test::close_caputre()
{
    is_running_.store(false);
    if (capture_thread_.joinable())
        capture_thread_.join();
}

说明

  1. 在子线程中获取摄像头每帧数据:

(1).因为QLabel中接收数据的类型为QImage,这里需要将cv::Mat转换为QImage。

(2).通过QMetaObject::invokeMethod函数调用对象上的信号或槽函数,支持跨线程调用。这里使用此函数将子线程获取到的图像数据传给主线程上的QLabel控件。使用Qt::QueuedConnection,跨线程异步调用。

2.UI操作必须在主线程中执行

(1).主线程中通过QLabel的setPixmap函数显示图像。

3.点击"open camera",开始打开摄像头采集显示图像;点击"close camera",关闭摄像头。

执行结果如下图所示:

GitHubhttps://github.com/fengbingchun/Qt_Test

相关推荐
梦回阑珊1 年前
《QT实用小工具·十二》邮件批量发送工具
开发语言·c++·qt·学习·qwidget·qlabel
KumaNPC1 年前
QLabel文字两端对齐解决方案
qt·qlabel·两端对齐·qproxystyle
noravinsc1 年前
pyqt的qlabel样式调整办法
pyqt·qlabel