在 QML VideoOutput 中将 cv::mat 显示为 QVideoFrame
Display cv::Mat as QVideoFrame in a QML VideoOutput
>我有一个OpenCV后端,它通过cv::VideoCapture
从相机设备检索视频帧,进行一些处理,然后将cv::Mat
帧传递给Qt5应用程序以在QMLVideoOutput
中显示。
问题是绘制的帧是空的/白色的。
CameraService
类正在从后端对象接收cv::Mat
,该对象使用Qt::QueuedConnection
信号在自己的线程上运行。然后我将其转换为QImage
,在设置像素格式后,我用它来初始化QVideoFrame
并将其传递给从QMLVideoOutput
接收的QAbstractVideoSurface
。
在转换为QVideoFrame
之前,我已经检查了cv::Mat
是否具有有效的内容,因此情况并非如此。
还是我完全错了,应该画一幅画?
相关代码:
CameraService.cpp
CameraService::CameraService(Video::Backend *backend)
: QObject(),
surface(nullptr),
isFormatSet(false) {
this->backend = backend;
connect(
backend, &Video::Backend::onFrameReady,
this, &CameraService::onVideoFrameReady,
Qt::QueuedConnection);
}
CameraService::~CameraService() {
backend->deleteLater();
}
QAbstractVideoSurface *CameraService::getVideoSurface() const {
return surface;
}
void CameraService::setVideoSurface(QAbstractVideoSurface *surface) {
if (!this->surface && surface)
backend->start();
if (this->surface && this->surface != surface && this->surface->isActive())
this->surface->stop();
this->surface = surface;
if (this->surface && format.isValid()) {
format = this->surface->nearestFormat(format);
this->surface->start(format);
}
}
void CameraService::setFormat(
int width,
int height,
QVideoFrame::PixelFormat frameFormat
){
QSize size(width, height);
QVideoSurfaceFormat format(size, frameFormat);
this->format = format;
if (surface) {
if (surface->isActive())
surface->stop();
this->format = surface->nearestFormat(this->format);
surface->start(this->format);
}
}
void CameraService::onVideoFrameReady(cv::Mat currentFrame) {
if (!surface || currentFrame.empty())
return;
cv::Mat continuousFrame;
if (!currentFrame.isContinuous())
continuousFrame = currentFrame.clone();
else
continuousFrame = currentFrame;
if (!isFormatSet) {
setFormat(
continuousFrame.cols,
continuousFrame.rows,
QVideoFrame::PixelFormat::Format_BGR32);
isFormatSet = true;
}
frame = QImage(
(uchar *)continuousFrame.data,
continuousFrame.cols,
continuousFrame.rows,
continuousFrame.step,
QVideoFrame::imageFormatFromPixelFormat(
QVideoFrame::PixelFormat::Format_BGR32));
surface->present(QVideoFrame(frame));
}
QML 对象:
VideoOutput {
objectName: "videoOutput";
anchors.fill: parent;
fillMode: VideoOutput.PreserveAspectCrop;
source: CameraService;
}
使用以下语句将CameraService
对象作为单例提供给 QML:
qmlRegisterSingletonInstance<Application::CameraService>("Application.CameraService", 1, 0, "CameraService", service);
分析代码 我注意到不支持转换(我建议您检查格式是否有效或(。为此,我进行了一些更改:...
#ifndef CAMERASERVICE_H
#define CAMERASERVICE_H
#include "backend.h"
#include <QObject>
#include <QPointer>
#include <QVideoFrame>
#include <QVideoSurfaceFormat>
#include <opencv2/core/mat.hpp>
class QAbstractVideoSurface;
class CameraService : public QObject
{
Q_OBJECT
Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface WRITE setVideoSurface NOTIFY surfaceChanged)
public:
explicit CameraService(Backend *backend, QObject *parent = nullptr);
QAbstractVideoSurface* videoSurface() const;
public Q_SLOTS:
void setVideoSurface(QAbstractVideoSurface* surface);
Q_SIGNALS:
void surfaceChanged(QAbstractVideoSurface* surface);
private Q_SLOTS:
void onVideoFrameReady(cv::Mat currentFrame);
private:
void setFormat(int width, int height, QVideoFrame::PixelFormat frameFormat);
QPointer<QAbstractVideoSurface> m_surface;
QScopedPointer<Backend> m_backend;
QVideoSurfaceFormat m_format;
bool m_isFormatSet;
QImage m_image;
};
#endif // CAMERASERVICE_H
#include "backend.h"
#include "cameraservice.h"
#include <QAbstractVideoSurface>
#include <iostream>
CameraService::CameraService(Backend *backend, QObject *parent)
: QObject(parent), m_backend(backend), m_isFormatSet(false)
{
connect(m_backend.data(), &Backend::frameReady, this, &CameraService::onVideoFrameReady);
}
QAbstractVideoSurface *CameraService::videoSurface() const
{
return m_surface;
}
void CameraService::setVideoSurface(QAbstractVideoSurface *surface){
if (m_surface == surface)
return;
if(m_surface && m_surface != surface && m_surface->isActive())
m_surface->stop();
m_surface = surface;
Q_EMIT surfaceChanged(m_surface);
m_backend->start();
if (m_surface && m_format.isValid()) {
m_format = m_surface->nearestFormat(m_format);
m_surface->start(m_format);
}
}
void CameraService::setFormat(
int width,
int height,
QVideoFrame::PixelFormat frameFormat
){
QSize size(width, height);
QVideoSurfaceFormat format(size, frameFormat);
m_format = format;
if (m_surface) {
if (m_surface->isActive())
m_surface->stop();
m_format = m_surface->nearestFormat(m_format);
m_surface->start(m_format);
}
}
void CameraService::onVideoFrameReady(cv::Mat currentFrame){
if (!m_surface || currentFrame.empty())
return;
cv::Mat continuousFrame;
if (!currentFrame.isContinuous())
continuousFrame = currentFrame.clone();
else
continuousFrame = currentFrame;
if (!m_isFormatSet) {
setFormat(continuousFrame.cols,
continuousFrame.rows,
QVideoFrame::Format_RGB32);
m_isFormatSet = true;
}
m_image = QImage(continuousFrame.data,
continuousFrame.cols,
continuousFrame.rows,
continuousFrame.step,
QImage::Format_RGB888);
m_image = m_image.rgbSwapped();
m_image.convertTo(QVideoFrame::imageFormatFromPixelFormat(QVideoFrame::Format_RGB32));
m_surface->present(QVideoFrame(m_image));
}
您可以在此处找到完整的示例。
相关文章:
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- Difference in displaying cv2 Mat
- 在 QML VideoOutput 中将 cv::mat 显示为 QVideoFrame
- 在qpixMap中显示一个CV :: MAT(键入CV_32F)
- 在MFC图片框中显示IPLimage/ MAT (opencv)
- C ++保存mat文件,构建日志显示"undefined reference to 'H5Tget_member_type'....................."
- 在图片框中显示cv::Mat格式的网络摄像头提要
- 如何显示窗口大小不同的输出图像?通过使用 cv::Mat
- Haar检测-保存图像的Mat,以便获得并显示前一帧
- OpenCV 2.4:在MFC中显示cv::Mat
- 用于安卓人脸识别的 openCV 显示"mat not continuous"错误
- 使用矢量显示视频无法<Mat>正常工作
- 将我的阵列移动到 Mat 并使用打开的 CV 显示图像
- 访问Ximea相机并使用OpenCV设置预定义的分辨率时,由于相机默认分辨率的大小为Mat,因此显示混乱的输出
- cv::imshow 在不同的线程上不显示 cv::mat 颜色
- 如何在Windows窗体应用程序中显示cv::Mat
- 如何在MFC视图上显示OpenCV Mat
- OpenCV,显示动态二维数组作为图像(到Mat对象)
- 如何在OpenCV中显示Mat变量中存在的所有值