Как конвертировать cv::Mat в QImage или QPixmap?
Я пытался осмотреться и попробовал все, что нашел, но не нашел решения этой проблемы.
Я пытаюсь обновить изображение в приложении QT нажатием кнопки.
В конструкторе мне удалось показать изображение:
cv::Mat temp = cv::Mat(*this->cv_size,CV_8UC3);
temp = cv::Scalar(0,255,155);
ui->image->setPixmap(QPixmap::fromImage( Mat2QImage(temp)));
А потом я создал кнопку и связал эту функцию с ней
void UIQT::refreshImage(){
cv::Mat temp = cv::Mat(*this->cv_size,CV_8UC3);
temp = cv::Scalar(0,255,0);
ui->image->setPixmap(QPixmap::fromImage( Mat2QImage(temp)));
std::cout << "refreshed" << std::endl;
}
Вот функция:
QImage UIQT::Mat2QImage(cv::Mat const& src) {
cv::Mat temp(src.cols,src.rows,src.type());
cvtColor(src, temp,CV_BGR2RGB);
QImage dest= QImage((uchar*) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
return dest;
}
Но когда я нажимаю кнопку, все изображение становится белым. У кого-нибудь есть идея?
1 ответ
Ваш код кажется безнадежно запутанным, и вы делаете много ненужных вещей. Нет причин иметь cv_size
указатель Вы должны просто использовать экземпляр cv::Size
, Ваш Mat2QImage
возвращает QImage
с висящим указателем на его данные.
Код ниже является полным, проверенным примером. Это поддерживает иное ненужное Ui
Пространство имен и т. д., просто чтобы сделать его похожим на существующую кодовую базу.
Некоторые опубликованы Mat2QImage
методы не работают, так как они возвращают QImage
который использует данные мата без сохранения ссылки на него. Если исходный мат перестает существовать, изображение ссылается на висячий указатель, и может произойти все что угодно. Это была твоя проблема. Версия ниже верна в этом отношении.
#include <QApplication>
#include <QBasicTimer>
#include <QImage>
#include <QPixmap>
#include <QGridLayout>
#include <QLabel>
#include <opencv2/opencv.hpp>
namespace Ui { struct UIQT {
QLabel * image;
void setupUi(QWidget * w) {
QGridLayout * layout = new QGridLayout(w);
layout->addWidget((image = new QLabel));
}
}; }
class UIQT : public QWidget {
Q_OBJECT
Ui::UIQT ui;
QBasicTimer m_timer;
cv::Size m_size;
void timerEvent(QTimerEvent *);
public:
UIQT(QWidget * parent = 0);
~UIQT();
Q_SLOT void refreshImage();
};
void matDeleter(void* mat) { delete static_cast<cv::Mat*>(mat); }
static QImage imageFromMat(cv::Mat const& src) {
Q_ASSERT(src.type() == CV_8UC3);
cv::Mat * mat = new cv::Mat(src.cols,src.rows,src.type());
cvtColor(src, *mat, CV_BGR2RGB);
return QImage((uchar*)mat->data, mat->cols, mat->rows, mat->step,
QImage::Format_RGB888, &matDeleter, mat);
}
static cv::Scalar randomScalar() {
static cv::RNG rng(12345);
return cv::Scalar(rng.uniform(0,255), rng.uniform(0, 255), rng.uniform(0, 255));
}
static QPixmap pixmapFromMat(const cv::Mat & src) {
QImage image(imageFromMat(src));
return QPixmap::fromImage(image);
}
UIQT::UIQT(QWidget * parent) :
QWidget(parent),
m_size(100, 100)
{
ui.setupUi(this);
m_timer.start(500, this);
refreshImage();
}
UIQT::~UIQT() {}
void UIQT::timerEvent(QTimerEvent * ev) {
if (ev->timerId() != m_timer.timerId()) return;
refreshImage();
}
void UIQT::refreshImage() {
cv::Mat mat(m_size, CV_8UC3, randomScalar());
ui.image->setPixmap(pixmapFromMat(mat));
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
UIQT w;
w.show();
return app.exec();
}
#include "main.moc"