add,山地所贡嘎山10:
优化rgb相机控制,添加采集视频和照片的逻辑;
This commit is contained in:
@ -120,6 +120,31 @@ void AppSettings::setFiberImagerDataFolder(const QString& path)
|
||||
m_settings.setValue("General/FiberImagerDataFolder", path);
|
||||
}
|
||||
|
||||
QString AppSettings::rgbCameraDataFolder() const
|
||||
{
|
||||
QString path = m_settings.value("RgbCamera/RgbCameraDataFolder", "D:").toString();
|
||||
if (path.isEmpty())
|
||||
{
|
||||
return QCoreApplication::applicationDirPath() + "/CapturedRgbCameraData/";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void AppSettings::setRgbCameraDataFolder(const QString& path)
|
||||
{
|
||||
m_settings.setValue("RgbCamera/RgbCameraDataFolder", path);
|
||||
}
|
||||
|
||||
QString AppSettings::rgbCameraFileName() const
|
||||
{
|
||||
return m_settings.value("RgbCamera/FileName", "test").toString();
|
||||
}
|
||||
|
||||
void AppSettings::setRgbCameraFileName(const QString& name)
|
||||
{
|
||||
m_settings.setValue("RgbCamera/FileName", name);
|
||||
}
|
||||
|
||||
double AppSettings::scanSpeed() const
|
||||
{
|
||||
return m_settings.value("OneMotorControl/ScanSpeed", kDefaultScanSpeed).toDouble();
|
||||
|
||||
@ -38,6 +38,13 @@ public:
|
||||
QString FiberImagerDataFolder() const;
|
||||
void setFiberImagerDataFolder(const QString& path);
|
||||
|
||||
QString rgbCameraDataFolder() const;
|
||||
void setRgbCameraDataFolder(const QString& path);
|
||||
|
||||
// RGB相机文件名
|
||||
QString rgbCameraFileName() const;
|
||||
void setRgbCameraFileName(const QString& name);
|
||||
|
||||
// 扫描速度
|
||||
double scanSpeed() const;
|
||||
void setScanSpeed(double value);
|
||||
|
||||
@ -1166,6 +1166,9 @@ void HPPA::onGonggashanRecord(QString posInfo)
|
||||
}
|
||||
|
||||
onStartRecordStep1();
|
||||
|
||||
//采集rgb图像
|
||||
|
||||
}
|
||||
|
||||
void HPPA::recordFromRobotArm(int fileCounter)
|
||||
@ -1667,6 +1670,7 @@ void HPPA::createGonggaRotatingPlatformScenario()
|
||||
|
||||
m_tabManager->showTab(m_hic);
|
||||
m_tabManager->showTab(m_ic);
|
||||
m_tabManager->showTab(m_rgbCameraControlWindow);
|
||||
m_tabManager->showTab(m_fodisWindow);
|
||||
m_tabManager->showTab(m_omc);
|
||||
m_tabManager->showTab(m_gonggaShanRecordCtl);
|
||||
|
||||
@ -160,6 +160,7 @@
|
||||
<ClCompile Include="recordFrameCounter.cpp" />
|
||||
<ClCompile Include="resononImager.cpp" />
|
||||
<ClCompile Include="ResononNirImager.cpp" />
|
||||
<ClCompile Include="RgbCameraCaptureCoordinator.cpp" />
|
||||
<ClCompile Include="RgbCameraOperation.cpp" />
|
||||
<ClCompile Include="rgbCameraWindow.cpp" />
|
||||
<ClCompile Include="RobotArmControl.cpp" />
|
||||
@ -289,6 +290,7 @@
|
||||
<ClInclude Include="ResononNirImager.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<QtMoc Include="RgbCameraCaptureCoordinator.h" />
|
||||
<QtMoc Include="RgbCameraOperation.h" />
|
||||
<QtMoc Include="resononImager.h" />
|
||||
<QtMoc Include="QMotorDoubleSlider.h" />
|
||||
|
||||
246
HPPA/RgbCameraCaptureCoordinator.cpp
Normal file
246
HPPA/RgbCameraCaptureCoordinator.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
#include "stdafx.h"
|
||||
#include "RgbCameraCaptureCoordinator.h"
|
||||
#include "RgbCameraOperation.h"
|
||||
#include "AppSettings.h"
|
||||
|
||||
RgbCameraCaptureCoordinator::RgbCameraCaptureCoordinator(RgbCameraOperation* rgbCamera, QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_rgbCamera(rgbCamera)
|
||||
, m_captureMode(None)
|
||||
, m_isCapturing(false)
|
||||
, m_isCameraOpened(false)
|
||||
, m_pendingOpenCamera(false)
|
||||
, m_pendingMode(None)
|
||||
{
|
||||
if (m_rgbCamera)
|
||||
{
|
||||
connect(m_rgbCamera, &RgbCameraOperation::CamOpenedSignal,
|
||||
this, &RgbCameraCaptureCoordinator::onCameraOpened);
|
||||
connect(m_rgbCamera, &RgbCameraOperation::CamClosedSignal,
|
||||
this, &RgbCameraCaptureCoordinator::onCameraClosed);
|
||||
connect(m_rgbCamera, &RgbCameraOperation::VideoRecordingStartedSignal,
|
||||
this, &RgbCameraCaptureCoordinator::onVideoRecordingStarted);
|
||||
connect(m_rgbCamera, &RgbCameraOperation::VideoRecordingStoppedSignal,
|
||||
this, &RgbCameraCaptureCoordinator::onVideoRecordingStopped);
|
||||
|
||||
connect(this, &RgbCameraCaptureCoordinator::openCameraSignal,
|
||||
m_rgbCamera, &RgbCameraOperation::OpenCamera, Qt::QueuedConnection);
|
||||
connect(this, &RgbCameraCaptureCoordinator::closeCameraSignal,
|
||||
m_rgbCamera, &RgbCameraOperation::CloseCamera, Qt::QueuedConnection);
|
||||
connect(this, &RgbCameraCaptureCoordinator::startVideoRecordingSignal,
|
||||
m_rgbCamera, &RgbCameraOperation::startVideoRecording, Qt::QueuedConnection);
|
||||
connect(this, &RgbCameraCaptureCoordinator::stopVideoRecordingSignal,
|
||||
m_rgbCamera, &RgbCameraOperation::stopVideoRecording, Qt::QueuedConnection);
|
||||
connect(this, &RgbCameraCaptureCoordinator::startPhotoSaveTimerSignal,
|
||||
m_rgbCamera, &RgbCameraOperation::startPhotoSaveTimer, Qt::QueuedConnection);
|
||||
connect(this, &RgbCameraCaptureCoordinator::stopPhotoSaveTimerSignal,
|
||||
m_rgbCamera, &RgbCameraOperation::stopPhotoSaveTimer, Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
RgbCameraCaptureCoordinator::~RgbCameraCaptureCoordinator()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::startVideoCapture()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
if (m_isCapturing)
|
||||
{
|
||||
if (m_captureMode == Video)
|
||||
{
|
||||
//emit errorOccurred(QStringLiteral("视频正在采集中"));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//emit errorOccurred(QStringLiteral("正在执行其他采集操作"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_pendingOpenCamera = true;
|
||||
m_pendingMode = Video;
|
||||
|
||||
openCamera();
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::stopVideoCapture()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
if (m_captureMode != Video || !m_isCapturing)
|
||||
{
|
||||
//emit errorOccurred(QStringLiteral("视频未在采集中"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_rgbCamera)
|
||||
{
|
||||
emit stopVideoRecordingSignal();
|
||||
closeCamera();
|
||||
}
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::startPhotoCapture()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
if (m_isCapturing)
|
||||
{
|
||||
if (m_captureMode == Photo)
|
||||
{
|
||||
//emit errorOccurred(QStringLiteral("照片正在采集中"));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//emit errorOccurred(QStringLiteral("正在执行其他采集操作"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_pendingOpenCamera = true;
|
||||
m_pendingMode = Photo;
|
||||
|
||||
openCamera();
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::stopPhotoCapture()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
if (m_captureMode != Photo || !m_isCapturing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
emit stopPhotoSaveTimerSignal();
|
||||
emit captureStopped(Photo);
|
||||
closeCamera();
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::openCamera()
|
||||
{
|
||||
if (!m_rgbCamera)
|
||||
{
|
||||
emit cameraOpenFailed(QStringLiteral("RGB相机对象未初始化"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_isCameraOpened)
|
||||
{
|
||||
onCameraOpened();
|
||||
return;
|
||||
}
|
||||
|
||||
emit openCameraSignal();
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::closeCamera()
|
||||
{
|
||||
if (!m_rgbCamera)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_isCameraOpened)
|
||||
{
|
||||
emit closeCameraSignal();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_isCameraOpened = false;
|
||||
m_isCapturing = false;
|
||||
m_captureMode = None;
|
||||
}
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::cleanup()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
if (m_rgbCamera && m_isCapturing)
|
||||
{
|
||||
if (m_captureMode == Video)
|
||||
{
|
||||
emit stopVideoRecordingSignal();
|
||||
}
|
||||
}
|
||||
|
||||
closeCamera();
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::onCameraOpened()
|
||||
{
|
||||
//QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
m_isCameraOpened = true;
|
||||
emit cameraOpened();
|
||||
|
||||
qDebug() << "Camera opened. Pending open camera: " << m_pendingOpenCamera << ", Pending mode: " << m_pendingMode;
|
||||
if (!m_pendingOpenCamera)
|
||||
{
|
||||
return;
|
||||
}
|
||||
qDebug() << "Camera opened. Pending open camera: --------------------------------------------";
|
||||
|
||||
m_pendingOpenCamera = false;
|
||||
CaptureMode mode = m_pendingMode;
|
||||
m_pendingMode = None;
|
||||
|
||||
m_captureMode = mode;
|
||||
m_isCapturing = true;
|
||||
|
||||
if (mode == Video)
|
||||
{
|
||||
emit startVideoRecordingSignal();
|
||||
}
|
||||
else if (mode == Photo)
|
||||
{
|
||||
emit captureStarted(Photo);
|
||||
emit startPhotoSaveTimerSignal();
|
||||
}
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::onCameraClosed()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
m_isCameraOpened = false;
|
||||
|
||||
CaptureMode previousMode = m_captureMode;
|
||||
|
||||
if (m_isCapturing)
|
||||
{
|
||||
emit captureStopped(previousMode);
|
||||
}
|
||||
|
||||
m_isCapturing = false;
|
||||
m_captureMode = None;
|
||||
|
||||
emit cameraClosed();
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::onVideoRecordingStarted()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
emit captureStarted(Video);
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::onVideoRecordingStopped()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
emit captureStopped(Video);
|
||||
|
||||
emit stopVideoRecordingSignal();
|
||||
closeCamera();
|
||||
}
|
||||
|
||||
void RgbCameraCaptureCoordinator::onPhotoCaptured()
|
||||
{
|
||||
}
|
||||
69
HPPA/RgbCameraCaptureCoordinator.h
Normal file
69
HPPA/RgbCameraCaptureCoordinator.h
Normal file
@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QMutex>
|
||||
|
||||
class RgbCameraOperation;
|
||||
|
||||
class RgbCameraCaptureCoordinator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum CaptureMode { None = 0, Video, Photo };
|
||||
Q_ENUM(CaptureMode)
|
||||
|
||||
explicit RgbCameraCaptureCoordinator(RgbCameraOperation* rgbCamera, QObject* parent = nullptr);
|
||||
~RgbCameraCaptureCoordinator();
|
||||
|
||||
// 视频采集控制
|
||||
Q_INVOKABLE void startVideoCapture();
|
||||
Q_INVOKABLE void stopVideoCapture();
|
||||
|
||||
// 照片采集控制
|
||||
Q_INVOKABLE void startPhotoCapture();
|
||||
Q_INVOKABLE void stopPhotoCapture();
|
||||
|
||||
// 状态查询
|
||||
CaptureMode getCurrentMode() const { return m_captureMode; }
|
||||
bool isCapturing() const { return m_isCapturing; }
|
||||
bool isCameraOpened() const { return m_isCameraOpened; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void captureStarted(CaptureMode mode);
|
||||
void captureStopped(CaptureMode mode);
|
||||
void cameraOpened();
|
||||
void cameraClosed();
|
||||
void cameraOpenFailed(const QString& error);
|
||||
void errorOccurred(const QString& error);
|
||||
void photoCaptured(const QString& filePath);
|
||||
|
||||
void openCameraSignal();
|
||||
void closeCameraSignal();
|
||||
void startVideoRecordingSignal();
|
||||
void stopVideoRecordingSignal();
|
||||
void startPhotoSaveTimerSignal();
|
||||
void stopPhotoSaveTimerSignal();
|
||||
|
||||
public Q_SLOTS:
|
||||
void openCamera();
|
||||
void closeCamera();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onCameraOpened();
|
||||
void onCameraClosed();
|
||||
void onVideoRecordingStarted();
|
||||
void onVideoRecordingStopped();
|
||||
void onPhotoCaptured();
|
||||
void cleanup();
|
||||
|
||||
private:
|
||||
RgbCameraOperation* m_rgbCamera;
|
||||
CaptureMode m_captureMode;
|
||||
bool m_isCapturing;
|
||||
bool m_isCameraOpened;
|
||||
bool m_pendingOpenCamera;//指示相机是否是带目的的打开:带目的打开true(打开就要录像+m_pendingMode),还是手动打开(false,不带目的)
|
||||
CaptureMode m_pendingMode;
|
||||
mutable QMutex m_dataMutex;
|
||||
};
|
||||
@ -1,15 +1,55 @@
|
||||
#include "stdafx.h"
|
||||
#include "RgbCameraOperation.h"
|
||||
#include "AppSettings.h"
|
||||
|
||||
RgbCameraOperation::RgbCameraOperation()
|
||||
{
|
||||
cam = nullptr;
|
||||
m_ImageProcessor = new ImageProcessor();
|
||||
m_func = nullptr;
|
||||
m_videoWriter = nullptr;
|
||||
m_isRecording = false;
|
||||
|
||||
m_captureTimer = new QTimer(this);
|
||||
connect(m_captureTimer, &QTimer::timeout, this, &RgbCameraOperation::onCaptureFrame);
|
||||
|
||||
m_photoSaveTimer = new QTimer(this);
|
||||
m_photoSaveTimer->setSingleShot(false);
|
||||
connect(m_photoSaveTimer, &QTimer::timeout, this, &RgbCameraOperation::onPhotoSaveTimeout);
|
||||
}
|
||||
|
||||
RgbCameraOperation::~RgbCameraOperation()
|
||||
{
|
||||
if (m_photoSaveTimer != nullptr)
|
||||
{
|
||||
m_photoSaveTimer->stop();
|
||||
//delete m_photoSaveTimer;
|
||||
m_photoSaveTimer = nullptr;
|
||||
}
|
||||
|
||||
if (m_captureTimer != nullptr)
|
||||
{
|
||||
m_captureTimer->stop();
|
||||
//delete m_captureTimer;
|
||||
m_captureTimer = nullptr;
|
||||
}
|
||||
|
||||
if (m_videoWriter != nullptr)
|
||||
{
|
||||
if (m_isRecording)
|
||||
{
|
||||
m_videoWriter->release();
|
||||
}
|
||||
delete m_videoWriter;
|
||||
m_videoWriter = nullptr;
|
||||
}
|
||||
|
||||
if (cam != nullptr)
|
||||
{
|
||||
cam->release();
|
||||
delete cam;
|
||||
cam = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void RgbCameraOperation::OpenCamera()
|
||||
@ -17,21 +57,80 @@ void RgbCameraOperation::OpenCamera()
|
||||
std::cout << "打开摄像头+++++++++++++++++++++++++++++++++++++++++++" << std::endl;
|
||||
cam = new cv::VideoCapture(0);
|
||||
|
||||
// 设置摄像头分辨率为最高可用分辨率
|
||||
int width = 640;//1920
|
||||
int height = 480;//1080
|
||||
cam->set(cv::CAP_PROP_FRAME_WIDTH, width);
|
||||
cam->set(cv::CAP_PROP_FRAME_HEIGHT, height);
|
||||
|
||||
// 验证实际设置的分辨率
|
||||
double actualWidth = cam->get(cv::CAP_PROP_FRAME_WIDTH);
|
||||
double actualHeight = cam->get(cv::CAP_PROP_FRAME_HEIGHT);
|
||||
std::cout << "摄像头分辨率设置为: " << actualWidth << "x" << actualHeight << std::endl;
|
||||
|
||||
record = true;
|
||||
|
||||
while (record)
|
||||
{
|
||||
//std::cout << "采集影像+++++++++++++++++++++++++++++++++++++++++++" << std::endl;
|
||||
cam->read(frame);
|
||||
m_qImage = m_ImageProcessor->Mat2QImage(frame);
|
||||
// 使用定时器定期获取图像,不再阻塞线程
|
||||
m_captureTimer->start(33); // ~30fps
|
||||
m_frameCounter = 0;
|
||||
}
|
||||
|
||||
emit PlotSignal();
|
||||
void RgbCameraOperation::onCaptureFrame()
|
||||
{
|
||||
if (!record || cam == nullptr || !cam->isOpened())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cam->release();
|
||||
cam->read(frame);
|
||||
m_frameCounter++;
|
||||
if (m_frameCounter == 1)
|
||||
{
|
||||
emit CamOpenedSignal();
|
||||
}
|
||||
|
||||
emit CamOpenedSignal();
|
||||
// 保存视频逻辑:如果正在录制,将当前帧写入视频
|
||||
if (m_isRecording && m_videoWriter != nullptr && !frame.empty())
|
||||
{
|
||||
m_videoWriter->write(frame);
|
||||
}
|
||||
|
||||
m_qImage = m_ImageProcessor->Mat2QImage(frame.clone());
|
||||
emit PlotSignal();
|
||||
}
|
||||
|
||||
void RgbCameraOperation::onPhotoSaveTimeout()
|
||||
{
|
||||
if (m_qImage.isNull())
|
||||
{
|
||||
std::cerr << "保存图片失败:当前没有可用的图像数据" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss_zzz");
|
||||
QString prefix = AppSettings::instance().rgbCameraFileName();
|
||||
QString fileName = QString("%1_rgb_%2.jpg").arg(prefix).arg(timestamp);
|
||||
QString fullPath = AppSettings::instance().rgbCameraDataFolder() + QDir::separator() + fileName;
|
||||
|
||||
if (m_qImage.save(fullPath, "JPG", 95))
|
||||
{
|
||||
std::cout << "图片已保存: " << fullPath.toStdString() << std::endl;
|
||||
emit photoSavedSignal(fullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "保存图片失败: " << fullPath.toStdString() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void RgbCameraOperation::startPhotoSaveTimer()
|
||||
{
|
||||
m_photoSaveTimer->start(2000); // 每2秒保存一张照片
|
||||
}
|
||||
|
||||
void RgbCameraOperation::stopPhotoSaveTimer()
|
||||
{
|
||||
m_photoSaveTimer->stop();
|
||||
}
|
||||
|
||||
void RgbCameraOperation::OpenCamera_callback()
|
||||
@ -66,5 +165,117 @@ void RgbCameraOperation::CloseCamera()
|
||||
|
||||
record = false;
|
||||
|
||||
// 停止定时器
|
||||
m_captureTimer->stop();
|
||||
m_photoSaveTimer->stop();
|
||||
|
||||
// 停止视频录制
|
||||
if (m_isRecording)
|
||||
{
|
||||
stopVideoRecording();
|
||||
}
|
||||
|
||||
// 释放摄像头
|
||||
if (cam != nullptr)
|
||||
{
|
||||
cam->release();
|
||||
//delete cam;
|
||||
cam = nullptr;
|
||||
}
|
||||
|
||||
emit CamClosedSignal();
|
||||
}
|
||||
|
||||
void RgbCameraOperation::saveImage()
|
||||
{
|
||||
if (m_qImage.isNull())
|
||||
{
|
||||
std::cerr << "保存图片失败:当前没有可用的图像数据" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 生成带时间戳的文件名
|
||||
QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss_zzz");
|
||||
QString prefix = AppSettings::instance().rgbCameraFileName();
|
||||
QString fileName = QString("%1_rgb_%2.jpg").arg(prefix).arg(timestamp);
|
||||
QString fullPath = AppSettings::instance().rgbCameraDataFolder() + QDir::separator() + fileName;
|
||||
|
||||
// 保存为 JPG 格式
|
||||
if (m_qImage.save(fullPath, "JPG", 95))
|
||||
{
|
||||
std::cout << "图片已保存: " << fullPath.toStdString() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "保存图片失败: " << fullPath.toStdString() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void RgbCameraOperation::startVideoRecording()
|
||||
{
|
||||
if (m_isRecording)
|
||||
{
|
||||
std::cout << "视频已经在录制中" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame.empty())
|
||||
{
|
||||
std::cerr << "开始录制失败:当前没有可用的帧数据" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 释放旧的 VideoWriter
|
||||
if (m_videoWriter != nullptr)
|
||||
{
|
||||
delete m_videoWriter;
|
||||
m_videoWriter = nullptr;
|
||||
}
|
||||
|
||||
// 生成带时间戳的视频文件名
|
||||
QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss");
|
||||
QString prefix = AppSettings::instance().rgbCameraFileName();
|
||||
QString fileName = QString("%1_video_%2.avi").arg(prefix).arg(timestamp);
|
||||
QString fullPath = AppSettings::instance().rgbCameraDataFolder() + QDir::separator() + fileName;
|
||||
|
||||
// 获取视频编码器和帧大小
|
||||
int fourcc = cv::VideoWriter::fourcc('M', 'J', 'P', 'G'); // Motion-JPEG 编码器
|
||||
cv::Size frameSize = frame.size();
|
||||
|
||||
// 创建 VideoWriter
|
||||
m_videoWriter = new cv::VideoWriter(fullPath.toStdString(), fourcc, 30.0, frameSize);
|
||||
|
||||
if (!m_videoWriter->isOpened())
|
||||
{
|
||||
std::cerr << "创建视频写入器失败: " << fullPath.toStdString() << std::endl;
|
||||
delete m_videoWriter;
|
||||
m_videoWriter = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
m_isRecording = true;
|
||||
std::cout << "开始录制视频: " << fullPath.toStdString() << std::endl;
|
||||
|
||||
emit VideoRecordingStartedSignal();
|
||||
}
|
||||
|
||||
void RgbCameraOperation::stopVideoRecording()
|
||||
{
|
||||
if (!m_isRecording)
|
||||
{
|
||||
std::cout << "视频没有在录制" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_videoWriter != nullptr)
|
||||
{
|
||||
m_videoWriter->release();
|
||||
//delete m_videoWriter;
|
||||
m_videoWriter = nullptr;
|
||||
}
|
||||
|
||||
m_isRecording = false;
|
||||
std::cout << "停止录制视频" << std::endl;
|
||||
|
||||
emit VideoRecordingStoppedSignal();
|
||||
}
|
||||
|
||||
@ -4,6 +4,9 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QDir>
|
||||
#include <QDateTime>
|
||||
#include <QCoreApplication>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <QImage>
|
||||
|
||||
@ -24,6 +27,12 @@ public:
|
||||
QImage m_qImage;
|
||||
void setCallback(void(*func)());
|
||||
|
||||
// 保存图片和视频的公共接口
|
||||
void saveImage(); // 保存当前帧为图片
|
||||
void startVideoRecording(); // 开始视频录制
|
||||
void stopVideoRecording(); // 停止视频录制
|
||||
bool isRecording() const { return m_isRecording; } // 获取录制状态
|
||||
|
||||
private:
|
||||
cv::Mat frame;
|
||||
cv::VideoCapture *cam;
|
||||
@ -34,15 +43,33 @@ private:
|
||||
|
||||
bool record;
|
||||
|
||||
// 保存图片和视频相关
|
||||
cv::VideoWriter* m_videoWriter;
|
||||
bool m_isRecording;
|
||||
int m_frameCounter;
|
||||
|
||||
// 定时器获取图像
|
||||
QTimer* m_captureTimer;
|
||||
// 定时器保存照片
|
||||
QTimer* m_photoSaveTimer;
|
||||
|
||||
private slots:
|
||||
void onCaptureFrame();
|
||||
void onPhotoSaveTimeout();
|
||||
|
||||
Q_SIGNALS:
|
||||
void PlotSignal();
|
||||
void CamOpenedSignal();
|
||||
void CamClosedSignal();
|
||||
void VideoRecordingStartedSignal(); // 录制开始信号
|
||||
void VideoRecordingStoppedSignal(); // 录制停止信号
|
||||
void photoSavedSignal(const QString& filePath); // 照片保存成功信号
|
||||
|
||||
public slots:
|
||||
void OpenCamera();
|
||||
void OpenCamera_callback();//不使用信号而使用回调函数来通知界面刷新视频
|
||||
void CloseCamera();
|
||||
|
||||
signals:
|
||||
void PlotSignal();
|
||||
|
||||
void CamOpenedSignal();
|
||||
void CamClosedSignal();
|
||||
void startPhotoSaveTimer();
|
||||
void stopPhotoSaveTimer();
|
||||
};
|
||||
#endif // !RGBCAMERAOPERATION_H
|
||||
|
||||
@ -109,7 +109,7 @@ QImage ImageProcessor::Mat2QImage(cv::Mat cvImg)//https://www.cnblogs.com/annt/p
|
||||
QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
return qImg;
|
||||
return qImg.copy(); // 返回独立数据副本,避免cvImg被覆盖导致QImage数据失效
|
||||
}
|
||||
|
||||
cv::Mat ImageProcessor::CStretchDeal(const cv::Mat img, const uint minnum, const uint maxnum)
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>416</width>
|
||||
<height>219</height>
|
||||
<width>489</width>
|
||||
<height>329</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -70,18 +70,50 @@ QPushButton:pressed
|
||||
}</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QLabel {
|
||||
color: rgb(255, 255, 255);
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>数据路径</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="dataFolderLineEdit">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QLineEdit {
|
||||
background-color: #142D7F;
|
||||
color: #e6eeff;
|
||||
border: 1px solid #2f6bff;
|
||||
border-radius: 6px;
|
||||
padding: 4px 8px;
|
||||
min-width: 70px;
|
||||
min-height: 20px;
|
||||
font-size: 13px;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>D:\</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="dataFolderBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
@ -96,6 +128,19 @@ QPushButton:pressed
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
@ -165,7 +210,7 @@ QPushButton:pressed
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="4" column="1">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@ -178,6 +223,44 @@ QPushButton:pressed
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QLabel {
|
||||
color: rgb(255, 255, 255);
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>文件名</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="fileNameLineEdit">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QLineEdit {
|
||||
background-color: #142D7F;
|
||||
color: #e6eeff;
|
||||
border: 1px solid #2f6bff;
|
||||
border-radius: 6px;
|
||||
padding: 4px 8px;
|
||||
min-width: 70px;
|
||||
min-height: 20px;
|
||||
font-size: 13px;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>test</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
#include "rgbCameraWindow.h"
|
||||
#include <Qthread>
|
||||
#include "rgbCameraWindow.h"
|
||||
#include <QThread>
|
||||
#include <QFileDialog>
|
||||
#include "AppSettings.h"
|
||||
|
||||
rgbCameraWindow::rgbCameraWindow(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_captureCoordinator(nullptr)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
@ -11,22 +14,185 @@ rgbCameraWindow::rgbCameraWindow(QWidget* parent)
|
||||
m_RgbCamera->moveToThread(m_RgbCameraThread);
|
||||
m_RgbCameraThread->start();
|
||||
|
||||
connect(ui.open_rgb_camera_btn, SIGNAL(clicked()), m_RgbCamera, SLOT(OpenCamera()));//ʹ<><CAB9><EFBFBD>ź<EFBFBD>֪ͨ<CDA8><D6AA><EFBFBD>̣߳<DFB3>ui<75>̣߳<DFB3>ˢ<EFBFBD><CBA2><EFBFBD><EFBFBD>Ƶ <20><> <20>ɹ<EFBFBD><C9B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǽ<EFBFBD><C7BD>濨<EFBFBD><E6BFA8>
|
||||
connect(m_RgbCamera, SIGNAL(PlotSignal()), this, SIGNAL(PlotRgbImageSignal()));
|
||||
|
||||
//m_RgbCamera->setCallback(onPlotRgbImage);
|
||||
//connect(this->ui.open_rgb_camera_btn, SIGNAL(clicked()), m_RgbCamera, SLOT(OpenCamera_callback()));//ʹ<>ûص<C3BB><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˢ<EFBFBD><CBA2><EFBFBD><EFBFBD><EFBFBD>̣߳<DFB3>ui<75>̣߳<DFB3><CCA3>ϵ<EFBFBD><CFB5><EFBFBD>Ƶ <20><> ʧ<><CAA7>
|
||||
|
||||
connect(ui.close_rgb_camera_btn, SIGNAL(clicked()), this, SLOT(onCloseRgbCamera()));//<2F>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD>
|
||||
connect(ui.open_rgb_camera_btn, &QPushButton::clicked,
|
||||
this, [this]() { if (m_captureCoordinator) m_captureCoordinator->openCamera(); });
|
||||
connect(m_RgbCamera, SIGNAL(CamClosedSignal()), this, SIGNAL(CamClosedSignal()));
|
||||
|
||||
connect(ui.close_rgb_camera_btn, &QPushButton::clicked,
|
||||
this, [this]() { if (m_captureCoordinator) m_captureCoordinator->closeCamera(); });
|
||||
|
||||
connect(this->ui.dataFolderBtn, SIGNAL(clicked()), this, SLOT(onSelectDataFolder()));
|
||||
|
||||
connect(this->ui.take_video_btn, &QPushButton::clicked,
|
||||
this, [this]() {
|
||||
if (m_captureCoordinator)
|
||||
{
|
||||
if (!m_captureCoordinator->isCapturing())
|
||||
m_captureCoordinator->startVideoCapture();
|
||||
else if (m_captureCoordinator->getCurrentMode() == RgbCameraCaptureCoordinator::Video)
|
||||
m_captureCoordinator->stopVideoCapture();
|
||||
}
|
||||
});
|
||||
connect(this->ui.take_photo_btn, &QPushButton::clicked,
|
||||
this, [this]() {
|
||||
if (m_captureCoordinator)
|
||||
{
|
||||
if (!m_captureCoordinator->isCapturing())
|
||||
m_captureCoordinator->startPhotoCapture();
|
||||
else if (m_captureCoordinator->getCurrentMode() == RgbCameraCaptureCoordinator::Photo)
|
||||
m_captureCoordinator->stopPhotoCapture();
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui.fileNameLineEdit, &QLineEdit::textChanged, this, &rgbCameraWindow::onFileNameChanged);
|
||||
|
||||
setupCaptureCoordinator();
|
||||
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
rgbCameraWindow::~rgbCameraWindow()
|
||||
{
|
||||
delete m_captureCoordinator;
|
||||
m_captureCoordinator = nullptr;
|
||||
|
||||
m_RgbCameraThread->quit();
|
||||
m_RgbCameraThread->wait();
|
||||
delete m_RgbCamera;
|
||||
delete m_RgbCameraThread;
|
||||
}
|
||||
|
||||
void rgbCameraWindow::onCloseRgbCamera()
|
||||
void rgbCameraWindow::setupCaptureCoordinator()
|
||||
{
|
||||
//std::cout << "<22>ر<EFBFBD><D8B1><EFBFBD>Ƶ+++++++++++++++++++++++++++++++++++++++++++" << std::endl;
|
||||
m_RgbCamera->CloseCamera();
|
||||
m_captureCoordinator = new RgbCameraCaptureCoordinator(m_RgbCamera, this);
|
||||
|
||||
connect(m_captureCoordinator, &RgbCameraCaptureCoordinator::captureStarted,
|
||||
this, &rgbCameraWindow::onCaptureStarted);
|
||||
connect(m_captureCoordinator, &RgbCameraCaptureCoordinator::captureStopped,
|
||||
this, &rgbCameraWindow::onCaptureStopped);
|
||||
connect(m_captureCoordinator, &RgbCameraCaptureCoordinator::cameraOpened,
|
||||
this, &rgbCameraWindow::onCameraOpened);
|
||||
connect(m_captureCoordinator, &RgbCameraCaptureCoordinator::cameraClosed,
|
||||
this, &rgbCameraWindow::onCameraClosed);
|
||||
connect(m_captureCoordinator, &RgbCameraCaptureCoordinator::cameraOpenFailed,
|
||||
this, &rgbCameraWindow::onCameraOpenFailed);
|
||||
connect(m_captureCoordinator, &RgbCameraCaptureCoordinator::photoCaptured,
|
||||
this, &rgbCameraWindow::onPhotoCaptured);
|
||||
connect(m_RgbCamera, &RgbCameraOperation::photoSavedSignal,
|
||||
this, &rgbCameraWindow::onPhotoSaved);
|
||||
}
|
||||
|
||||
void rgbCameraWindow::startVideoCapture()
|
||||
{
|
||||
if (m_captureCoordinator)
|
||||
{
|
||||
m_captureCoordinator->startVideoCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void rgbCameraWindow::stopVideoCapture()
|
||||
{
|
||||
if (m_captureCoordinator)
|
||||
{
|
||||
m_captureCoordinator->stopVideoCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void rgbCameraWindow::startPhotoCapture()
|
||||
{
|
||||
if (m_captureCoordinator)
|
||||
{
|
||||
m_captureCoordinator->startPhotoCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void rgbCameraWindow::stopPhotoCapture()
|
||||
{
|
||||
if (m_captureCoordinator)
|
||||
{
|
||||
m_captureCoordinator->stopPhotoCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void rgbCameraWindow::onCaptureStarted(RgbCameraCaptureCoordinator::CaptureMode mode)
|
||||
{
|
||||
if (mode == RgbCameraCaptureCoordinator::Video)
|
||||
{
|
||||
ui.take_video_btn->setText(QString::fromLocal8Bit("停止录制"));
|
||||
}
|
||||
else if (mode == RgbCameraCaptureCoordinator::Photo)
|
||||
{
|
||||
ui.take_photo_btn->setText(QString::fromLocal8Bit("采集中..."));
|
||||
}
|
||||
}
|
||||
|
||||
void rgbCameraWindow::onCaptureStopped(RgbCameraCaptureCoordinator::CaptureMode mode)
|
||||
{
|
||||
if (mode == RgbCameraCaptureCoordinator::Video)
|
||||
{
|
||||
ui.take_video_btn->setText(QString::fromLocal8Bit("录制视频"));
|
||||
}
|
||||
else if (mode == RgbCameraCaptureCoordinator::Photo)
|
||||
{
|
||||
ui.take_photo_btn->setText(QString::fromLocal8Bit("拍照"));
|
||||
}
|
||||
}
|
||||
|
||||
void rgbCameraWindow::onCameraOpened()
|
||||
{
|
||||
}
|
||||
|
||||
void rgbCameraWindow::onCameraClosed()
|
||||
{
|
||||
}
|
||||
|
||||
void rgbCameraWindow::onCameraOpenFailed(const QString& error)
|
||||
{
|
||||
//QMessageBox::warning(this, QString::fromLocal8Bit("相机打开失败"), error);
|
||||
}
|
||||
|
||||
void rgbCameraWindow::onPhotoCaptured(const QString& filePath)
|
||||
{
|
||||
}
|
||||
|
||||
void rgbCameraWindow::onPhotoSaved(const QString& filePath)
|
||||
{
|
||||
// 可在此更新界面,例如显示已保存的照片数量
|
||||
std::cout << "照片已保存: " << filePath.toStdString() << std::endl;
|
||||
}
|
||||
|
||||
void rgbCameraWindow::loadSettings()
|
||||
{
|
||||
QString folder = AppSettings::instance().rgbCameraDataFolder();
|
||||
setDataFolder(folder);
|
||||
setFileName(AppSettings::instance().rgbCameraFileName());
|
||||
}
|
||||
|
||||
void rgbCameraWindow::onSelectDataFolder()
|
||||
{
|
||||
QString dir = QFileDialog::getExistingDirectory(this,
|
||||
QString::fromLocal8Bit("选择数据保存路径"),
|
||||
ui.dataFolderLineEdit->text());
|
||||
|
||||
setDataFolder(dir);
|
||||
}
|
||||
|
||||
void rgbCameraWindow::setDataFolder(QString dir)
|
||||
{
|
||||
if (!dir.isEmpty())
|
||||
{
|
||||
ui.dataFolderLineEdit->setText(dir);
|
||||
}
|
||||
}
|
||||
|
||||
void rgbCameraWindow::setFileName(QString name)
|
||||
{
|
||||
ui.fileNameLineEdit->setText(name);
|
||||
}
|
||||
|
||||
void rgbCameraWindow::onFileNameChanged(const QString& text)
|
||||
{
|
||||
AppSettings::instance().setRgbCameraFileName(text);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QNetworkRequest>
|
||||
@ -8,6 +8,7 @@
|
||||
#include "ui_rgbCamera.h"
|
||||
|
||||
#include "RgbCameraOperation.h"
|
||||
#include "RgbCameraCaptureCoordinator.h"
|
||||
|
||||
class rgbCameraWindow : public QDialog
|
||||
{
|
||||
@ -19,16 +20,41 @@ public:
|
||||
|
||||
RgbCameraOperation* m_RgbCamera;
|
||||
|
||||
public Q_SLOTS:
|
||||
void onCloseRgbCamera();
|
||||
// 视频采集控制
|
||||
void startVideoCapture();
|
||||
void stopVideoCapture();
|
||||
|
||||
signals:
|
||||
// 照片采集控制
|
||||
void startPhotoCapture();
|
||||
void stopPhotoCapture();
|
||||
|
||||
public Q_SLOTS:
|
||||
void onSelectDataFolder();
|
||||
void onFileNameChanged(const QString& text);
|
||||
|
||||
Q_SIGNALS:
|
||||
void PlotRgbImageSignal();
|
||||
void CamClosedSignal();
|
||||
|
||||
private Q_SLOTS:
|
||||
// 协调器信号处理
|
||||
void onCaptureStarted(RgbCameraCaptureCoordinator::CaptureMode mode);
|
||||
void onCaptureStopped(RgbCameraCaptureCoordinator::CaptureMode mode);
|
||||
void onCameraOpened();
|
||||
void onCameraClosed();
|
||||
void onCameraOpenFailed(const QString& error);
|
||||
void onPhotoCaptured(const QString& filePath);
|
||||
void onPhotoSaved(const QString& filePath);
|
||||
|
||||
private:
|
||||
Ui::rgbCameraClass ui;
|
||||
|
||||
|
||||
QThread* m_RgbCameraThread;//rgb<67><62><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡͼ<C8A1><CDBC><EFBFBD>߳<EFBFBD>
|
||||
QThread* m_RgbCameraThread;//rgb相机获取图像线程
|
||||
RgbCameraCaptureCoordinator* m_captureCoordinator;
|
||||
|
||||
void setDataFolder(QString dir);
|
||||
void setFileName(QString name);
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
void setupCaptureCoordinator();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user