【问题标题】:show webcam stream from OpenCV with Qt使用 Qt 显示来自 OpenCV 的网络摄像头流
【发布时间】:2026-01-28 04:10:02
【问题描述】:

所以我可以通过这个简单的代码使用带有 imshow 的 OpenCV 查看我的网络摄像头流

int main(int, char**)
{
    VideoCapture cap(0); 
    Mat edges;
    namedWindow("webcam", 1);
    while (true)
    {
        Mat frame;
        cap >> frame; 
        imshow("webcam", frame);
        if (waitKey(30) >= 0) break;
    }
    return 0;
}

现在我想要在 QT 上的 Widget 中的 QImage 中显示来自 OpenCV 的图像 这是从 cv::Mat 到 QImage 的转换

QImage Mat2QImage(cv::Mat const& src)
{
    cv::Mat temp; 
    cvtColor(src, temp, CV_BGR2RGB); 
    QImage dest((const uchar *)temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
    dest.bits(); 
    // of QImage::QImage ( const uchar * data, int width, int height, Format format )
    return dest;
}

以及在 QT 中使用 QImage 显示图像的小代码

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QImage myImage;
    myImage.load("a.png");
    QLabel myLabel;
    myLabel.setPixmap(QPixmap::fromImage(myImage));
    myLabel.show();
    return a.exec();
}

我试图以这种方式组合它们,但没有运气

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    VideoCapture cap(0);

    QImage myImage;
    QLabel myLabel;
    while (true)
    {
        Mat frame;
        cap >> frame; // get a new frame from camera

        myImage = Mat2QImage(frame);
        myLabel.setPixmap(QPixmap::fromImage(myImage));
    }


    myLabel.show();

    return a.exec();

【问题讨论】:

  • 这不是它的工作方式。你进入一个无限循环:你怎么能看到任何东西,因为myLabel.show()循环之后?
  • 从设备流式传输以及对图像数据的任何处理都应在单独的线程中完成。如果你迟早要做你正在做的事情,你将不得不重写你的代码。查看我制作的关于 OpenCV 与 Qt 集成的几个视频:youtube.com/… 请注意,您也可以使用自定义的QThread,并且您不必坚持我在教程中使用的 Worker 模式。

标签: c++ qt opencv opencv3.0


【解决方案1】:

您必须创建一个继承自 QMainWindowWindowQTimer。在构造函数中,将计时器连接到Window 方法。您将把您的 openCV 代码放入这个超时方法中,每 X 毫秒调用一次:

class Window : public QMainWindow
{
    Q_OBJECT
    QTimer _timer;

    private slots:
    void on_timeout()
    {
        // put your opencv code in it
    }
    public:
    Window() :
        QMainWindow(), _timer(this)
    {
        connect(&_timer, SIGNAL(timeout()), this, SLOT(on_timeout()));
        // populate your window with images, labels, etc. here
        _timer.start(10 /*call the timer every 10 ms*/);
    }
};

然后在主窗口中显示您的窗口:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Window win;
    win.show();
    return a.exec();
}

如果你使用Qt creator,用Qt开发更简单:想想吧。

【讨论】:

    【解决方案2】:

    感谢@Boiethios 的回复 这是我放在 mainwindow.cpp 中的最终代码

        MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    class Window : public QMainWindow
    {
        Q_OBJECT
            QTimer _timer;
    
        private slots:
        void on_timeout()
        {
            VideoCapture cap(0);
    
            Mat edges;
            namedWindow("edges", 1);
            while (true)
            {
                Mat frame;
                cap >> frame;
                myImage = Mat2QImage(frame);
                myLabel.setPixmap(QPixmap::fromImage(myImage));
                myLabel.show();
            }
        }
    public:
        QImage myImage;
        QLabel myLabel;
        Window() :
            QMainWindow(), _timer(this)
        {
            connect(&_timer, SIGNAL(timeout()), this, SLOT(on_timeout()));
            // populate your window with images, labels, etc. here
            _timer.start(10 /*call the timer every 10 ms*/);
        }
    };
    

    它编译和执行正常,但什么都没有发生,只是一个空白窗口

    【讨论】:

    • 在这里用图像、标签等填充您的窗口 意思是:将您的图像放在窗口中。否则你不会看到它。与设计师一起做,并通过ui->the_image_name 访问它。
    • 只是一个旁注:请不要发布您确定它不起作用的答案。如果您想显示一些代码,请编辑您的问题并在那里添加代码。否则 1)该问题缺少您在新添加的代码中提供的基本信息,并且 2)人们会查看该问题,然后查看答案,他们会摸不着头脑,想知道为什么您发布了一些您知道它不起作用的东西.