我使用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();
}
网络摄像头正确打开并且正常工作,但我看到一个白色的窗口,而不是捕获的帧,正如您在此图像中看到的
如果我取消注释:namedWindow (..), imshow(..), if(waitKey(..)
,它可以工作(我看到两个窗口具有相同的图像),但我用OpenCV显示捕获的帧,这是我想要避免的。
我的问题是:我错了什么?我不知道,从Mat到Qimage的转换是错误的?? 或者,我不能仅使用Qt显示捕获的帧?
谢谢!
答案 0 :(得分: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 :(得分: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()));
答案 2 :(得分:0)
如果您要设置在Label中启动Capture Video,则必须在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;