QPixmap::scaled: Pixmap is a null pixmap (displaying Pixmap on the label)
-
Hello.
I've been trying to write a program that when you click on a button it captures the current frame from the webcam (something like this, but more GUI based: https://www.youtube.com/watch?v=oHFTM1XPicI), but lastly, I've come to some problems.
Whenever I run my program, activate a webcam, and then try to capture frame I get the following errors in the Application Output:QPixmap::scaled: Pixmap is a null pixmap OpenCV: terminate handler is called! The last OpenCV error is: OpenCV(4.5.2) Error: Assertion failed (!_src.empty()) in cv::cvtColor, file C:\build\master_winpack-build-win64-vc15\opencv\modules\imgproc\src\color.cpp, line 182 18:43:33: The program has unexpectedly finished.
And to be clear, I do not get any errors in Qt.
Rest of the code:
myvideocapture.h#ifndef MYVIDEOCAPTURE_H #define MYVIDEOCAPTURE_H #include <QPixmap> #include <QImage> #include <QThread> #include <opencv2/opencv.hpp> #define ID_CAMERA 0 class MyVideoCapture : public QThread { Q_OBJECT public: MyVideoCapture(QObject *parent = nullptr); QPixmap klatka(); /*QPixmap zdjecie() const { return frame3; }*/ QPixmap pixmap() const { return mPixmap; } signals: void newPixmapCaptured(); // imagen nueva ha sido capturada //void nowaklatka(); protected: void run() override; private: QPixmap mPixmap; // imagen de Qt cv::Mat mFrame; // imagen de OpenCV cv::VideoCapture mVideoCap; // capturador de video cv::Mat frame2; QPixmap frame3; //QPixmap frame4; QImage cvMatToQImage(const cv::Mat &inMat); QPixmap cvMatToQPixmap(const cv::Mat &inMat); }; #endif // MYVIDEOCAPTURE_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include "myvideocapture.h" #include "myvideocapture.cpp" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); mOpenCV_videoCapture = new MyVideoCapture(this); /*connect(mOpenCV_videoCapture, &MyVideoCapture::nowaklatka, this, [&]() { ui->label_2->setPixmap(mOpenCV_videoCapture->zdjecie().scaled(500, 500)); });*/ connect(mOpenCV_videoCapture, &MyVideoCapture::newPixmapCaptured, this, [&]() { ui->label->setPixmap(mOpenCV_videoCapture->pixmap().scaled(500, 500)); }); } MainWindow::~MainWindow() { delete ui; mOpenCV_videoCapture->terminate(); } void MainWindow::on_pushButton_clicked() { mOpenCV_videoCapture->start(QThread::HighestPriority); } void MainWindow::on_pushButton_2_clicked() { MyVideoCapture f; QPixmap frame4 = f.klatka(); ui->label_2->setPixmap(frame4.scaled(500, 500)); } /*void MyVideoCapture::klatka() { frame2 = mFrame.clone(); frame3 = cvMatToQPixmap(frame2); }*/
myvideocapture.cpp
#include "myvideocapture.h" #include "mainwindow.h" //#include "ui_mainwindow.h" #include <QDebug> MyVideoCapture::MyVideoCapture(QObject *parent) : QThread { parent } , mVideoCap { ID_CAMERA } { } void MyVideoCapture::run() { if (mVideoCap.isOpened()) { while (true) { mVideoCap >> mFrame; applyColorMap(mFrame, mFrame, cv::COLORMAP_HOT); if (!mFrame.empty()) { //cv::rectangle(mFrame, cv::Point(10, 10), cv::Point(401, 401), cv::Scalar(0, 0, 255), 1); mPixmap = cvMatToQPixmap(mFrame); emit newPixmapCaptured(); } } } } QPixmap MyVideoCapture::klatka() { //extern QPixmap frame3; //QPixmap frame4; frame2 = mFrame.clone(); frame3 = cvMatToQPixmap(frame2); return frame3; } QImage MyVideoCapture::cvMatToQImage(const cv::Mat &inMat) { switch (inMat.type()) { // 8-bit, 4 channel case CV_8UC4: { QImage image(inMat.data, inMat.cols, inMat.rows, static_cast<int>(inMat.step), QImage::Format_ARGB32); return image; } // 8-bit, 3 channel case CV_8UC3: { QImage image(inMat.data, inMat.cols, inMat.rows, static_cast<int>(inMat.step), QImage::Format_RGB888); return image.rgbSwapped(); } // 8-bit, 1 channel case CV_8UC1: { #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) QImage image(inMat.data, inMat.cols, inMat.rows, static_cast<int>(inMat.step), QImage::Format_Grayscale8); #else static QVector<QRgb> sColorTable; // only create our color table the first time if (sColorTable.isEmpty()) { sColorTable.resize(256 ); for (int i = 0; i < 256; ++i ) { sColorTable[i] = qRgb(i, i, i ); } } QImage image(inMat.data, inMat.cols, inMat.rows, static_cast<int>(inMat.step), QImage::Format_Indexed8 ); image.setColorTable(sColorTable ); #endif return image; } default: { qWarning()<< "ASM::cvMatToQImage()- cv::Mat image type not handled in switch:" << inMat.type(); break; } } return QImage(); } QPixmap MyVideoCapture::cvMatToQPixmap(const cv::Mat &inMat) { return QPixmap::fromImage(cvMatToQImage(inMat)); }
According to the debugger, I guess it crashes right after the void MainWindow::on_pushButton_2_clicked() function is done, in the mainwindow.cpp however, I don't know how I could implement it in the other way so it would work properly.
Please help...
-
Hi
MyVideoCapture is a thread so your usage seems a bit suspect as it
will have a very short life.void MainWindow::on_pushButton_2_clicked()
{
MyVideoCapture f;
QPixmap frame4 = f.klatka();
ui->label_2->setPixmap(frame4.scaled(500, 500));
} << "f" dies here so might not have time to capture anything.However, you already have
mOpenCV_videoCapture
which seems to be a MyVideoCapture
so it seems a bit odd to make a new one.Also you did hook up to the signal
connect(mOpenCV_videoCapture, &MyVideoCapture::newPixmapCaptured, this, &
{
ui->label->setPixmap(mOpenCV_videoCapture->pixmap().scaled(500, 500));
});Does this function ever run?
It will only emit that signal if it captures a frame so if it's not emitted then something is
up with the actual capture. -
I would say it's the common problem when converting cv::Mat to a QImage - noone is reading the documentation and then wonder why the program is crashing. A forum search would have helped here too...
"The buffer must remain valid throughout the life of the QImage and all copies that have not been modified or otherwise detached from the original buffer. The image does not delete the buffer at destruction. You can provide a function pointer cleanupFunction along with an extra pointer cleanupInfo that will be called when the last copy is destroyed."
-
@mrjj said in QPixmap::scaled: Pixmap is a null pixmap (displaying Pixmap on the label):
Hi
MyVideoCapture is a thread so your usage seems a bit suspect as it
will have a very short life.void MainWindow::on_pushButton_2_clicked()
{
MyVideoCapture f;
QPixmap frame4 = f.klatka();
ui->label_2->setPixmap(frame4.scaled(500, 500));
} << "f" dies here so might not have time to capture anything.However, you already have
mOpenCV_videoCapture
which seems to be a MyVideoCapture
so it seems a bit odd to make a new one.Oh my god... I've changed
void MainWindow::on_pushButton_2_clicked() { MyVideoCapture f; QPixmap frame4 = f.klatka(); ui->label_2->setPixmap(frame4.scaled(500, 500)); }
to
void MainWindow::on_pushButton_2_clicked() { QPixmap frame4 = mOpenCV_videoCapture->klatka(); ui->label_2->setPixmap(frame4.scaled(500, 500)); }
and now it works as intended. Thank you so much!
Also you did hook up to the signal
connect(mOpenCV_videoCapture, &MyVideoCapture::newPixmapCaptured, this, &
{
ui->label->setPixmap(mOpenCV_videoCapture->pixmap().scaled(500, 500));
});Does this function ever run?
It will only emit that signal if it captures a frame so if it's not emitted then something is
up with the actual capture.Well yes, it displays frames from my webcam after I press first button. I might mislead you, as I forgot to add mainwindow.h file. Here it is:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> namespace Ui { class MainWindow; } class MyVideoCapture; class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); //QPixmap frame4; private slots: void on_pushButton_clicked(); void on_pushButton_2_clicked(); private: Ui::MainWindow *ui; MyVideoCapture *mOpenCV_videoCapture; //QPixmap frame4; }; #endif // MAINWINDOW_H
-
@Yamado said in QPixmap::scaled: Pixmap is a null pixmap (displaying Pixmap on the label):
and now it works as intended. Thank you so much!
But will still crash now and then - read my post and my link