HorizontalSlider verschieben - Programm hängt sich auf

Verschiedenes zu Qt
Antworten
Saul
Beiträge: 29
Registriert: 17. Juni 2011 09:41

HorizontalSlider verschieben - Programm hängt sich auf

Beitrag von Saul » 11. Januar 2012 19:24

Hallo Community,
ich habe ein Problem mit dem horizontalSlider. Es soll ein Wert "Value" variierbar sein, mittels dessen Hilfe ein Webcamstream beeinflusst werden kann.
Die grobe Struktur sieht so aus:

Code: Alles auswählen

...
QImage image;
while(true)
{
     image = webcamStream;
     value = ui.horizontalSlider->value();

     changeStream(value);

     ui.label->setPixmap(QPixmap::fromImage(image));
     ui.label->update();
}
Prinzipiell funktioniert es so wie es soll. Doch wenn der Slider verschoben wird, bricht das Programm manchmal ab. Sieht so aus, als wenn der Fehler nur auftritt, wenn der Slider zu langsam bewegt wird. Kann es sein, dass das Programm nicht auf den Wert (Value) zugreifen kann, wenn der Slider verschoben wird? Bin ziemlich Ratlos, was die Ursache des Problems angeht =(
Hoffe ihr könnt mir helfen.
Viele Grüße,
Saul
Zuletzt geändert von Saul am 12. Januar 2012 15:15, insgesamt 1-mal geändert.

franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: HorizontalSlider verschieben

Beitrag von franzf » 11. Januar 2012 19:55

Definitiv zu wenig Code (und so recht schlau werd ich auch nicht draus).
Meine Vermutung: der gepostete Schnippsel läuft in nem anderen Thread.

Saul
Beiträge: 29
Registriert: 17. Juni 2011 09:41

Re: HorizontalSlider verschieben

Beitrag von Saul » 11. Januar 2012 21:41

Ja, ich weiß =) Normalerweise regelt man die Sache über Threads, ich bin aber nicht so der Qt Profi und habe eine schnelle und einfache Variante zur Realisierung gesucht.
OK, hoffe der Code ist dennoch einigermaßen nachvollziehbar. Ich nutze zusätzlich OpenCV. Das eigenartige ist, das alles glatt läuft wenn ich die Funktion cvFindStereoCorrespondenceBM auskommentiere. Sobald die Funktion eingebunden ist, bricht das Programm ab beim verschieben des Sliders.

main.cpp

Code: Alles auswählen

#include "prog.h"
#include <QtGui/QApplication>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	Prog w;
	w.show();
	return a.exec();
}
prog.h

Code: Alles auswählen

#ifndef PROG_H
#define PROG_H

#include <QtGui/QMainWindow>
#include "ui_prog.h"
#include "cv.h"
#include "highgui.h"

class Prog : public QMainWindow
{
	Q_OBJECT

public:
	Prog(QWidget *parent = 0, Qt::WFlags flags = 0);
	~Prog();

private:
	Ui::ProgClass ui;
	IplImage *image;
	IplImage *image2;
	CvCapture *capture;
	CvCapture *capture2;

private slots:
	void webcam();
	void changeValue();
};

#endif // PROG_H
prog.cpp

Code: Alles auswählen

#include "prog.h"

Prog::Prog(QWidget *parent, Qt::WFlags flags)
	: QMainWindow(parent, flags)
{
	ui.setupUi(this);

	connect(ui.horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(changeValue()));
}

Prog::~Prog()
{

}

void Prog::changeValue()
{
											// label zeigt den Kamera Output
	ui.label_2->setNum(ui.horizontalSlider->value()); 	// label_2 zeigt den Wert
}

void Prog::webcam()
{
	capture = cvCaptureFromCAM(0);
	capture2 = cvCaptureFromCAM(1);
	CvStereoBMState *BMState = cvCreateStereoBMState();

	while(true)
	{
		image = cvQueryFrame(capture);
		image2 = cvQueryFrame(capture2);

		assert(BMState != 0);
		BMState->preFilterSize = ui.horizontalSlider->value();

		cvFindStereoCorrespondenceBM(image, image2, ..., BMState);

		cvCvtColor(image, image, CV_BGR2RGB);
		QImage qimg((const uchar *)image->imageData, image->width, image->height, QImage::Format_RGB888);
		ui.label->setPixmap(QPixmap::fromImage(qimg));
		ui.label->update();
		
		QCoreApplication::processEvents();
	}

	cvReleaseCapture(&capture);
	cvReleaseCapture(&capture2);
	cvReleaseImage(&image);
	cvReleaseImage(&image2);
}

Saul
Beiträge: 29
Registriert: 17. Juni 2011 09:41

Re: HorizontalSlider verschieben - Programm hängt sich auf

Beitrag von Saul » 14. Januar 2012 20:30

Gibt es denn eine Möglichkeit die while Schleife zu unterbrechen, bis die Positionierung des Sliders abgeschlossen ist?

solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: HorizontalSlider verschieben - Programm hängt sich auf

Beitrag von solarix » 19. Januar 2012 10:15

Wozu die while-Schleife? Einfach mittels QTimer ein periodischer Update implementieren...

hth..

QtGuy
Beiträge: 8
Registriert: 21. Februar 2012 14:53

Re: HorizontalSlider verschieben - Programm hängt sich auf

Beitrag von QtGuy » 23. Februar 2012 14:10

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.

Antworten