问题
I've tried to look around and tried everything I've found, but haven't found a solution for this problem.
I'm trying to update an image in a QT application by button click.
In the constructor I've managed to show a image:
cv::Mat temp = cv::Mat(*this->cv_size,CV_8UC3);
temp = cv::Scalar(0,255,155);
ui->image->setPixmap(QPixmap::fromImage( Mat2QImage(temp)));
And then I've created a button and linked this function to it
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;
}
Here is the function:
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;
}
But when I hit the button the whole image turns white. Anyone got an idea?
回答1:
Your code seems to be hopelessly convoluted and you do a lot of unnecessary things. There's no reason to have cv_size
a pointer. You should just use an instance of cv::Size
. Your Mat2QImage
returns a QImage
with a dangling pointer to its data.
The code below is a complete, tested example. It maintains the otherwise unnecessary Ui
namespace etc. just to make it similar to your existing code base.
Some publicized Mat2QImage
-style methods are broken as they return a QImage
that uses the mat's data without retaining a reference to it. If the source mat ceases to exist, the image references a dangling pointer, and anything can happen. That was your problem. The version below is correct in this respect.
#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"
来源:https://stackoverflow.com/questions/22872075/how-to-convert-a-cvmat-to-qimage-or-qpixmap