0

I am going to make a thread which recieves the image from webcam camera, using opencv and Mat type. then I convert it to QImage and send it to main thread using a signal. when I want to visualize it in a QLabel object in ui (after converting to a pixmap) I get this error:

The program has unexpectedly finished.

here is my camera class: camera.h:

#ifndef CAMERA_H
#define CAMERA_H

#include <QObject>
#include <QThread>
#include <QtCore>
#include <QtGui>

#include <opencv2/opencv.hpp>

using namespace cv;

class Camera: public QThread
{
    Q_OBJECT
public:
    Camera();

    void run();
    bool Stop = false;

signals:
    void ImgSignal(QImage*);

private:

public slots:


};

#endif // THREAD_H

camera.cpp:

#include "camera.h"
#include <iostream>

using namespace std;

Camera::Camera()
{

}

void Camera::run()
{
    VideoCapture cap;
    cap.open(0);

    while(1){

        Mat img;
        cap >> img;

        cvtColor(img,img,CV_BGR2RGB);

        QImage image = QImage((const uchar*)img.data,img.cols,img.rows,img.step,QImage::Format_RGB888);
        emit ImgSignal(&image);
        QThread::msleep(30);
    }
}

and finally my onImgSignal function that recieves the image and passes it to gui:

void MainWindow::onImgSignal(QImage *img)
{
    QPixmap *p;
    p->fromImage(*img);

    ui->label->setPixmap(*p);

}

I would be so glad if you help me. thanks!

Edit when I changed the pixmap poiner to a pixmap variable the error did not come up but the pixmap variable is null. even if i load an image separately it will be null:

QPixmap p;
p.load("mark.png");
cout << p.isNull();

ui->label->setPixmap(p);
jpnurmi
  • 5,716
  • 2
  • 21
  • 37
  • At what point are you seeing the program crash? And after how many iterations? – Monza Dec 08 '16 at 00:15
  • exactly when i am puting the pixmap into label in first iteration – Seyed Hojat Mirtajadini Dec 08 '16 at 00:18
  • Can you inspect the img and pixmap objects in the debugger to verify that it looks alright internally? Without running the code I'm guessing that your conversion is not correct. Try loading an image from disk and emitting that loaded image to prove that your emit logic is correctly handling the data. (narrows down location of problem) – Monza Dec 08 '16 at 00:29
  • Examine the value of p in your debugger when in the `onImgSignal()` method. – MrEricSir Dec 08 '16 at 01:57

1 Answers1

1

My first hunch is that some pointer to some object/memory are accidentally accessed by two different threads at the same time, creating an access violation. So by just making a COPY of the image you pass around might do the trick (so both threads arn't accessing the pixel data of the same image at the same time). Here are some other things you can do to address that:

First, the threads implementation in Qt is a bit unconventional. For example, it is not considered best practice to extend the QThread class like you have done, as the QThread instance will NOT live in the new OS level thread. Yes! It's true. This leads to many sources of confusion that in turn lead to bugs. To read the official unofficial guide on how to do threads correctly in Qt, please look at this excellent article. Short summary: QThread class will act as a "management" class living in the execution thread where you instantiated it, so first tip is to learn this, and use the QThread class as intended.

Second, Qt is supposed to guess during signal time when the source and destination are in same thread or not, however I have found that it sometimes, just for the peace of mind, pays to be specific about how signals will be passed. That is why my code is full of this:

if(!connect(this,SIGNAL(colorChanged(QColor)),&ob,SLOT(onColorChanged(QColor)),(Qt::ConnectionType) (Qt::QueuedConnection | Qt::UniqueConnection) )) {
    qWarning()<<"ERROR: Could not connect "<<ob.objectName();
}

Notice the last parameter to the connect call, as it specifies Qt::QueuedConnection and Qt::UniqueConnection connections. Qt::QueuedConnection means that it is "thread safe" in that it will store the signal in a thread safe FIFO. Qt::UniqueConnection just means that connecting twice will generate an error the second time instead of creating two connections (which may lead to hard-to-trace bugs).

Third, are you starting any threads without using Qt? In that case care should be taken with signals, because they might not work properly unless you are working with Qt initiated threads. I THINK the Qt::QueuedConnection trick above should be enough, but I don't know. Here is more. Oh, and if OpenCV ever decides to knowingly or unknowingly start some threads of it's own, they will count as "threads started outside Qt".

Fourth, did you run this in a debugger? At what exact point did it crash? This should be your first move, btw.

Fifth, If all else fails wrap your code in a QMutex and use QMutexLocker to ensure that there is no problems. Or you could get fancy and use some thread safe containers or some such.

PS: Please let me know how you fare!

Community
  • 1
  • 1
Mr. Developerdude
  • 9,118
  • 10
  • 57
  • 95
  • thank you mr Rolland for your detailed answer! I have tested all steps and notes above and none of them works for my case. the exact problem occurs when I put the image in gui. I mean this part of the code: ui->label->setPixmap(*p); my own geuss is that there is something wrong in generating image in the camera thread but i dont know how to fix it – Seyed Hojat Mirtajadini Dec 08 '16 at 07:11