7

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

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

我想这样做是因为使用函数 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();
}   

网络摄像头已正确打开并且可以正常工作,但我看到的是一个白色窗口,而不是捕获的帧,正如您在这张图片中看到的那样 在此处输入图像描述

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

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

谢谢!

4

3 回答 3

9

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

 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;   
}
于 2013-02-06T13:03:21.693 回答
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信号连接到update小部件的插槽。使用 20-40 毫秒的间隔。就像您制作一个按钮来启动相机一样,将以下代码放入其clickedSLOT 中。

QTimer *timer = new QTimer;
timer->setInterval(20);
connect(timer,SIGNAL(timeout()),this,SLOT(update()));
于 2013-02-06T15:23:55.673 回答
0

如果您要在标签中开始捕获视频,那么您必须像在 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));
}

在标题中:

private slots:
    void processFrameAndUpdateGUI();
    void on_button_clicked();
private:
    cv::VideoCapture captureVideoInLabel;
于 2017-05-06T19:29:41.563 回答