0

I have a webcam demo with Qt and OpenCV. Basically it will show the webcam's feed, and when a button gets clicked, it starts a thread with a long (three-five seconds) thread.

The problem is that the QImage gets immediately corrupted as you can see here when I click the button, and I don't see the video feed anymore. The signals & slots work (I see the output in the console), but I cannot spot the problem here.

Can anyone help?

window::window() : QMainWindow(NULL, 0)
{
    std::cout << "constructor start" << std::endl;

    setWindowTitle("Video");

    button = new QPushButton("Long Job");
    connect(button, SIGNAL(clicked()), this, SLOT(longjob()));

    image = new QLabel();
    image->setAlignment(Qt::AlignCenter);

    layout = new QVBoxLayout();
    layout->addWidget(image);
    layout->addWidget(button);

    mainwidget = new QWidget();
    mainwidget->setLayout(layout);

    resize(800, 600);

    setCentralWidget(mainwidget);

    cap = cv::VideoCapture(0);

    timer = new QTimer();
    timer->setInterval(100);
    timer->start();
    connect(timer, SIGNAL(timeout()), this, SLOT(newframe()));

    std::cout << "constructor end" << std::endl;
}

void window::newframe()
{
    std::cout << "FRAME " << count++ << std::endl;

    cv::Mat frame;
    cap >> frame;

    image->setPixmap(QPixmap::fromImage(showImage(frame))); // converts perfectly
}

void window::longjob()
{

    std::cout << "START THREAD" << std::endl;

    w = new worker();

    connect(w, SIGNAL(resultReady(double)), this, SLOT(detected(double)));

    w->start();

    return;
}

void window::detected(double d)
{
    disconnect(w, SIGNAL(resultReady(double)), this, SLOT(detected(double)));

    std::cout << "DETECTED " << d << std::endl;

    delete w;

    frames.clear();
}

class worker : public QThread
{
    Q_OBJECT

public:

    worker();

    ~worker();

    void run() Q_DECL_OVERRIDE;

signals:
    void resultReady(double d);
};

worker::worker() : QThread()
{

}

worker::~worker()
{
    std::cout << "THREAD EXIT" << std::endl;
}

void worker::run()  
{
    std::cout << "THREAD RUN" << std::endl;

    double d = longOpenCVJob();

    emit resultReady(d);
}
senseiwa
  • 2,369
  • 3
  • 24
  • 47
  • Where is `showImage()` implementation? – karlphillip May 14 '16 at 14:57
  • Here's [an application that shows how to create a Qt window to display videos loaded with OpenCV](https://github.com/karlphillip/GraphicsProgramming/tree/master/cvVideo). Minor adjustments will be required to make it stream video from a camera. – karlphillip May 14 '16 at 15:00
  • 1
    http://stackoverflow.com/questions/17127762/cvmat-to-qimage-and-back – Evgeniy May 14 '16 at 20:09
  • Thanks @Evgeniy it was indeed the memory management! I honestly believed that QImage behaved like STL containers, erroneously. Thank you! – senseiwa May 15 '16 at 09:27

1 Answers1

0

I would use this code for showImage():

QImage window::showImage(cv::Mat mat)
{
  cv::Mat tmp;
  mat.convertTo(tmp, CV_8U);
  cvtColor(tmp, tmp, CV_BGR2RGB);
  QImage img = QImage((const unsigned char *)(tmp.data), tmp.cols, tmp.rows, tmp.step, QImage::Format_RGB888);
  return img;
}
FalseCAM
  • 55
  • 1
  • 7
  • 1
    QImage does not make deep-copy of tmp.data. So it will become invalid after tmp destruction i.e. function return. Take a look here: http://doc.qt.io/qt-5/qimage.html#QImage-3: "...The buffer must remain valid throughout the life of the QImage and all copies..." – Evgeniy May 14 '16 at 20:05