1
votes

I am creating a simple application in Qt for learning purpose. I want to display the images captured by the webcam to be displayed in a Graphicsview of my User Interface (ui).

Functionality: When the Start button is pressed, the webcam frames start getting displayed in the Graphics View. When the Paused button is pressed, the webcam streaming gets paused. And finally, if the Quit button is pressed then, the whole application gets terminated.

My Approach: I want to start a Qt thread when the start button is pressed and this thread will continuously capture the webcam frames. After capturing each webcam frame, this thread will emit a signal and pass the pointer to the data of captured image, its height and its width. This signal will be connected to a slot (i.e. setGraphicsView()) of MainWindow class. The slot of MainWindow class will assign the captured webcam image to the GraphicsView of ui.

My Code:

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MainWindow *w = new MainWindow;
    w->show();

    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

//Threading
#include "thread.h"

//OpenCV
#include <opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include "opencv2/opencv.hpp"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:

    void on_StartButton_clicked();

    void on_PauseButton_clicked();

    void on_QuitButton_clicked();
    void setGraphicsView(unsigned char* ptrWebcamImg, int iw, int ih);

private:
    Ui::MainWindow *ui;
    Thread guiThread;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGraphicsPixmapItem>

using namespace cv;

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QObject::connect(ui->StartButton, SIGNAL(clicked()), &guiThread, SLOT(start()), Qt::QueuedConnection);
    //When the thread emits a signal saying it has got a new webcam frame, reflect that change in the graphicsview of ui.
    QObject::connect(&guiThread,SIGNAL(signalGotNewFrame(const unsigned char* ptrWebcamImage, int iw, int ih)),this,SLOT(setGraphicsView(const unsigned char* ptrWebcamImage, int iw, int ih)), Qt::QueuedConnection);
    QObject::connect(ui->PauseButton, SIGNAL(clicked()), &guiThread, SLOT(stopRunning()), Qt::QueuedConnection);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setGraphicsView(unsigned char *ptrWebcamImg, int iw, int ih)
{
    Mat frame(ih, iw, CV_8UC3, Scalar(0,0,255));

    //Conver the Mat frame into QImage and assign it to the GraphicsView of ui.
    QImage image( frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888 );
    QGraphicsScene* scene = new QGraphicsScene();
    QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(image));
    scene->addItem(item);
    ui->graphicsView->setScene(scene);
}

void MainWindow::on_StartButton_clicked()
{
}

void MainWindow::on_PauseButton_clicked()
{
    //guiThread.stopRunning();
}

void MainWindow::on_QuitButton_clicked()
{
    connect(ui->QuitButton,SIGNAL(released()), qApp, SLOT(quit()));
}

thread.h

#ifndef THREAD_H
#define THREAD_H

#include <QThread>

class Thread : public QThread
{
    Q_OBJECT

public slots:
    void stopRunning();
    //virtual void run();
protected:
    virtual void run();
private:
    bool isWebcamNeeded;
signals:
    void signalGotNewFrame(unsigned char* ptrFrame, int iw, int ih);

};


#endif // THREAD_H

thread.cpp

#include "thread.h"

//Qt and
#include <QGraphicsPixmapItem>
#include <iostream>

//OpenCV related
#include <opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace cv;

void Thread::run()
{
    std::cout<<"\nIn the thread"<<std::endl;
    isWebcamNeeded = true;
    cv::VideoCapture cap(0);
    Mat frame;
    unsigned char *ptrFrame;
    while(isWebcamNeeded == true) //"this->isWebcamNeeded" will become false when PauseButton will be clicked
    {
        cap >> frame;
        ptrFrame = frame.data;
        emit signalGotNewFrame(ptrFrame, frame.cols, frame.rows);
    }
}

void Thread::stopRunning()
{
    isWebcamNeeded = false;
}

Problem: I am getting the following runtime errors:

QObject::connect: No such signal Thread::signalGotNewFrame(const unsigned char* ptrWebcamImage, int iw, int ih) in ../MyCamApp/mainwindow.cpp:12
QObject::connect:  (receiver name: 'MainWindow')
1
Remove the argument names like ptrFrame, ih, iw from the connect() statementFrank Osterfeld
@FrankOsterfeld: I tried that but it didn't helpuser2756695

1 Answers

0
votes

This code has so many problems!

  1. You do not need threads here. QTimer is better and safer solution (You will do less mistakes)
  2. Sub-classing QThread is bad approach when handling threads (I won't explain why, since you should not use them).
  3. your signal is slots are badly defined, what will lead to problems with memory management.
  4. conversion method from cv::Mat to QPixmap is a bit more complicated
  5. the way you are trying to display that on QGraphicsView is completely wrong. You should read documentation how to use this part of Qt.

Bottom line there is a long way for you to make things working properly. IMO you should take couple steps back a start with something a bit simpler. For now you you have lack of skills in so many areas (3 at least) that it will be for you very painful to learn anything. Improve skill in one new area at the time.