QvideoFrame to cv::Mat -> Solved
-
Re: Convert QvideoFrame to Mat image
1- Configure profile (if Qt vesrion < 5.15.0)
in profile (.pro or .pri) add:QT += gui-private
2- create functions:
in your class functions add: example: MyFunctions.h#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) #include "private/qvideoframe_p.h" #endif #include <QOpenGLContext> #include <QOpenGLFunctions> #include <QVideoFrame> #include <QDebug> #include <QImage> #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/imgproc/types_c.h"
static QImage QVideoFrameToQImage( const QVideoFrame& videoFrame ){ if ( videoFrame.handleType() == QAbstractVideoBuffer::NoHandle ) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) QImage image = videoFrame.image(); #else QImage image = qt_imageFromVideoFrame( videoFrame ); #endif if ( image.isNull() ) return QImage(); if ( image.format() != QImage::Format_ARGB32 ) return image.convertToFormat( QImage::Format_ARGB32 ); return image; } if ( videoFrame.handleType() == QAbstractVideoBuffer::GLTextureHandle ) { QImage image( videoFrame.width(), videoFrame.height(), QImage::Format_ARGB32 ); GLuint textureId = static_cast<GLuint>( videoFrame.handle().toInt() ); QOpenGLContext* ctx = QOpenGLContext::currentContext(); QOpenGLFunctions* f = ctx->functions(); GLuint fbo; f->glGenFramebuffers( 1, &fbo ); GLint prevFbo; f->glGetIntegerv( GL_FRAMEBUFFER_BINDING, &prevFbo ); f->glBindFramebuffer( GL_FRAMEBUFFER, fbo ); f->glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0 ); f->glReadPixels( 0, 0, videoFrame.width(), videoFrame.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.bits() ); f->glBindFramebuffer( GL_FRAMEBUFFER, static_cast<GLuint>( prevFbo ) ); return image.rgbSwapped(); } return QImage(); }
static cv::Mat QImageToCvMat(QImage inImage, bool inCloneImageData = true) { switch ( inImage.format() ) { // 8-bit, 4 channel case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: { cv::Mat mat( inImage.height(), inImage.width(), CV_8UC4, const_cast<uchar*>(inImage.bits()), static_cast<size_t>(inImage.bytesPerLine()) ); return (inCloneImageData ? mat.clone() : mat); } // 8-bit, 3 channel case QImage::Format_RGB32: { if ( !inCloneImageData ) { qWarning() << "QImageToCvMat() - Conversion requires cloning so we don't modify the original QImage data"; } cv::Mat mat( inImage.height(), inImage.width(), CV_8UC4, const_cast<uchar*>(inImage.bits()), static_cast<size_t>(inImage.bytesPerLine()) ); cv::Mat matNoAlpha; cv::cvtColor( mat, matNoAlpha, cv::COLOR_BGRA2BGR ); // drop the all-white alpha channel return matNoAlpha; } // 8-bit, 3 channel case QImage::Format_RGB888: { if ( !inCloneImageData ) { qWarning() << "QImageToCvMat() - Conversion requires cloning so we don't modify the original QImage data"; } QImage swapped = inImage.rgbSwapped(); cv::Mat mat( swapped.height(), swapped.width(), CV_8UC3, const_cast<uchar*>(swapped.bits()), static_cast<size_t>(swapped.bytesPerLine()) ); return (inCloneImageData ? mat.clone() : mat); } // 8-bit, 1 channel case QImage::Format_Grayscale8: case QImage::Format_Indexed8: { cv::Mat mat( inImage.height(), inImage.width(), CV_8UC1, const_cast<uchar*>(inImage.bits()), static_cast<size_t>(inImage.bytesPerLine()) ); return (inCloneImageData ? mat.clone() : mat); } #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) case QImage::Format_Grayscale16: { cv::Mat mat(cv::Size(inImage.width(),inImage.height()),CV_16U,const_cast<uchar*>(inImage.bits()),cv::Mat::AUTO_STEP); // or // cv::Mat mat( inImage.height(), inImage.width(), // CV_16U, // const_cast<uchar*>(inImage.bits()), // static_cast<size_t>(inImage.bytesPerLine()) // ); return (inCloneImageData ? mat.clone() : mat); } #endif default: qWarning() << "QImageToCvMat() - QImage format not handled in switch:" << inImage.format(); break; } return cv::Mat(); }
3- test
in your code .cpp:
// vFrame is a QVideoFrame to convertQImage img = QVideoFrameToQImage(vFrame); cv::Mat videoFrame = QImageToCvMat(img);
or
cv::Mat videoFrame = QImageToCvMat(QVideoFrameToQImage(vFrame))
-
-
-
-
-
-
-
-