首页 文章

用OpenCV打开webcamera并用QLabel - 白色窗口显示它

提问于
浏览
6

我使用OpenCV和Qt Libraries以及VS 2010在Win7 x64上工作 .

我想用OpenCV打开我的相机然后用Qt显示捕获的帧,例如使用QLabel,从Mat转换为QImage .

我想这样做是因为使用函数imshow(“camera”,image)和waitKey()减慢了流式摄像机的速度 .

这是我的代码:

int main () {
 QApplication a(argc, argv);
 QLabel myLabel;
 VideoCapture cap(0);
 //namedWindow(c"camera", 1);

 for (;;) {

    cap >> image;
        //conversion from Mat to QImage
    Mat dest;
    cvtColor(image, dest,CV_BGR2RGB);
    QImage image1= QImage((uchar*) dest.data, dest.cols, dest.rows, dest.step, QImage::Format_RGB888);

        //show Qimage using QLabel
    myLabel.setPixmap(QPixmap::fromImage(image1));
    myLabel.show();
    //imshow("camera",image);
    //if (waitKey(30)>= 0)  break;
 }
return a.exec();
}

网络摄像头打开正常并且可以工作,但是我看到一个白色的窗口,而不是捕获的帧,正如您在此图像中看到的那样
enter image description here

如果我取消注释: namedWindow (..), imshow(..), if(waitKey(..) ,它可以工作(我看到两个窗口具有相同的图像),但我用OpenCV显示捕获的帧,这是我想要避免的 .

我的问题是:我错了什么?我不知道,从Mat到Qimage的转换是错误的??或者,我不能只用Qt显示捕获的帧?

谢谢!

3 回答

  • 6

    我没有太多经验,但我可以看到这里可能出现的问题:

    for (;;) {
    
        cap >> image;
            //conversion from Mat to QImage
        Mat dest;
        cvtColor(image, dest,CV_BGR2RGB);
        QImage image1= QImage((uchar*) dest.data, dest.cols, dest.rows, dest.step, QImage::Format_RGB888);
    
            //show Qimage using QLabel
        myLabel.setPixmap(QPixmap::fromImage(image1));
        myLabel.show();
        //imshow("camera",image);
        //if (waitKey(30)>= 0)  break;
     }
    

    你是在死循环中这样做 - 这将导致你的QLabel无限更新自己,所以你可能看不到任何东西 . 此外,如果取消注释 waitKey 正在帮助您,那么这几乎意味着您正在将数据转换为 QImage ,但其他内容已被破坏 .

    请注意 a.exec() 将永远不会执行,因为您将陷入循环,但我想这足以击中概念 .

    为了不阻塞事件循环,您需要创建 QTimer 并每隔x毫秒更新一次窗口小部件:

    class VideoWindow: public QWidget
     {
        Q_OBJECT
        public:
            VideoWindow(QWidget* parent = 0): QWidget(parent), cap(0)
            {
                timer = new QTimer(this);
                connect(timer, SIGNAL(timeout()), this, SLOT(updatePicture()));
                timer->start(20);
            }
    
    
        public slots:
            void updatePicture()
            {
                cap >> image;
                //conversion from Mat to QImage
                Mat dest;
                cvtColor(image, dest,CV_BGR2RGB);
                QImage image1 = QImage((uchar*) dest.data, dest.cols, dest.rows, dest.step, QImage::Format_RGB888);
    
                //show Qimage using QLabel
                setPixmap(QPixmap::fromImage(image1));
            }
    
        private:
            QTimer * timer;
            VideoCapture cap;
    };
    
    int main(int argc, char** argv)
    {
        QApplication app(argc, argv);
        VideoWindow w;
        w.show();
    
        app.exec();
        return 0;   
    }
    
  • 1

    在要用于显示图像的窗口小部件(窗口小部件/主窗口)的 paintEvent() 中尝试此操作 .

    在窗口小部件的构造函数中打开相机:

    VideoCapture myVideo;
    myVideo.open(0);
    if(!myVideo.isOpened())
       cout<<"CANNOT OPEN CAMERA"<<endl; //or you can put some error message
    

    paintEvent() 这样做

    myVideo >> frame;
    QImage image = QImage((const unsigned char*)frame.data,frame.cols,
                   frame.rows,frame.step,QImage::Format_RGB888);
    
    QRectF target(0.0,0.0,image.width(),image.height());
    QRectF source(0.0,0.0,image.width(),image.height());
    QPainter painter(this);
    painter.drawImage(target,image,source)
    

    使用计时器,您可以将 timeout SIGNAL连接到窗口小部件的 update SLOT . 使用20-40毫秒的间隔 . 就像你按下按钮启动相机一样,将以下代码放在 clicked SLOT中 .

    QTimer *timer = new QTimer;
    timer->setInterval(20);
    connect(timer,SIGNAL(timeout()),this,SLOT(update()));
    
  • 0

    如果你设置在Label中开始捕获视频,那么你必须在CPP中编写这样的代码:这段代码对我来说非常好,我希望它也能帮到你 .

    void <Class name Here>::on_button_clicked(){
    captureVideoInLabel.open(0);
        if (captureVideoInLabel.isOpened() == false)
        {
            qDebug() << "Camera can't open";
            return;
        }
        timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, 
    SLOT(processFrameAndUpdateGUI()));
        timer->start(20);
    }
    
    void <here you need to write class name>::processFrameAndUpdateGUI()
    {
        Mat originalImage;
        captureVideoInLabel.read(originalImage);
    
        if (originalImage.empty() == true)
        {
            return;
        }
    
        QImage qOriginalImage((uchar*)originalImage.data, originalImage.cols, 
        originalImage.rows, originalImage.step, QImage::Format_RGB888);
        ui->label->setPixmap(QPixmap::fromImage(qOriginalImage));
    }
    

    在 Headers 中:

    private slots:
        void processFrameAndUpdateGUI();
        void on_button_clicked();
    private:
        cv::VideoCapture captureVideoInLabel;
    

相关问题