? ? ? Qt中的QLabel控件用于顯示文本或圖像,不提供用戶交互功能。以下測試代碼用于從內置攝像頭獲取圖像并實時顯示:
? ? ? Widgets_Test.h:
class Widgets_Test : public QMainWindow
{Q_OBJECTpublic: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:
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",關閉攝像頭。
? ? ? 執行結果如下圖所示:
? ? ? GitHub:https://github.com/fengbingchun/Qt_Test