Mat格式转QImage格式,对QImage对象操作时崩溃(QImge::scaled或其他操作)

最近编写QT+opencv视觉计算框架时,遇到了崩溃问题,已经解决,今天记录一下。
环境:QT5.9.0(MSVC2015 32bit编译器)+opencv4.1.1(MSVC2015 32bit自行编译版)
问题描述:重写QThread的run函数,开启了一个子线程进行摄像头图像采集,然后通过信号槽将QImage对象发送到主界面进行显示,结果在主界面槽中对QImage对象进行缩放的时候,程序异常崩溃了。
崩溃原因:子线程中通过opencv采集到了Mat格式的图片:

    Mat mat=camera->read();
    

然后使用MattoQImage转化函数转成QImage格式:

QImage image =camera->MattoQImage(mat);
/*函数原型
QImage Camera::MattoQImage(Mat mat)
{
    cvtColor(mat,mat,CV_BGR2RGB);
    QImage image(mat.data,
                 mat.cols,
                 mat.rows,
                 QImage::Format_RGB888);
    return image;
}
*/

之后,我将这个QImage对象直接通过信号槽进行了传递:

emit updateImage(image);

主界面类中的槽函数:

void MainWindow::updateImagefrom_threadCameraBelow(	QImage image)
{
    QImage image2=image_camerabelow.scaled(480,360,Qt::IgnoreAspectRatio); //执行到这句程序崩溃
    ui->label_camera->setPixmap(QPixmap::fromImage(image2)); 
}

解决方法:
不要将image对象直接传递,换成使用QImage::copy将image拷贝一份,然后进行传递

    QImage image =camera->MattoQImage(mat);
    image_copy=image.copy(image.rect());
    emit updateImage(image_copy);

妈妈再也不担心我的程序崩溃了

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
以下是代码实现: ```cpp #include <QWidget> #include <QImage> #include <opencv2/opencv.hpp> #include <QTimer> #include <QFileDialog> class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_open_video_btn_clicked(); void on_stop_video_btn_clicked(); void on_capture_btn_clicked(); void readFarme(); void on_timeout_video_btn_clicked(); void on_keep_video_btn_clicked(); private: QImage *imag; cv::VideoCapture *cam; cv::Mat *frame; QTimer *timer; bool isPlaying; bool isTiming; bool isRecording; cv::VideoWriter *writer; }; Widget::Widget(QWidget *parent) : QWidget(parent) { imag = new QImage(); cam = new cv::VideoCapture(); frame = new cv::Mat(); timer = new QTimer(); isPlaying = false; isTiming = false; isRecording = false; writer = new cv::VideoWriter(); } Widget::~Widget() { delete imag; delete cam; delete frame; delete timer; delete writer; } void Widget::on_open_video_btn_clicked() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open Video"), ".", tr("Video Files(*.mp4 *.avi *.flv)")); if (fileName.isEmpty()) { return; } cam->open(fileName.toStdString()); if (!cam->isOpened()) { return; } isPlaying = true; cv::namedWindow("Video", CV_WINDOW_NORMAL); cv::resizeWindow("Video", 800, 600); timer->start(30); } void Widget::on_stop_video_btn_clicked() { isPlaying = false; timer->stop(); cam->release(); cv::destroyWindow("Video"); } void Widget::on_capture_btn_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save Image"), ".", tr("Images(*.png *.jpg *.bmp)")); if (fileName.isEmpty()) { return; } cv::imwrite(fileName.toStdString(), *frame); } void Widget::readFarme() { (*cam) >> *frame; if (frame->empty()) { on_stop_video_btn_clicked(); return; } cv::cvtColor(*frame, *frame, cv::COLOR_BGR2RGB); QImage image((uchar*)frame->data, frame->cols, frame->rows, QImage::Format_RGB888); *imag = image.scaled(this->size(), Qt::KeepAspectRatio); update(); } void Widget::on_timeout_video_btn_clicked() { if (!isTiming) { isTiming = true; timer->start(30); } else { isTiming = false; timer->stop(); } } void Widget::on_keep_video_btn_clicked() { if (!isRecording) { QString fileName = QFileDialog::getSaveFileName(this, tr("Save Video"), ".", tr("Videos(*.avi)")); if (fileName.isEmpty()) { return; } int fourcc = cv::VideoWriter::fourcc('M', 'J', 'P', 'G'); double fps = 30.0; writer->open(fileName.toStdString(), fourcc, fps, cv::Size(cam->get(cv::CAP_PROP_FRAME_WIDTH), cam->get(cv::CAP_PROP_FRAME_HEIGHT))); isRecording = true; } else { isRecording = false; writer->release(); } } void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.drawImage(0, 0, *imag); } ``` 该类继承自 QWidget 类,并重载了 paintEvent() 函数用于显示图像。通过成员变量和成员函数实现了视频播放、视频截取、视频录制等功能。其中,QTimer 类用于定读取视频帧信息,QFileDialog 类用于打开、保存文件对话框。OpenCV 中的 cv::VideoCapture 类用于获取视频帧信息,cv::Mat 类用于存储每一帧图像信息,cv::VideoWriter 类用于保存录制的视频文件。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值