Hi,
QTimer sollte Abhilfe schaffen. Ich kann aber nur wärmstens empfehlen, statt einem QLabel ein QGLWidget zum Darstellen des Cam-Streams zu verwenden, weil das wesentlich schneller geht. Hier unten siehst Du die Implementierung als "CVWidget". Das Widget benutzt OpenGL und rendert das OpenCV-Image als Textur auf eine OpenGL-Fläche. Wenn Du den Code änders, kannst Du sogar OpenCV-Videos auf einen Würfel projizieren und den Frei drehen und es performt anstandslos.
Einfach den Header einbinden und ein CVWidget erstellen. Dann kannst Du einfach die Methode sendImage(CV::Mat) wiederholt aufrufen und so ein Video ablaufen lassen. Übrigens ist CV::Mat und IPLImage kompatibel und konvertierbar, allerding ist IPLImage und alle Methoden die mit cv* beginnen deprecated, also veraltet. CV:Mat und die MEthoden in dem Beispiel unten sind OpenCV 2.0+ Code und objektorientiert, während Dein Code c-Syntax verwendet. Ich würde mich davon trennen.
Hier CVWidget.h
Code: Alles auswählen
#include "cvwidget.cpp"
#include <glu.h>
CVWidget::CVWidget() : QGLWidget(QGLFormat(QGL::SampleBuffers)) {
setMinimumSize(320,240);
this->display_mode = 0;
}
void CVWidget::initializeGL() {
glClearColor(0.0f,0.0f,0.0f,1.0f);
}
void CVWidget::paintGL() {
glClear (GL_COLOR_BUFFER_BIT);
glClearColor (0.0,0.0,0.0,1.0);
if (!qframe.isNull()) { // glDrawPixels mode selected ...
qframe = qframe.scaled(this->size(), Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
if (this->display_mode == 0) glDrawPixels(qframe.width(),qframe.height(), GL_RGBA, GL_UNSIGNED_BYTE, qframe.bits());
else { // 2D texture mapping mode selected ...
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,qframe.width(),qframe.height(),0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D( GL_TEXTURE_2D, 0, 4, qframe.width(), qframe.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, qframe.bits() );
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex2f(0,qframe.height());
glTexCoord2f(0,1); glVertex2f(0,0);
glTexCoord2f(1,1); glVertex2f(qframe.width(),0);
glTexCoord2f(1,0); glVertex2f(qframe.width(),qframe.height());
glEnd();
glDisable(GL_TEXTURE_2D);
}
glFlush();
}
}
void CVWidget::resizeGL(int w, int h) {
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
glMatrixMode (GL_MODELVIEW);
// qDebug() << "Resizing...";
}
void CVWidget::sendImage(Mat* img) {
if (img->channels() > 1)
qframe = QImage((const unsigned char*)(img->data), img->cols, img->rows, img->step, QImage::Format_RGB888).rgbSwapped();
else
qframe = QImage((const unsigned char*)(img->data), img->cols, img->rows, img->step, QImage::Format_Indexed8).rgbSwapped();
qframe = QGLWidget::convertToGLFormat(qframe);
this->updateGL();
}
void CVWidget::setDisplayMode(int mode) {
this->display_mode = mode;
}
Und CVWidget.h
Code: Alles auswählen
#ifndef CVWIDGET_H
#define CVWIDGET_H
#include <QGLWidget>
#include <QtOpenGL>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
class CVWidget : public QGLWidget
{
Q_OBJECT
public:
CVWidget();
void setDisplayMode(int mode);
void sendImage(Mat *img);
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
private:
QImage qframe;
int display_mode;
};
#endif // CVWIDGET_H
Und hier siehst Du, wie man es verwendet. Die MainWindow.cpp hat Methoden um die Webcam zu starten, zu stoppen und zeigt wie man Frames als Stream abgreift mit QTimer.
MainWindow.cpp
Code: Alles auswählen
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
cvWidget = new CVWidget();
this->ui->frame_main_View->layout()->addWidget(cvWidget);
}
void MainWindow::startCam() {
if (capture.isOpened()) { capture.release(); }
capture = VideoCapture(this->ui->comboBox_Cam->currentText().toInt());
this->processCam();
}
void MainWindow::stopCam() {
this->capture.release();
ui->statusBar->showMessage("Stopped");
}
void MainWindow::processCam() {
if (this->capture.isOpened()) {
timer.restart();
Mat frame;
capture >> frame;
processFrame(frame);
if (frame.data) {
ui->statusBar->showMessage("Running....");
QTimer::singleShot(25, this, SLOT(processCam()));
}
}
return;
}
void MainWindow::processFrame(Mat& img) {
// process your frame here
Mat gray;
/*/ simple example how to change brightness and contrast
const double brightness_gain = 0.5;
const double contrast_gain = 0.6;
Mat white(img.size(), CV_8UC3);
white=Scalar(255,255,255);
addWeighted(img, contrast_gain, white, 1,-128 + brightness_gain, img);*/
cvWidget->sendImage(&img);
}
MainWindow::~MainWindow() {
if (capture.isOpened()) { capture.release(); }
delete ui;
}
void MainWindow::on_actionStart_triggered()
{
startCam();
}
void MainWindow::on_actionStop_triggered()
{
stopCam();
}
Und hier MainWindow.h
Code: Alles auswählen
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTime>
#include "cvwidget.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void startCam();
void stopCam();
void processCam();
void on_actionStart_triggered();
void on_actionStop_triggered();
private:
Ui::MainWindow *ui;
void processFrame(Mat& img);
CVWidget *cvWidget;
VideoCapture capture;
QTime timer;
};
#endif // MAINWINDOW_H
Der Include "glu.h" in der CVWidget ist erst seit Qt 4.8 notwendig. Bei 4.7.x kann er einfach raus.