Qt6中如何直接从QCamera获取帧?相机就绪报错求助
问题解决与逐帧接收实现方案
一、修复「Camera is not ready」错误
你的代码出现该错误的核心原因是相机启动为异步操作,调用camera()->start()后相机不会立刻进入就绪状态,此时调用capture()必然报错。此外代码还存在对象重复创建、信号重复连接的问题,以下是修正后的关键逻辑:
1. 优化相机启动流程,等待就绪状态
先清理旧资源,再创建新设备,并监听相机状态确保就绪后再允许捕获:
// 类成员变量需提前声明:QCamera* m_camera = nullptr; QImageCapture* m_imageCapture = nullptr; QObject::connect(ui->start, &QPushButton::clicked, [this]() { // 清理旧资源,避免内存泄漏 if (m_camera) { if (m_camera->isActive()) m_camera->stop(); delete m_camera; m_camera = nullptr; } if (m_imageCapture) { delete m_imageCapture; m_imageCapture = nullptr; } auto item = ui->list->currentItem(); auto cam = item->data(Qt::UserRole).value<QCameraDevice>(); m_camera = new QCamera(cam); m_imageCapture = new QImageCapture; capturesession.setCamera(m_camera); capturesession.setImageCapture(m_imageCapture); // 监听相机状态,就绪后给出提示 connect(m_camera, &QCamera::cameraStatusChanged, this, [this](QCamera::Status status) { if (status == QCamera::ActiveStatus) { ui->text->appendPlainText("相机已就绪,可执行捕获"); } }); // 直接连接图像捕获信号,避免重复连接 connect(m_imageCapture, &QImageCapture::imageCaptured, this, [this](int id, const QImage &preview) { ui->text->appendPlainText(QString("Image Captured:%1").arg(id)); ui->label->setPixmap(QPixmap::fromImage(preview)); }); connect(m_imageCapture, &QImageCapture::errorOccurred, this, [this](int id, QImageCapture::Error error, const QString &errorString) { ui->text->appendPlainText(QString("[%1]error:%2").arg(id).arg(errorString)); }); m_camera->start(); });
2. 修改捕获按钮逻辑,增加就绪判断
QObject::connect(ui->capture, &QPushButton::clicked, [this]() { if (!m_camera || m_camera->status() != QCamera::ActiveStatus) { ui->text->appendPlainText("相机未就绪,请等待"); return; } // 打印相机状态 ui->text->appendPlainText( QString("camera[%1]:isActive=%2, isAvailable=%3, isFlashReady=%4.\n") .arg(m_camera->cameraDevice().id()) .arg(m_camera->isActive()) .arg(m_camera->isAvailable()) .arg(m_camera->isFlashReady()) ); // 执行捕获 m_imageCapture->capture(); });
二、直接从相机接收逐帧并显示(无需QVideoWidget)
可以通过QVideoSink实时获取相机每一帧,直接处理后显示在QLabel或QGraphicsView上,步骤如下:
1. 添加成员变量
在类中声明:QVideoSink* m_videoSink = nullptr;
2. 修改相机启动逻辑,设置QVideoSink
在start按钮的槽函数中,创建QVideoSink并绑定到捕获会话,监听帧变化信号:
// 在start按钮槽函数创建m_camera和m_imageCapture后添加: m_videoSink = new QVideoSink(this); capturesession.setVideoSink(m_videoSink); // 监听每帧数据变化 connect(m_videoSink, &QVideoSink::videoFrameChanged, this, [this](const QVideoFrame &frame) { // 将QVideoFrame转换为QImage QVideoFrame cloneFrame = frame; if (!cloneFrame.map(QVideoFrame::ReadOnly)) return; QImage image(cloneFrame.bits(), cloneFrame.width(), cloneFrame.height(), QVideoFrame::imageFormatFromPixelFormat(cloneFrame.pixelFormat())); image = image.copy(); // 解除映射前复制图像,避免内存问题 cloneFrame.unmap(); // 显示到QLabel(保持比例适配控件大小) ui->label->setPixmap(QPixmap::fromImage(image).scaled(ui->label->size(), Qt::KeepAspectRatio)); });
3. 完善停止逻辑
QObject::connect(ui->stop, &QPushButton::clicked, [this]() { if (m_camera && m_camera->isActive()) { m_camera->stop(); } // 如需完全释放资源,可在此处delete m_camera、m_imageCapture、m_videoSink });
这种方式可以实时获取相机原始帧,无需依赖QVideoWidget即可完成帧处理与显示。
内容的提问来源于stack exchange,提问作者Ershat Dilmurat
相关产品推荐
相关产品推荐

