Compare commits
6 Commits
9307947ed0
...
0562e8592c
| Author | SHA1 | Date | |
|---|---|---|---|
| 0562e8592c | |||
| 9bc2133e24 | |||
| e552dc2ed5 | |||
| 2e7bf50737 | |||
| 1a64fb32e3 | |||
| ebc39f9f9d |
@ -120,6 +120,41 @@ 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_rgb_data").toString();
|
||||
}
|
||||
|
||||
void AppSettings::setRgbCameraFileName(const QString& name)
|
||||
{
|
||||
m_settings.setValue("RgbCamera/FileName", name);
|
||||
}
|
||||
|
||||
QString AppSettings::fodisCameraFileName() const
|
||||
{
|
||||
return m_settings.value("FodisCamera/FileName", "test_fodis_data").toString();
|
||||
}
|
||||
|
||||
void AppSettings::setFodisCameraFileName(const QString& name)
|
||||
{
|
||||
m_settings.setValue("FodisCamera/FileName", name);
|
||||
}
|
||||
|
||||
double AppSettings::scanSpeed() const
|
||||
{
|
||||
return m_settings.value("OneMotorControl/ScanSpeed", kDefaultScanSpeed).toDouble();
|
||||
|
||||
@ -38,6 +38,16 @@ 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);
|
||||
|
||||
QString fodisCameraFileName() const;
|
||||
void setFodisCameraFileName(const QString& name);
|
||||
|
||||
// 扫描速度
|
||||
double scanSpeed() const;
|
||||
void setScanSpeed(double value);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include "CaptureCoordinator.h"
|
||||
#include <algorithm>
|
||||
|
||||
TwoMotionCaptureCoordinator::TwoMotionCaptureCoordinator(
|
||||
IrisMultiMotorController* motorCtrl,
|
||||
@ -458,7 +459,9 @@ OneMotionCaptureCoordinator::OneMotionCaptureCoordinator(
|
||||
connect(this, &OneMotionCaptureCoordinator::stopRecordHSISignal,
|
||||
m_cameraCtrl, &ImagerOperationBase::stop_record);
|
||||
connect(m_cameraCtrl, &ImagerOperationBase::RecordFinishedSignal_WhenFrameNumberMeet,
|
||||
this, &OneMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet);
|
||||
this, &OneMotionCaptureCoordinator::handleHyperImagerCaptureComplete);
|
||||
connect(m_cameraCtrl, &ImagerOperationBase::RecordFinishedSignal_WhenFrameNumberNotMeet,
|
||||
this, &OneMotionCaptureCoordinator::handleHyperImagerCaptureComplete);
|
||||
}
|
||||
|
||||
OneMotionCaptureCoordinator::~OneMotionCaptureCoordinator()
|
||||
@ -497,12 +500,9 @@ void OneMotionCaptureCoordinator::stopStepMotion()
|
||||
{
|
||||
m_cameraCtrl->stop_record();
|
||||
}
|
||||
|
||||
emit stopMotorSignal(0);
|
||||
m_isHypercamStopRecord = true;
|
||||
}
|
||||
|
||||
void OneMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet()
|
||||
void OneMotionCaptureCoordinator::handleHyperImagerCaptureComplete()
|
||||
{
|
||||
emit stopMotorSignal(0);
|
||||
m_isHypercamStopRecord = true;
|
||||
@ -587,13 +587,11 @@ void OneMotionCaptureCoordinator::handleMotorStoped(int motorID, double pos)
|
||||
}
|
||||
move2LocBeforeStart();
|
||||
|
||||
emit sequenceComplete_cam_stop_before_motorback(0);
|
||||
emit sequenceCompleteSignal_hyperImagerStopRecord(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// emit sequenceComplete last: the slot connected to it may delete this object,
|
||||
// so no member access is allowed after this point.
|
||||
emit sequenceComplete(0);
|
||||
emit sequenceCompleteSignal_motorBack2Origin(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -972,3 +970,265 @@ double OneMotionCoordinator::getErrorRate(double targetLoc, double actualLoc)
|
||||
|
||||
return errorRate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
OneMotorMultiPosCoordinator::OneMotorMultiPosCoordinator(
|
||||
IrisMultiMotorController* motorCtrl,
|
||||
ImagerOperationBase* cameraCtrl,
|
||||
QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_motorCtrl(motorCtrl)
|
||||
, m_cameraCtrl(cameraCtrl)
|
||||
, m_currentPos(0)
|
||||
, m_isRunning(false)
|
||||
, m_isZeroing(false)
|
||||
{
|
||||
//这些信号槽是按照逻辑顺序的
|
||||
connect(this, SIGNAL(moveTo(int, double, double, int)),
|
||||
m_motorCtrl, SLOT(moveTo(int, double, double, int)));
|
||||
|
||||
connect(this, &OneMotorMultiPosCoordinator::zeroStart,
|
||||
m_motorCtrl, &IrisMultiMotorController::zeroStart);
|
||||
|
||||
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal,
|
||||
this, &OneMotorMultiPosCoordinator::handlePositionReached);
|
||||
//connect(m_motorCtrl, &IrisMultiMotorController::moveFailed,
|
||||
// this, &OneMotorMultiPosCoordinator::handleError);
|
||||
|
||||
connect(this, &OneMotorMultiPosCoordinator::startAutoExposureSignal,
|
||||
m_cameraCtrl, &ImagerOperationBase::auto_exposure);
|
||||
|
||||
connect(m_cameraCtrl, &ImagerOperationBase::autoExposureSignal,
|
||||
this, &OneMotorMultiPosCoordinator::onAutoExposureFinished);
|
||||
//connect(m_cameraCtrl, &ImagerOperationBase::captureFailed,
|
||||
// this, &OneMotorMultiPosCoordinator::handleError);
|
||||
}
|
||||
|
||||
OneMotorMultiPosCoordinator::~OneMotorMultiPosCoordinator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OneMotorMultiPosCoordinator::startStepMotion(double speed, std::vector<double> locations)
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
if (locations.empty())
|
||||
{
|
||||
emit sequenceComplete(1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (m_isRunning)
|
||||
{
|
||||
emit errorOccurred("Sequence already running");
|
||||
return;
|
||||
}
|
||||
m_locations = locations;
|
||||
|
||||
m_counter = 0;
|
||||
|
||||
m_positionData.clear();
|
||||
|
||||
m_speed = speed;
|
||||
m_iStepIntervalRealTime = 1;
|
||||
|
||||
m_isRunning = true;
|
||||
m_isZeroing = true;
|
||||
|
||||
// 先执行归零操作
|
||||
emit zeroStart(0);
|
||||
qDebug() << "OneMotorMultiPosCoordinator::startStepMotion: Zeroing started.";
|
||||
}
|
||||
|
||||
void OneMotorMultiPosCoordinator::startMotionSequence()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
m_isZeroing = false;
|
||||
qDebug() << "OneMotorMultiPosCoordinator::startMotionSequence: Zeroing complete. Starting motion sequence.";
|
||||
|
||||
processNextPosition();
|
||||
}
|
||||
|
||||
void OneMotorMultiPosCoordinator::handleZeroComplete(int motorID, double pos)
|
||||
{
|
||||
if (!m_isRunning || !m_isZeroing) return;
|
||||
|
||||
// 归零完成,开始分步运动
|
||||
startMotionSequence();
|
||||
}
|
||||
|
||||
void OneMotorMultiPosCoordinator::stopStepMotion()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
m_isRunning = false;
|
||||
emit sequenceStopped();
|
||||
}
|
||||
|
||||
QVector<PositionsLogData> OneMotorMultiPosCoordinator::getAllPositionData() const
|
||||
{
|
||||
//QMutexLocker locker(&m_dataMutex);
|
||||
return m_positionData;
|
||||
}
|
||||
|
||||
bool OneMotorMultiPosCoordinator::saveToCsv(const QString& filename)
|
||||
{
|
||||
//QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
QFile file(filename);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&file);
|
||||
out << "Timestamp,targetPosition,ActualPosition,exposureTime\n";
|
||||
|
||||
for (const auto& data : m_positionData)
|
||||
{
|
||||
out << data.timestamp.toString("yyyy-MM-dd HH:mm:ss.zzz") << ","
|
||||
<< QString::number(data.targetPosition, 'f', 4) << ","
|
||||
<< QString::number(data.actualPosition, 'f', 4) << ","
|
||||
<< QString::number(data.exposureTime, 'f', 4) << "\n";
|
||||
}
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void OneMotorMultiPosCoordinator::handlePositionReached(int motorID, double pos)
|
||||
{
|
||||
if (!m_isRunning) return;
|
||||
|
||||
// 如果正在等待归零完成,调用归零完成处理
|
||||
if (m_isZeroing)
|
||||
{
|
||||
handleZeroComplete(motorID, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
//验证马达运动位置是否到达指定位置
|
||||
//if (pos != m_currentPos) return;
|
||||
|
||||
// 记录位置信息
|
||||
PositionsLogData data;
|
||||
data.targetPosition = m_currentPos;
|
||||
data.actualPosition = pos;
|
||||
data.timestamp = QDateTime::currentDateTime();
|
||||
data.frameRate = 10;
|
||||
m_positionData.append(data);
|
||||
|
||||
// 开始自动曝光
|
||||
m_cameraCtrl->setFramerate(m_positionData.last().frameRate);
|
||||
emit startAutoExposureSignal();
|
||||
}
|
||||
|
||||
void OneMotorMultiPosCoordinator::onAutoExposureFinished(double exposureTime)
|
||||
{
|
||||
if (!m_isRunning) return;
|
||||
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
// 在保证曝光质量的前提下,尽量提高帧率,帧率下限为10hz
|
||||
|
||||
m_positionData.last().exposureTime = exposureTime;
|
||||
|
||||
std::cout << "第" << m_counter << "次曝光:" << std::endl;
|
||||
std::cout << "目标位置:" << m_positionData.last().targetPosition << std::endl;
|
||||
std::cout << "实际位置:" << m_positionData.last().actualPosition << std::endl;
|
||||
std::cout << "曝光时间:" << m_positionData.last().exposureTime << std::endl;
|
||||
|
||||
// 如果曝光时间过低(< 2ms),基于曝光时间计算新的帧率并重新进行自动曝光
|
||||
if (exposureTime < 2.0) {
|
||||
int currentFrameRate = m_positionData.last().frameRate;
|
||||
|
||||
// 基于曝光时间计算理论最大帧率:fps = 1000 / exposureTime(ms)
|
||||
// 乘以0.8作为安全系数,确保不会达到极限
|
||||
int newFrameRate = static_cast<int>((1000.0 / exposureTime) * 0.8);
|
||||
|
||||
// 设置合理的帧率范围:[currentFrameRate + 10, min(200, newFrameRate)]
|
||||
newFrameRate = std::max(currentFrameRate + 10, newFrameRate);
|
||||
newFrameRate = std::min(newFrameRate, 200);
|
||||
|
||||
m_positionData.last().frameRate = newFrameRate;
|
||||
|
||||
std::cout << "曝光时间过低,基于曝光时间计算新帧率:" << currentFrameRate << " -> " << newFrameRate << std::endl;
|
||||
std::cout << "(曝光时间 " << exposureTime << "ms -> 理论最大帧率 " << (1000.0 / exposureTime) << "fps)" << std::endl;
|
||||
|
||||
m_cameraCtrl->setFramerate(newFrameRate);
|
||||
}
|
||||
|
||||
processNextPosition();
|
||||
}
|
||||
|
||||
void OneMotorMultiPosCoordinator::handleError(const QString& error)
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
m_isRunning = false;
|
||||
emit errorOccurred(error);
|
||||
}
|
||||
|
||||
void OneMotorMultiPosCoordinator::processNextPosition()
|
||||
{
|
||||
if (!m_isRunning) return;
|
||||
|
||||
if (m_locations.empty())
|
||||
{
|
||||
m_isRunning = false;
|
||||
emit sequenceComplete(0);
|
||||
|
||||
// 找到曝光时间最大的那组数据
|
||||
double maxExposureTime = 0.0;
|
||||
double maxFrameRate = 10;
|
||||
for (const auto& data : m_positionData) {
|
||||
if (data.exposureTime > maxExposureTime) {
|
||||
maxExposureTime = data.exposureTime;
|
||||
maxFrameRate = data.frameRate;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "自动曝光完成,使用最大曝光时间参数:" << std::endl;
|
||||
std::cout << " 曝光时间:" << maxExposureTime << "ms" << std::endl;
|
||||
std::cout << " 帧率:" << maxFrameRate << "Hz" << std::endl;
|
||||
|
||||
emit hyperAutoExposureDoneSignal(maxExposureTime, maxFrameRate);
|
||||
m_cameraCtrl->setIntegrationTime(maxExposureTime);
|
||||
m_cameraCtrl->setFramerate(maxFrameRate);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_currentPos = m_locations.front();
|
||||
m_locations.erase(m_locations.begin());
|
||||
|
||||
emit moveTo(0, m_currentPos, m_speed, 1000);
|
||||
}
|
||||
|
||||
@ -141,11 +141,11 @@ public slots:
|
||||
void startStepMotion(OneMotionCapturePathLine pathLine);
|
||||
void stopStepMotion();
|
||||
|
||||
void handleCaptureCompleteWhenFrameNumberMeet();
|
||||
void handleHyperImagerCaptureComplete();
|
||||
|
||||
signals:
|
||||
void sequenceComplete_cam_stop_before_motorback(int);
|
||||
void sequenceComplete(int);
|
||||
void sequenceCompleteSignal_hyperImagerStopRecord(int);
|
||||
void sequenceCompleteSignal_motorBack2Origin(int);
|
||||
void errorOccurred(const QString& error);
|
||||
void moveTo(int, double, double, int);
|
||||
void moveSignal(int, bool, double, int);
|
||||
@ -300,3 +300,75 @@ private:
|
||||
int m_retryTimes;
|
||||
bool m_reached;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 数据记录结构体
|
||||
struct PositionsLogData
|
||||
{
|
||||
double targetPosition; // 目标位置
|
||||
double actualPosition; // 实际马达位置
|
||||
double frameRate; // 帧率
|
||||
double exposureTime; //
|
||||
QDateTime timestamp; // 时间戳
|
||||
|
||||
PositionsLogData(double target = 0, double actual = 0.0, double exposure = 0.0, double frameRate = 10.0)
|
||||
: targetPosition(target), actualPosition(actual), frameRate(frameRate),
|
||||
exposureTime(exposure ), timestamp(QDateTime::currentDateTime()) {
|
||||
}
|
||||
};
|
||||
|
||||
// 协调控制器
|
||||
class OneMotorMultiPosCoordinator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OneMotorMultiPosCoordinator(IrisMultiMotorController* motorCtrl,
|
||||
ImagerOperationBase* cameraCtrl,
|
||||
QObject* parent = nullptr);
|
||||
~OneMotorMultiPosCoordinator();
|
||||
|
||||
QVector<PositionsLogData> getAllPositionData() const;
|
||||
bool saveToCsv(const QString& filename);
|
||||
|
||||
public slots:
|
||||
void startStepMotion(double speed, std::vector<double> locations);
|
||||
void stopStepMotion();
|
||||
|
||||
signals:
|
||||
void progressChanged(int progress);
|
||||
void sequenceComplete(int status);
|
||||
void sequenceStopped();
|
||||
void errorOccurred(const QString& error);
|
||||
void moveTo(int, double, double, int);
|
||||
void startAutoExposureSignal();
|
||||
void zeroStart(int motorID);
|
||||
|
||||
void hyperAutoExposureDoneSignal(double exposureTime, double frameRate);
|
||||
|
||||
private slots:
|
||||
void handlePositionReached(int motorID, double pos);
|
||||
void onAutoExposureFinished(double exposureTime);
|
||||
void handleError(const QString& error);
|
||||
void handleZeroComplete(int motorID, double pos);
|
||||
|
||||
private:
|
||||
void processNextPosition();
|
||||
void startMotionSequence();
|
||||
|
||||
IrisMultiMotorController* m_motorCtrl;
|
||||
ImagerOperationBase* m_cameraCtrl;
|
||||
QVector<PositionsLogData> m_positionData;
|
||||
mutable QMutex m_dataMutex;
|
||||
|
||||
double m_currentPos;
|
||||
bool m_isRunning;
|
||||
double m_speed;
|
||||
|
||||
int m_iStepInterval;
|
||||
int m_iStepIntervalRealTime;
|
||||
int m_counter;
|
||||
bool m_isZeroing;
|
||||
|
||||
std::vector<double> m_locations;
|
||||
};
|
||||
|
||||
@ -50,7 +50,7 @@ private:
|
||||
|
||||
public slots:
|
||||
virtual void recordDark(QString path) = 0;
|
||||
virtual void recordTarget(int recordTimes, QString path) = 0;
|
||||
virtual void recordTarget2csv(int recordTimes, QString path) = 0;
|
||||
virtual void autoExpose() = 0;
|
||||
|
||||
signals:
|
||||
|
||||
@ -27,10 +27,9 @@ FodisWindow::FodisWindow(QWidget* parent)
|
||||
|
||||
connect(this->ui.dataFolderBtn, SIGNAL(clicked()), this, SLOT(onSelectDataFolder()));
|
||||
|
||||
// 初始化数据保存路径显示(从 AppSettings 恢复或使用默认)
|
||||
ui.dataFolderLineEdit->setText(AppSettings::instance().depthCameraDataFolder());
|
||||
connect(ui.fileNameLineEdit, &QLineEdit::textChanged, this, &FodisWindow::onFileNameChanged);
|
||||
|
||||
setDataFolder(AppSettings::instance().FiberImagerDataFolder());
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
FodisWindow::~FodisWindow()
|
||||
@ -41,6 +40,12 @@ FodisWindow::~FodisWindow()
|
||||
m_JinspFiberImagerOperation = nullptr;
|
||||
}
|
||||
|
||||
void FodisWindow::loadSettings()
|
||||
{
|
||||
ui.dataFolderLineEdit->setText(AppSettings::instance().FiberImagerDataFolder());
|
||||
ui.fileNameLineEdit->setText(AppSettings::instance().fodisCameraFileName());
|
||||
}
|
||||
|
||||
void FodisWindow::onSelectDataFolder()
|
||||
{
|
||||
QString dir = QFileDialog::getExistingDirectory(this,
|
||||
@ -59,6 +64,17 @@ void FodisWindow::setDataFolder(QString dir)
|
||||
}
|
||||
}
|
||||
|
||||
void FodisWindow::setFileName(QString name)
|
||||
{
|
||||
ui.fileNameLineEdit->setText(name);
|
||||
AppSettings::instance().setFodisCameraFileName(name);
|
||||
}
|
||||
|
||||
void FodisWindow::onFileNameChanged(const QString& text)
|
||||
{
|
||||
AppSettings::instance().setFodisCameraFileName(text);
|
||||
}
|
||||
|
||||
void FodisWindow::setCaptureInterval(int captureIntervalSeconds)
|
||||
{
|
||||
m_JinspFiberImagerOperation->setCaptureInterval(captureIntervalSeconds);
|
||||
@ -69,11 +85,24 @@ void FodisWindow::openFiberImager()
|
||||
openFiberImager_expose_record("pos_null");
|
||||
}
|
||||
|
||||
void FodisWindow::openFiberImager_expose_record(QString posInfo)
|
||||
void FodisWindow::openFiberImager_expose_record(QString posInfo, QString dataFolder)
|
||||
{
|
||||
setDataFolder(dataFolder);
|
||||
setFileName(posInfo);
|
||||
|
||||
if (!m_JinspFiberImagerOperation->getRecordStatus())
|
||||
{
|
||||
emit openFiberImagerSignal(posInfo);
|
||||
QString folder = AppSettings::instance().FiberImagerDataFolder();
|
||||
QDir dir(folder);
|
||||
if (!dir.exists())
|
||||
{
|
||||
dir.mkpath(".");
|
||||
}
|
||||
QString eventPrefix = posInfo.isEmpty() ? "default" : posInfo;
|
||||
QString dateStr = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss");
|
||||
QString m_qstrFullFileName = folder + QDir::separator() + dateStr + "_" + eventPrefix + "_fodis_data.dat";
|
||||
|
||||
emit openFiberImagerSignal(m_qstrFullFileName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -31,15 +31,17 @@ public:
|
||||
|
||||
public Q_SLOTS:
|
||||
void openFiberImager();
|
||||
void openFiberImager_expose_record(QString posInfo);
|
||||
void openFiberImager_expose_record(QString posInfo, QString dataFolder = "");
|
||||
void onCamOpened();
|
||||
void closeFiberImager();
|
||||
void onCamClosed();
|
||||
|
||||
void onSelectDataFolder();
|
||||
void onFileNameChanged(const QString& text);
|
||||
void setFileName(QString name);
|
||||
|
||||
signals:
|
||||
void openFiberImagerSignal(QString posInfo);
|
||||
void openFiberImagerSignal(QString filePath);
|
||||
void PlotSpectralSignal();
|
||||
void FiberImagerClosedSignal();
|
||||
|
||||
@ -53,4 +55,6 @@ private:
|
||||
QThread* m_FiberImagerThread;
|
||||
|
||||
JinspFiberImager* m_JinspFiberImagerOperation;
|
||||
|
||||
void loadSettings();
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -10,34 +10,108 @@
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QDir>
|
||||
#include <QStateMachine>
|
||||
#include <QSignalTransition>
|
||||
#include <QFinalState>
|
||||
#include <QTimer>
|
||||
#include <QSerialPort>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "ui_gonggashanCtl.h"
|
||||
|
||||
#include "CommunicationViaTCP.h"
|
||||
#include "AppSettings.h"
|
||||
|
||||
class GonggashanTaskScheduler : public QObject
|
||||
class GsbGpsParse;
|
||||
class GsbGpsReader;
|
||||
|
||||
// ============ 执行阶段枚举 ============
|
||||
enum class GonggaShanExecPhase {
|
||||
Idle, // 空闲
|
||||
Preparation, // 准备阶段
|
||||
HyperExposure, // 高光谱传感器曝光
|
||||
FiberExposure, // 光纤光谱仪曝光
|
||||
GpsAcquisition, // 获取GPS位置
|
||||
MotorCalc, // 计算马达速度
|
||||
DataCollection, // 开始采集:高光谱、FODIS、rgb相机
|
||||
Completed // 完成
|
||||
};
|
||||
|
||||
// ============ 任务执行器 ============
|
||||
class GonggashanTaskExecutor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class TaskState
|
||||
{
|
||||
Idle,
|
||||
Running
|
||||
};
|
||||
explicit GonggashanTaskExecutor(QObject* parent = nullptr);
|
||||
~GonggashanTaskExecutor();
|
||||
|
||||
explicit GonggashanTaskScheduler(QObject* parent = nullptr);
|
||||
~GonggashanTaskScheduler();
|
||||
bool isRunning() const { return m_machine && m_machine->isRunning() && !m_machine->configuration().isEmpty(); }
|
||||
|
||||
bool isTaskRunning() const;
|
||||
void setTaskRunning(bool running);
|
||||
public slots:
|
||||
void start(const QString& posInfo);
|
||||
void stop();
|
||||
|
||||
Q_SIGNALS:
|
||||
void taskStateChanged(TaskState state);
|
||||
void onHyperExposureComplete(double exposureTime, double frameRate);
|
||||
void onFiberExposureComplete(double exposureTime);
|
||||
void onGpsAcquired(double latitude, double longitude, double altitude);
|
||||
void onMotorSpeedCalculated(double rotationSpeed);
|
||||
void onRcordComplete();
|
||||
|
||||
signals:
|
||||
void hyperAutoExposureSignal_gonggashan();
|
||||
void fiberExposureRecordSignal(QString posInfo, QString dataFolder);
|
||||
void gpsAcquisitionSignal();
|
||||
void motorSpeedSignal(double speed);
|
||||
void startCollectionSignal(const QString& posInfo, const QString& gpsData, double m_motorRotationSpeed, QString dataFolder);
|
||||
|
||||
void calculateMotorSpeedSignal(double hyperFrameRate);
|
||||
|
||||
void finished(bool success);
|
||||
void errorOccurred(const QString& error);
|
||||
|
||||
// ---- 以下为状态机内部信号,供 transition 使用 ----
|
||||
void taskStartRequested(const QString& posInfo);
|
||||
void preparationComplete();
|
||||
void hyperExposureDone();
|
||||
void fiberExposureDone();
|
||||
void gpsAcquisitionDone();
|
||||
void motorSpeedDone();
|
||||
void dataCollectionDone();
|
||||
void stopRequested();
|
||||
|
||||
protected:
|
||||
virtual bool preparationImpl();
|
||||
virtual bool hyperExposureImpl(int exposureTime);
|
||||
virtual bool fiberExposureImpl(int exposureTime);
|
||||
virtual bool gpsAcquisitionImpl(double lat, double lon, double alt);
|
||||
virtual bool motorCalcImpl();
|
||||
|
||||
private slots:
|
||||
void onFinalStateEntered();
|
||||
|
||||
private:
|
||||
TaskState m_taskState;
|
||||
void buildStateMachine();
|
||||
QState* currentState() const;
|
||||
void leavePhase(QState* state);
|
||||
|
||||
QString m_posInfo;
|
||||
QString m_gpsData;
|
||||
double m_motorRotationSpeed = 0.0;
|
||||
double m_hyperExposureTime = 0;
|
||||
double m_hyperFrameRate = 0;
|
||||
double m_fiberExposureTime = 0;
|
||||
bool m_stopRequested = false;
|
||||
QString m_todayDataFolder; // 当天日期的数据保存文件夹
|
||||
|
||||
// Qt State Machine
|
||||
QStateMachine* m_machine = nullptr;
|
||||
QState* m_hyperExposureState = nullptr;
|
||||
QState* m_fiberExposureState = nullptr;
|
||||
QState* m_gpsAcquisitionState = nullptr;
|
||||
QState* m_motorCalcState = nullptr;
|
||||
QState* m_dataCollectionState = nullptr;
|
||||
QFinalState* m_finalState = nullptr;
|
||||
};
|
||||
|
||||
class GonggaShanRecordCtl : public QDialog
|
||||
@ -55,8 +129,18 @@ public Q_SLOTS:
|
||||
void onFiberImagerExposureCompleteSignal(int exposureTime);
|
||||
|
||||
Q_SIGNALS:
|
||||
// Emitted when user changes any of the R/G/B wavelength values
|
||||
void startRcordSignal(QString posInfo);
|
||||
void gpsAcquisitionDoneSignal_gonggashan(double lat, double lon, double alt);
|
||||
|
||||
void calculateMotorSpeedDoneSignal_gonggashan(double rotationSpeed);
|
||||
|
||||
void hyperAutoExposureSignal_gonggashan();
|
||||
void hyperAutoExposureDoneSignal_gonggashan(double exposureTime, double frameRate);
|
||||
|
||||
void fiberExposureRecordSignal_gonggashan(QString posInfo, QString dataFolder);
|
||||
void fiberExposureDoneSignal_gonggashan(double exposureTime);
|
||||
|
||||
void startRcordSignal_gonggashan(const QString& posInfo, const QString& gpsData, double m_motorRotationSpeed, QString dataFolder);
|
||||
void recordFinishedSignal_gonggashan();
|
||||
|
||||
private Q_SLOTS:
|
||||
void startListen();
|
||||
@ -64,13 +148,202 @@ private Q_SLOTS:
|
||||
|
||||
void startRecord(int position);
|
||||
|
||||
// GonggashanTaskExecutor 反馈槽
|
||||
void onTaskExecutorFinished(bool success);
|
||||
|
||||
void onGpsAcquisition();
|
||||
void onCalculateMotorSpeed(double hyperFrameRate);
|
||||
|
||||
private:
|
||||
void logStatus(const QString& message, bool isHearderBlankLine = false, bool isTailBlankLine = false);
|
||||
|
||||
Ui::gongga_control ui;
|
||||
QPointer<MotorParams::CommunicationViaTCP> tcpServer6005;
|
||||
GonggashanTaskScheduler* m_taskScheduler;
|
||||
GonggashanTaskExecutor* m_taskExecutor; // 新增
|
||||
QString m_logFilePath;
|
||||
QFile m_logFile;
|
||||
QTextStream m_logStream;
|
||||
|
||||
// GPS 串口读取器
|
||||
GsbGpsReader* m_gpsReader = nullptr;
|
||||
};
|
||||
|
||||
// ============ USB GPS NMEA-0183 解析器 (G6301, COM17) ============
|
||||
class GsbGpsParse : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// GPS数据有效性状态
|
||||
enum class GpsStatus {
|
||||
Invalid, // 无效或未定位
|
||||
Valid, // 有效定位
|
||||
Differential // 差分定位
|
||||
};
|
||||
|
||||
// GPS解析数据结构
|
||||
struct GpsData {
|
||||
QString rawNmea; // 原始NMEA语句
|
||||
QString utcTime; // UTC时间 (HHMMSS.SSS)
|
||||
QString utcDate; // UTC日期 (DDMMYY)
|
||||
double latitude = 0.0; // 纬度 (十进制度)
|
||||
double longitude = 0.0; // 经度 (十进制度)
|
||||
double altitude = 0.0; // 高程 (米)
|
||||
int satelliteCount = 0; // 卫星数目
|
||||
GpsStatus status = GpsStatus::Invalid; // 定位状态
|
||||
bool isValid = false; // 综合有效性
|
||||
bool hasGga = false; // 是否已收到GPGGA语句
|
||||
bool hasRmc = false; // 是否已收到GPRMC语句
|
||||
};
|
||||
|
||||
explicit GsbGpsParse(QObject* parent = nullptr);
|
||||
~GsbGpsParse() = default;
|
||||
|
||||
// 设置最小卫星数目要求 (默认4颗)
|
||||
void setMinSatelliteCount(int count) { m_minSatelliteCount = count; }
|
||||
int minSatelliteCount() const { return m_minSatelliteCount; }
|
||||
|
||||
// 解析单条NMEA语句
|
||||
bool parseNmeaSentence(const QString& sentence);
|
||||
|
||||
// 获取当前解析的GPS数据
|
||||
const GpsData& gpsData() const { return m_gpsData; }
|
||||
|
||||
// 检查GPS数据是否有效
|
||||
bool isGpsDataValid() const;
|
||||
|
||||
// 格式化输出
|
||||
QString toDisplayString() const;
|
||||
|
||||
// 获取状态描述
|
||||
QString statusDescription() const;
|
||||
|
||||
signals:
|
||||
void gpsDataUpdated(const GpsData& data);
|
||||
void gpsStatusChanged(bool isValid);
|
||||
|
||||
private:
|
||||
// 解析 $GPGGA - GPS定位数据
|
||||
bool parseGpgga(const QStringList& fields);
|
||||
|
||||
// 解析 $GPRMC - 推荐最小定位数据
|
||||
bool parseGprmc(const QStringList& fields);
|
||||
|
||||
// NMEA校验
|
||||
bool validateNmeaChecksum(const QString& sentence);
|
||||
|
||||
// 转换纬度格式 (DDMM.MMMM -> DD.DDDDD)
|
||||
double convertLatitude(const QString& degMin, const QString& direction);
|
||||
|
||||
// 转换经度格式 (DDDMM.MMMM -> DDD.DDDDD)
|
||||
double convertLongitude(const QString& degMin, const QString& direction);
|
||||
|
||||
// 检查数据有效性
|
||||
void validateData();
|
||||
|
||||
GpsData m_gpsData;
|
||||
int m_minSatelliteCount = 4; // 默认要求至少4颗卫星
|
||||
QString m_pendingTime;
|
||||
QString m_pendingDate;
|
||||
};
|
||||
|
||||
// ============ USB GPS 串口读取器 (G6301, COM17) ============
|
||||
class GsbGpsReader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GsbGpsReader(QObject* parent = nullptr);
|
||||
~GsbGpsReader();
|
||||
|
||||
// 打开指定串口
|
||||
bool openPort(const QString& portName, qint32 baudRate = 4800);
|
||||
|
||||
// 关闭串口
|
||||
void closePort();
|
||||
|
||||
// 串口是否打开
|
||||
bool isPortOpen() const;
|
||||
|
||||
// 获取GPS解析器(用于设置参数如最小卫星数)
|
||||
GsbGpsParse* gpsParser() { return &m_parser; }
|
||||
const GsbGpsParse* gpsParser() const { return &m_parser; }
|
||||
|
||||
// 获取GPS数据
|
||||
GsbGpsParse::GpsData currentGpsData() const;
|
||||
|
||||
// 等待有效GPS数据 (带超时)
|
||||
bool waitForValidData(int timeoutMs = 30000);
|
||||
|
||||
signals:
|
||||
void gpsDataReady(const GsbGpsParse::GpsData& data);
|
||||
void portOpened();
|
||||
void portClosed();
|
||||
void portError(const QString& error);
|
||||
|
||||
private slots:
|
||||
void onReadyRead();
|
||||
|
||||
private:
|
||||
GsbGpsParse m_parser;
|
||||
QSerialPort* m_serialPort;
|
||||
};
|
||||
|
||||
// ============ 帧率与旋转速度计算器 ============
|
||||
class FramerateRotateSpeedCal : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FramerateRotateSpeedCal(QObject* parent = nullptr);
|
||||
~FramerateRotateSpeedCal() = default;
|
||||
|
||||
// 设置参数
|
||||
void setAltitude(double altitude) { m_altitude = altitude; }
|
||||
void setVerticalFov(double fovDegrees) { m_verticalFov = fovDegrees; }
|
||||
void setVerticalPixels(int pixels) { m_verticalPixels = pixels; }
|
||||
void setFramerate(double framerate) { m_framerate = framerate; }
|
||||
|
||||
// 获取参数
|
||||
double altitude() const { return m_altitude; }
|
||||
double verticalFov() const { return m_verticalFov; }
|
||||
int verticalPixels() const { return m_verticalPixels; }
|
||||
double framerate() const { return m_framerate; }
|
||||
|
||||
// 计算垂直航向分辨率(地面分辨率)
|
||||
// 基于高度、视场角和像素个数
|
||||
// 公式: resolution = 2 * altitude * tan(FOV/2) / pixels
|
||||
double calculateVerticalGroundResolution();
|
||||
|
||||
// 计算速度
|
||||
// 基于帧率和垂直航向分辨率
|
||||
// 公式: speed = framerate * ground_resolution
|
||||
double calculateSpeed();
|
||||
|
||||
// 计算旋转速度
|
||||
// 基于高度和计算出的速度
|
||||
// 公式: rotation_speed = speed / (2 * PI * altitude)
|
||||
double calculateRotationSpeed();
|
||||
|
||||
// 一站式计算:设置参数后一次性计算所有结果
|
||||
double calculate(double altitude, double verticalFov, int verticalPixels, double framerate);
|
||||
|
||||
// 获取计算结果
|
||||
double groundResolution() const { return m_groundResolution; }
|
||||
double speed() const { return m_speed; }
|
||||
double rotationSpeed() const { return m_rotationSpeedDegPerSec; }
|
||||
|
||||
signals:
|
||||
void calculationCompleted(double groundResolution, double speed, double rotationSpeed);
|
||||
|
||||
private:
|
||||
double m_pi = 3.14159265358979323846; // 圆周率
|
||||
double m_altitude = 0.0; // 高度(米)
|
||||
double m_verticalFov = 0.0; // 垂直视场角(度)
|
||||
int m_verticalPixels = 0; // 垂直方向像素个数
|
||||
double m_framerate = 0.0; // 帧率(Hz)
|
||||
|
||||
double m_groundResolution = 0.0; // 垂直航向分辨率(米/像素)
|
||||
double m_speed = 0.0; // 速度(米/秒)
|
||||
double m_rotationSpeedDegPerSec = 0.0; // 旋转速度(度/秒)
|
||||
};
|
||||
|
||||
@ -1112,22 +1112,47 @@ void HPPA::initControlTabwidget()
|
||||
|
||||
void HPPA::setupGonggashanAutoRecordConnection()
|
||||
{
|
||||
connect(m_gonggaShanRecordCtl, &GonggaShanRecordCtl::startRcordSignal, this, &HPPA::onGonggashanRecord);
|
||||
connect(m_gonggaShanRecordCtl, &GonggaShanRecordCtl::hyperAutoExposureSignal_gonggashan, this, &HPPA::onGonggashanHyperAutoExposure);
|
||||
connect(m_omc, &OneMotorControl::hyperAutoExposureDoneSignal_gonggashan, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::hyperAutoExposureDoneSignal_gonggashan);
|
||||
|
||||
connect(m_gonggaShanRecordCtl, &GonggaShanRecordCtl::fiberExposureRecordSignal_gonggashan, this, &HPPA::onGonggashanFiberAutoExposureRecord);
|
||||
connect(m_fodisWindow, &FodisWindow::startExposureSignal, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::onFiberImagerStartExposureSignal);
|
||||
connect(m_fodisWindow, &FodisWindow::exposureCompleteSignal, this, &HPPA::onStartRecordStep1);
|
||||
connect(m_fodisWindow, &FodisWindow::exposureCompleteSignal, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::onFiberImagerExposureCompleteSignal);
|
||||
connect(m_fodisWindow, &FodisWindow::exposureCompleteSignal, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::fiberExposureDoneSignal_gonggashan);
|
||||
|
||||
connect(m_omc, &OneMotorControl::sequenceComplete, m_fodisWindow, &FodisWindow::closeFiberImager);
|
||||
connect(m_omc, &OneMotorControl::sequenceComplete, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::onRcordFinished);
|
||||
connect(m_gonggaShanRecordCtl, &GonggaShanRecordCtl::startRcordSignal_gonggashan, this, &HPPA::onGonggashanRecord);
|
||||
connect(m_omc, &OneMotorControl::sequenceCompleteSignal_hyperImagerStopRecord, m_rgbCameraControlWindow, &rgbCameraWindow::toggleTakePhoto);
|
||||
connect(m_omc, &OneMotorControl::sequenceCompleteSignal_hyperImagerStopRecord, m_fodisWindow, &FodisWindow::closeFiberImager);
|
||||
connect(m_omc, &OneMotorControl::sequenceCompleteSignal_hyperImagerStopRecord, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::recordFinishedSignal_gonggashan);
|
||||
//connect(m_omc, &OneMotorControl::sequenceComplete_motorBack2Origin, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::);
|
||||
}
|
||||
|
||||
void HPPA::onGonggashanRecord(QString posInfo)
|
||||
void HPPA::onGonggashanHyperAutoExposure()
|
||||
{
|
||||
//连接马达和光谱仪
|
||||
m_omc->connectMotor(false);
|
||||
|
||||
if (!testImagerVality())
|
||||
{
|
||||
onconnect();
|
||||
}
|
||||
|
||||
m_omc->setImager(m_Imager);
|
||||
m_omc->multiPosHyperAutoExposure();
|
||||
}
|
||||
|
||||
void HPPA::onGonggashanFiberAutoExposureRecord(QString posInfo, QString dataFolder)
|
||||
{
|
||||
//设置数据存储路径和文件名
|
||||
m_fodisWindow->openFiberImager_expose_record(posInfo, dataFolder);
|
||||
}
|
||||
|
||||
void HPPA::onGonggashanRecord(const QString& posInfo, const QString& gpsData, double motorRotationSpeed, QString dataFolder)
|
||||
{
|
||||
//设置文件名
|
||||
//AppSettings::instance().setFrameRate(f);
|
||||
//AppSettings::instance().setIntegrationTime(e);
|
||||
//AppSettings::instance().setDataFolder(filePath);
|
||||
AppSettings::instance().setDataFolder(dataFolder);
|
||||
|
||||
QString dateStr = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss");
|
||||
//QString fi = AppSettings::instance().fileName() + "_" + dateStr;
|
||||
@ -1137,13 +1162,17 @@ void HPPA::onGonggashanRecord(QString posInfo)
|
||||
|
||||
//连接马达和光谱仪
|
||||
m_omc->connectMotor(false);
|
||||
m_omc->setScanSpeed(motorRotationSpeed);
|
||||
|
||||
if (!testImagerVality())
|
||||
{
|
||||
onconnect();
|
||||
}
|
||||
|
||||
m_fodisWindow->openFiberImager_expose_record(posInfo);
|
||||
|
||||
onStartRecordStep1();
|
||||
|
||||
//采集rgb图像
|
||||
m_rgbCameraControlWindow->toggleTakePhoto();
|
||||
}
|
||||
|
||||
void HPPA::recordFromRobotArm(int fileCounter)
|
||||
@ -1645,6 +1674,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);
|
||||
@ -2571,7 +2601,7 @@ void HPPA::onconnect()
|
||||
connect(m_Imager, SIGNAL(RecordDarlFinishSignal()), this, SLOT(recordDarkFinish()));
|
||||
|
||||
// Connect LayerFileCreated from imager to HPPA slot
|
||||
connect(m_Imager, SIGNAL(LayerFileCreated(QString,QString,int)), this, SLOT(onLayerCreatedFromFile(QString,QString,int)));
|
||||
connect(m_Imager, SIGNAL(LayerFileCreated(QString,QString,int, QString)), this, SLOT(onLayerCreatedFromFile(QString,QString,int, QString)));
|
||||
|
||||
connect(this->ui.actionOpenDirectory, SIGNAL(triggered()), this, SLOT(onActionOpenDirectory()));
|
||||
|
||||
@ -3083,22 +3113,22 @@ void WorkerThread3::run()
|
||||
emit AutoFocusFinishedSignal();
|
||||
}
|
||||
|
||||
void HPPA::onLayerCreatedFromFile(const QString& baseName, const QString& filePath, int fileIndex)
|
||||
void HPPA::onLayerCreatedFromFile(const QString& baseName, const QString& filePath, int fileIndex, const QString& hyperimagerTppe)
|
||||
{
|
||||
if (!m_LayerTreeModel || !m_RasterGroup) return;
|
||||
|
||||
if (ui.mAction3DPlantPhenotypeScenario->isChecked())
|
||||
{
|
||||
//addLayer(baseName, filePath, false, false);
|
||||
addLayer(baseName, filePath, false);
|
||||
addLayer(baseName, filePath, false, true, hyperimagerTppe);
|
||||
}
|
||||
else
|
||||
{
|
||||
addLayer(baseName, filePath, false);
|
||||
addLayer(baseName, filePath, false, true, hyperimagerTppe);
|
||||
}
|
||||
}
|
||||
|
||||
void HPPA::addLayer(const QString& baseName, const QString& filePath,bool refresh, bool isAddImage)
|
||||
void HPPA::addLayer(const QString& baseName, const QString& filePath,bool refresh, bool isAddImage, const QString& hyperimagerTppe)
|
||||
{
|
||||
// Create MapLayer first and attach it to a LayerTreeLayerNode
|
||||
RasterLayer* ml = new RasterLayer(baseName, filePath);
|
||||
@ -3115,14 +3145,41 @@ void HPPA::addLayer(const QString& baseName, const QString& filePath,bool refres
|
||||
|
||||
if (isAddImage)
|
||||
{
|
||||
newImage(ml, RasterImageLayer::RendererType::Multiband, node, refresh);
|
||||
newImage(ml, RasterImageLayer::RendererType::Multiband, node, refresh, hyperimagerTppe);
|
||||
}
|
||||
}
|
||||
|
||||
void HPPA::newImage(RasterLayer* ml, RasterImageLayer::RendererType type, LayerTreeNode* parent, bool refresh)
|
||||
void HPPA::newImage(RasterLayer* ml, RasterImageLayer::RendererType type, LayerTreeNode* parent, bool refresh, const QString& hyperimagerTppe)
|
||||
{
|
||||
QWidget* mapcavasContainer = onCreateTab(ml->name());
|
||||
RasterImageLayer* rasterImageLayer = new RasterImageLayer(ml, type);
|
||||
RasterImageLayer* rasterImageLayer;
|
||||
|
||||
//当边采集边显示时,需要修改rasterImageLayer默认渲染波段
|
||||
if (hyperimagerTppe== "visibleLight")
|
||||
{
|
||||
rasterImageLayer = new RasterImageLayer(ml, type, false);
|
||||
|
||||
auto params = rasterImageLayer->multibandParams();
|
||||
params.rWave = 665;
|
||||
params.gWave = 560;
|
||||
params.bWave = 490;
|
||||
rasterImageLayer->setMultibandParams(params);
|
||||
}
|
||||
else if (hyperimagerTppe == "nearInfrared")
|
||||
{
|
||||
rasterImageLayer = new RasterImageLayer(ml, type, false);
|
||||
|
||||
auto params = rasterImageLayer->multibandParams();
|
||||
params.rWave = 1500;
|
||||
params.gWave = 1300;
|
||||
params.bWave = 1100;
|
||||
rasterImageLayer->setMultibandParams(params);
|
||||
}
|
||||
else//当打开影像文件时,rasterImageLayer默认渲染波段由头文件决定
|
||||
{
|
||||
rasterImageLayer = new RasterImageLayer(ml, type, true);
|
||||
}
|
||||
|
||||
QList<Mapcavas*> mapcavas = mapcavasContainer->findChildren<Mapcavas*>();
|
||||
if (mapcavas.size() == 0)
|
||||
{
|
||||
|
||||
10
HPPA/HPPA.h
10
HPPA/HPPA.h
@ -430,9 +430,9 @@ public Q_SLOTS:
|
||||
void createMicroscopicMotionControlScenario();
|
||||
void onCreated3DModelOneMotor();
|
||||
|
||||
void addLayer(const QString& baseName, const QString& filePath, bool refresh, bool isAddImage = true);
|
||||
void newImage(RasterLayer* ml, RasterImageLayer::RendererType, LayerTreeNode* parent, bool refresh=true);
|
||||
void onLayerCreatedFromFile(const QString& baseName, const QString& filePath, int fileIndex);
|
||||
void addLayer(const QString& baseName, const QString& filePath, bool refresh, bool isAddImage = true, const QString& hyperimagerTppe="");
|
||||
void newImage(RasterLayer* ml, RasterImageLayer::RendererType, LayerTreeNode* parent, bool refresh=true, const QString& hyperimagerTppe="");
|
||||
void onLayerCreatedFromFile(const QString& baseName, const QString& filePath, int fileIndex, const QString& hyperimagerTppe);
|
||||
void removeLayerByTreeIndex();
|
||||
void removeLayerByNode(LayerTreeNode* node);
|
||||
void showColorImageByTreeIndex();
|
||||
@ -457,7 +457,9 @@ public Q_SLOTS:
|
||||
void onStretchedImageReady(int fileNumber, const QString& filePath, QPixmap& pixmap);
|
||||
void onStretchProcessingError(int fileNumber, const QString& filePath, const QString& error);
|
||||
|
||||
void onGonggashanRecord(QString posInfo);
|
||||
void onGonggashanRecord(const QString& posInfo, const QString& gpsData, double motorRotationSpeed, QString dataFolder);
|
||||
void onGonggashanHyperAutoExposure();
|
||||
void onGonggashanFiberAutoExposureRecord(QString posInfo, QString dataFolder);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
@ -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" />
|
||||
|
||||
@ -68,11 +68,12 @@ double ImagerOperationBase::auto_exposure()
|
||||
|
||||
imagerStopCollect();
|
||||
|
||||
emit autoExposureSignal();
|
||||
double exposureTime = getIntegrationTime();
|
||||
emit autoExposureSignal(exposureTime);
|
||||
|
||||
//std::cout << "自动曝光:" << getIntegrationTime() << std::endl;
|
||||
//std::cout << "自动曝光:" << exposureTime << std::endl;
|
||||
|
||||
return getIntegrationTime();
|
||||
return exposureTime;
|
||||
}
|
||||
|
||||
void ImagerOperationBase::focus()
|
||||
@ -251,7 +252,7 @@ void ImagerOperationBase::start_record()
|
||||
m_FileName2Save2 = m_FileName2Save + "_" + std::to_string(m_FileSavedCounter) + ".bil";
|
||||
QString baseName = QString::fromStdString(getFileNameFromPath(m_FileName2Save2));
|
||||
QString filePath = QString::fromStdString(m_FileName2Save2);
|
||||
emit LayerFileCreated(baseName, filePath, m_FileSavedCounter);
|
||||
emit LayerFileCreated(baseName, filePath, m_FileSavedCounter, "visibleLight");
|
||||
|
||||
FILE* m_fImage = fopen(m_FileName2Save2.c_str(), "w+b");
|
||||
|
||||
@ -313,7 +314,7 @@ void ImagerOperationBase::start_record()
|
||||
fprintf(hTimesFile, "%ll\n", timeOs);
|
||||
|
||||
//将rgb波段提取出来,以便在界面中显示
|
||||
m_RgbImage->FillRgbImage(buffer);//??????????????????????????????????????????????????????????????????????????????????????????????????????
|
||||
m_RgbImage->FillRgbImage(buffer, 121, 79, 40);//??????????????????????????????????????????????????????????????????????????????????????????????????????
|
||||
|
||||
//std::cout << "第" << m_iFrameCounter << "帧写了" << x << "个unsigned short。" << std::endl;
|
||||
|
||||
|
||||
@ -117,11 +117,11 @@ signals:
|
||||
|
||||
|
||||
void testImagerStatus();//表示可以测试相机连接状态:是否连接,并反映到界面上
|
||||
void autoExposureSignal();
|
||||
void autoExposureSignal(double exposureTime);
|
||||
|
||||
// 新增:当一组影像文件(.bil/.hdr)写入完成后发出(会从采集线程发出,Qt 会做 queued connection)
|
||||
void ImageFileSaved(const QString& path, int fileIndex);
|
||||
|
||||
// 修改:不再直接发送 MapLayer*,而是发送文件名与文件路径,UI 层负责创建 MapLayer 对象并管理生命周期
|
||||
void LayerFileCreated(const QString& baseName, const QString& filePath, int fileIndex);
|
||||
void LayerFileCreated(const QString& baseName, const QString& filePath, int fileIndex, const QString& hyperimagerTppe);
|
||||
};
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
// Created by 73505 on 2023/5/7.
|
||||
//
|
||||
#include <algorithm>
|
||||
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include "JinspFiberImager.h"
|
||||
|
||||
JinspFiberImager::JinspFiberImager(bool bIsUSBMode, std::string ucPortNumber, std::string strDeviceName)
|
||||
@ -132,7 +133,7 @@ void JinspFiberImager::recordDark(QString path)
|
||||
outfile.close();
|
||||
}
|
||||
|
||||
void JinspFiberImager::recordTarget(int recordTimes, QString path)
|
||||
void JinspFiberImager::recordTarget2csv(int recordTimes, QString path)
|
||||
{
|
||||
//获取设备信息
|
||||
DeviceAttribute attribute;
|
||||
@ -318,10 +319,8 @@ void JinspFiberImager::setCaptureInterval(int captureIntervalSeconds)
|
||||
m_captureIntervalMilliseconds = captureIntervalSeconds * 1000;
|
||||
}
|
||||
|
||||
void JinspFiberImager::OpenFiberImagerAndRecord(QString posInfo)
|
||||
void JinspFiberImager::OpenFiberImagerAndRecord(QString filePath)
|
||||
{
|
||||
m_posInfo = posInfo;
|
||||
|
||||
//连接光谱仪
|
||||
QString SN;
|
||||
QString pixelCount;
|
||||
@ -335,13 +334,25 @@ void JinspFiberImager::OpenFiberImagerAndRecord(QString posInfo)
|
||||
emit exposureCompleteSignal(m_iExposureTime);
|
||||
|
||||
//采集
|
||||
QFile qfData(filePath);
|
||||
bool bRes = qfData.open(QFile::WriteOnly | QIODevice::Append);
|
||||
if (!bRes)
|
||||
{
|
||||
printf("WriteData QFile open Failed");
|
||||
return;
|
||||
}
|
||||
|
||||
m_record = true;
|
||||
DataFrame data;
|
||||
while (m_record)
|
||||
{
|
||||
recordTarget(1, AppSettings::instance().FiberImagerDataFolder());
|
||||
singleShot(data);
|
||||
qfData.write((char*)&data, sizeof(DataFrame));
|
||||
qfData.flush();
|
||||
|
||||
QThread::msleep(m_captureIntervalMilliseconds);
|
||||
}
|
||||
qfData.close();
|
||||
|
||||
std::cout << "close.........." << std::endl;
|
||||
m_FiberSpectrometer->Close();
|
||||
|
||||
@ -61,10 +61,10 @@ private:
|
||||
|
||||
public slots:
|
||||
void recordDark(QString path);
|
||||
void recordTarget(int recordTimes, QString path);
|
||||
void recordTarget2csv(int recordTimes, QString path);
|
||||
void autoExpose();
|
||||
|
||||
void OpenFiberImagerAndRecord(QString posInfo);
|
||||
void OpenFiberImagerAndRecord(QString filePath);
|
||||
|
||||
signals:
|
||||
void sendExposureTimeSignal(int exposureTime);
|
||||
|
||||
@ -42,6 +42,11 @@ void OneMotorControl::onConnectMotor()
|
||||
connectMotor(true);
|
||||
}
|
||||
|
||||
void OneMotorControl::setScanSpeed(double speed)
|
||||
{
|
||||
ui.speed_lineEdit->setText(QString::number(speed));
|
||||
}
|
||||
|
||||
void OneMotorControl::connectMotor(bool isNotification)
|
||||
{
|
||||
if (getMotorsConnectionStatus())
|
||||
@ -225,16 +230,20 @@ void OneMotorControl::run()
|
||||
{
|
||||
if (m_coordinator)//当高光谱相机停止采集后,马达还未回到原点时,上次任务的m_coordinator还没有被销毁
|
||||
{
|
||||
onSequenceComplete(0);
|
||||
onSequenceComplete_motorBack2Origin(0);
|
||||
}
|
||||
|
||||
qRegisterMetaType<OneMotionCapturePathLine>("OneMotionCapturePathLine");
|
||||
m_coordinator = new OneMotionCaptureCoordinator(m_multiAxisController, m_Imager);
|
||||
m_coordinator->setObjectName("testOneMotionCaptureCoordinator");
|
||||
connect(this, SIGNAL(start(OneMotionCapturePathLine)), m_coordinator, SLOT(startStepMotion(OneMotionCapturePathLine)));
|
||||
connect(this, SIGNAL(stopStepMotionSignal()), m_coordinator, SLOT(stopStepMotion()));
|
||||
|
||||
connect(m_coordinator, SIGNAL(sequenceComplete(int)), this, SLOT(onSequenceComplete(int)));
|
||||
connect(this, &OneMotorControl::start, m_coordinator, &OneMotionCaptureCoordinator::startStepMotion);
|
||||
connect(this, &OneMotorControl::stopStepMotionSignal, m_coordinator, &OneMotionCaptureCoordinator::stopStepMotion);
|
||||
|
||||
connect(m_coordinator, &OneMotionCaptureCoordinator::sequenceCompleteSignal_hyperImagerStopRecord,
|
||||
this, &OneMotorControl::sequenceCompleteSignal_hyperImagerStopRecord);
|
||||
connect(m_coordinator, &OneMotionCaptureCoordinator::sequenceCompleteSignal_motorBack2Origin,
|
||||
this, &OneMotorControl::onSequenceComplete_motorBack2Origin);
|
||||
|
||||
OneMotionCapturePathLine tmp;
|
||||
tmp.speedRecord = ui.speed_lineEdit->text().toDouble();
|
||||
@ -248,13 +257,37 @@ void OneMotorControl::stop()
|
||||
emit stopStepMotionSignal();
|
||||
}
|
||||
|
||||
void OneMotorControl::onSequenceComplete(int state)
|
||||
void OneMotorControl::multiPosHyperAutoExposure()
|
||||
{
|
||||
emit sequenceComplete();
|
||||
//所有该自动曝光的位置
|
||||
std::vector<double> maxRangeLocations = m_multiAxisController->getMaxPos();
|
||||
double maxPos = maxRangeLocations[0];
|
||||
|
||||
disconnect(this, SIGNAL(start(OneMotionCapturePathLine)), m_coordinator, SLOT(startStepMotion(OneMotionCapturePathLine)));
|
||||
disconnect(this, SIGNAL(stopStepMotionSignal()), m_coordinator, SLOT(stopStepMotion()));
|
||||
disconnect(m_coordinator, SIGNAL(sequenceComplete(int)), this, SLOT(onSequenceComplete(int)));
|
||||
std::vector<double> locations;
|
||||
locations.push_back(maxPos * 0.2);
|
||||
locations.push_back(maxPos * 0.5);
|
||||
locations.push_back(maxPos * 0.8);
|
||||
|
||||
//创建协调器,并连接信号槽
|
||||
m_coordinator_gonggashan_autoexpose = new OneMotorMultiPosCoordinator(m_multiAxisController, m_Imager);
|
||||
|
||||
//connect(this, SIGNAL(stopStepMotionSignal()), m_coordinator_gonggashan_autoexpose, SLOT(stopStepMotion()));
|
||||
connect(m_coordinator_gonggashan_autoexpose, &OneMotorMultiPosCoordinator::sequenceComplete, this, &OneMotorControl::onSequenceComplete_gonggashan_autoexpose);
|
||||
connect(m_coordinator_gonggashan_autoexpose, &OneMotorMultiPosCoordinator::hyperAutoExposureDoneSignal, this, &OneMotorControl::hyperAutoExposureDoneSignal_gonggashan);
|
||||
|
||||
m_coordinator_gonggashan_autoexpose->startStepMotion(ui.speed_lineEdit->text().toDouble(), locations);
|
||||
}
|
||||
|
||||
void OneMotorControl::onSequenceComplete_gonggashan_autoexpose(int state)
|
||||
{
|
||||
emit multiPosAutoexposeSequenceCompleteSignal();
|
||||
|
||||
m_coordinator_gonggashan_autoexpose->deleteLater();
|
||||
}
|
||||
|
||||
void OneMotorControl::onSequenceComplete_motorBack2Origin(int state)
|
||||
{
|
||||
emit sequenceComplete_motorBack2Origin();
|
||||
|
||||
// Use deleteLater() instead of delete: this slot may have been called directly
|
||||
// from OneMotionCaptureCoordinator's call stack (direct connection), so deleting
|
||||
|
||||
@ -26,6 +26,8 @@ public:
|
||||
void run();
|
||||
void stop();
|
||||
|
||||
void multiPosHyperAutoExposure();
|
||||
|
||||
void record_dark();
|
||||
void record_white();
|
||||
|
||||
@ -33,6 +35,8 @@ public:
|
||||
|
||||
void connectMotor(bool isNotification);
|
||||
|
||||
void setScanSpeed(double speed);
|
||||
|
||||
public Q_SLOTS:
|
||||
void onConnectMotor();
|
||||
|
||||
@ -46,7 +50,8 @@ public Q_SLOTS:
|
||||
void onxMotorLeft();
|
||||
void onxMotorStop();
|
||||
|
||||
void onSequenceComplete(int state);
|
||||
void onSequenceComplete_motorBack2Origin(int state);
|
||||
void onSequenceComplete_gonggashan_autoexpose(int state);
|
||||
|
||||
signals:
|
||||
void moveSignal(int, bool, double, int);
|
||||
@ -62,9 +67,16 @@ signals:
|
||||
void stopStepMotionSignal();
|
||||
|
||||
void sequenceComplete();
|
||||
void sequenceComplete_motorBack2Origin();
|
||||
|
||||
void broadcastLocationSignal(std::vector<double>);
|
||||
|
||||
void hyperAutoExposureDoneSignal_gonggashan(double exposureTime, double frameRate);
|
||||
|
||||
void multiPosAutoexposeSequenceCompleteSignal();
|
||||
|
||||
void sequenceCompleteSignal_hyperImagerStopRecord(int);
|
||||
|
||||
private:
|
||||
Ui::OneMotorControl_UI ui;
|
||||
|
||||
@ -78,6 +90,8 @@ private:
|
||||
DarkAndWhiteCaptureCoordinator* m_whiteCaptureCoordinator = nullptr;
|
||||
|
||||
bool m_xMotorConnectionStatus = false;
|
||||
|
||||
QPointer<OneMotorMultiPosCoordinator> m_coordinator_gonggashan_autoexpose;
|
||||
};
|
||||
|
||||
class OneMotorControl_LiftingPlatform : public QDialog, public MotorWindowBase
|
||||
@ -128,6 +142,7 @@ signals:
|
||||
|
||||
void broadcastLocationSignal(std::vector<double>);
|
||||
|
||||
|
||||
private:
|
||||
Ui::OneMotorControl_UI ui;
|
||||
|
||||
|
||||
@ -5,11 +5,39 @@
|
||||
#include "MultibandRasterRenderer.h"
|
||||
#include "SinglebandRasterRenderer.h"
|
||||
|
||||
RasterImageLayer::RasterImageLayer(RasterLayer* layer, RendererType type)
|
||||
RasterImageLayer::RasterImageLayer(RasterLayer* layer, RendererType type, bool initRenderParamsFromFile)
|
||||
: m_layer(layer)
|
||||
, m_rendererType(type)
|
||||
, m_rendererInitialized(false)
|
||||
{
|
||||
if (initRenderParamsFromFile)
|
||||
{
|
||||
// 此处根据头文件(打开影像文件)修改默认渲染波段,只对打开文件的情况下有效;
|
||||
// 当边采集边显示时(initRenderParamsFromFile设置为false),应该在实例化RasterImageLayer后调用setMultibandParams设置默认渲染波段
|
||||
try
|
||||
{
|
||||
if (!m_layer) return;
|
||||
|
||||
std::vector<double> wavelengths = m_layer->bandWavelengths();
|
||||
if (wavelengths.empty()) return;
|
||||
|
||||
std::sort(wavelengths.begin(), wavelengths.end());
|
||||
double m_minWave = wavelengths.front();
|
||||
double m_maxWave = wavelengths.back();
|
||||
|
||||
if (m_minWave > 800 && m_maxWave > 1600)
|
||||
{
|
||||
m_multibandParams.rWave = 1500;
|
||||
m_multibandParams.gWave = 1300;
|
||||
m_multibandParams.bWave = 1100;
|
||||
}
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void RasterImageLayer::ensureRenderer()
|
||||
|
||||
@ -19,7 +19,7 @@ public:
|
||||
Singleband
|
||||
};
|
||||
|
||||
RasterImageLayer(RasterLayer* layer, RendererType type);
|
||||
RasterImageLayer(RasterLayer* layer, RendererType type, bool initRenderParamsFromFile);
|
||||
~RasterImageLayer();
|
||||
|
||||
void ensureRenderer();
|
||||
|
||||
@ -104,20 +104,25 @@ void ResononNirImager::setSpectraBin(int new_spectral_bin)
|
||||
double ResononNirImager::auto_exposure()
|
||||
{
|
||||
//第一步:先设置曝光时间为在当前帧率情况下最大
|
||||
double x = 1 / getFramerate() * 1000;//获取最大毫秒曝光时间
|
||||
double f = getFramerate();
|
||||
double x = 1 / f * 1000;//获取最大毫秒曝光时间
|
||||
std::cout << f << "hz帧率下,最大曝光时间为" << x << std::endl;
|
||||
|
||||
reConnectImage();
|
||||
setIntegrationTime(x);
|
||||
|
||||
//第二步:通过循环寻找最佳曝光时间
|
||||
imagerStartCollect();
|
||||
|
||||
double tmpTime;
|
||||
while (true)
|
||||
{
|
||||
getFrame(buffer);
|
||||
if (GetMaxValue(buffer, m_FrameSize) >= 4095)
|
||||
if (GetMaxValue(buffer, m_FrameSize) >= 16383)
|
||||
{
|
||||
setIntegrationTime(getIntegrationTime() * 0.8);
|
||||
std::cout << "自动曝光-----------" << std::endl;
|
||||
tmpTime = getIntegrationTime() * 0.8;
|
||||
setIntegrationTime(tmpTime);
|
||||
std::cout << "自动曝光-----------:" << tmpTime << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -128,9 +133,28 @@ double ResononNirImager::auto_exposure()
|
||||
reConnectImage();
|
||||
//imagerStopCollect();
|
||||
|
||||
//std::cout << "自动曝光:" << getIntegrationTime() << std::endl;
|
||||
double exposureTime = getIntegrationTime();
|
||||
emit autoExposureSignal(exposureTime);
|
||||
|
||||
return getIntegrationTime();
|
||||
//std::cout << "自动曝光:" << exposureTime << std::endl;
|
||||
|
||||
return exposureTime;
|
||||
}
|
||||
|
||||
unsigned short ResononNirImager::GetMaxValue(unsigned short* dark, int number)
|
||||
{
|
||||
unsigned int max = 0;
|
||||
for (size_t i = 0; i < number; i++)
|
||||
{
|
||||
if (dark[i] > 16383) continue;//IR L为14位
|
||||
|
||||
if (dark[i] > max)
|
||||
{
|
||||
max = dark[i];
|
||||
}
|
||||
}
|
||||
std::cout << "本帧最大值为" << max << std::endl;
|
||||
return max;
|
||||
}
|
||||
|
||||
double ResononNirImager::getWavelengthAtBand(int band)
|
||||
@ -290,7 +314,7 @@ void ResononNirImager::start_record()
|
||||
m_FileName2Save2 = m_FileName2Save + "_" + std::to_string(m_FileSavedCounter) + ".bil";
|
||||
QString baseName = QString::fromStdString(getFileNameFromPath(m_FileName2Save2));
|
||||
QString filePath = QString::fromStdString(m_FileName2Save2);
|
||||
emit LayerFileCreated(baseName, filePath, m_FileSavedCounter);
|
||||
emit LayerFileCreated(baseName, filePath, m_FileSavedCounter, "nearInfrared");
|
||||
|
||||
FILE* m_fImage = fopen(m_FileName2Save2.c_str(), "w+b");
|
||||
|
||||
@ -352,7 +376,8 @@ void ResononNirImager::start_record()
|
||||
fprintf(hTimesFile, "%ll\n", timeOs);
|
||||
|
||||
//将rgb波段提取出来,以便在界面中显示
|
||||
m_RgbImage->FillRgbImage(buffer);//??????????????????????????????????????????????????????????????????????????????????????????????????????
|
||||
//需要修改函数m_RgbImage->FillRgbImage,接收参数:提取rgb的偏移,参数由相机类型、单帧大小、波长范围等确定
|
||||
m_RgbImage->FillRgbImage(buffer, 172, 112, 52);//??????????????????????????????????????????????????????????????????????????????????????????????????????
|
||||
|
||||
//std::cout << "第" << m_iFrameCounter << "帧写了" << x << "个unsigned short。" << std::endl;
|
||||
|
||||
@ -408,7 +433,7 @@ void ResononNirImager::WriteHdr()
|
||||
outfile << "ENVI\n";
|
||||
outfile << "interleave = bil\n";
|
||||
outfile << "data type = 12\n";
|
||||
outfile << "bit depth = 12\n";
|
||||
outfile << "bit depth = 14\n";
|
||||
outfile << "byte order = 0\n";
|
||||
outfile << "samples = " << getSampleCount() << "\n";
|
||||
outfile << "bands = " << getBandCount() << "\n";
|
||||
|
||||
@ -38,6 +38,8 @@ public:
|
||||
void WriteHdr();
|
||||
|
||||
protected:
|
||||
unsigned short GetMaxValue(unsigned short* dark, int number);
|
||||
|
||||
private:
|
||||
void reConnectImage();
|
||||
|
||||
|
||||
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
|
||||
|
||||
@ -288,7 +288,7 @@ QPushButton:pressed
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>版本:3.1.3</string>
|
||||
<string>版本:3.1.4</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
100
HPPA/fodis.ui
100
HPPA/fodis.ui
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>857</width>
|
||||
<height>477</height>
|
||||
<width>438</width>
|
||||
<height>330</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -83,7 +83,7 @@ QPushButton:pressed
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="1" column="1" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="close_btn">
|
||||
@ -113,33 +113,7 @@ QPushButton:pressed
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>135</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>135</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="2" column="1" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
@ -184,7 +158,71 @@ QPushButton:pressed
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="3" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>135</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<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>
|
||||
<item row="3" column="3">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>135</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
||||
@ -64,7 +64,7 @@ void CImage::SetRgbImageWidthAndHeight(int BandCount, int Sample, int FrameNumbe
|
||||
//std::cout << "rgb影像内存地址为:" << m_QRgbImage << std::endl;
|
||||
}
|
||||
|
||||
void CImage::FillRgbImage(unsigned short *datacube)
|
||||
void CImage::FillRgbImage(unsigned short *datacube, int rBandNumber, int gBandNumber, int bBandNumber)
|
||||
{
|
||||
//uchar==unsigned char,内存大小:1个字节,范围为0-255
|
||||
//uchar * imagebits24 = m_QRgbImage->bits();
|
||||
@ -78,9 +78,9 @@ void CImage::FillRgbImage(unsigned short *datacube)
|
||||
//std::cout << "rgb图像写入数据帧数:" << j << std::endl;
|
||||
|
||||
//取值:一帧影像中,从左到右的rgb像元值
|
||||
r = *(datacube + 121 * m_iSampleNumber + j);
|
||||
g = *(datacube + 79 * m_iSampleNumber + j);
|
||||
b = *(datacube + 40 * m_iSampleNumber + j);
|
||||
r = *(datacube + rBandNumber * m_iSampleNumber + j);
|
||||
g = *(datacube + gBandNumber * m_iSampleNumber + j);
|
||||
b = *(datacube + bBandNumber * m_iSampleNumber + j);
|
||||
|
||||
//将像元值赋值到cv::Mat中,操作像元值:https://zhuanlan.zhihu.com/p/51842288
|
||||
//int dataType = m_matRgbImage->type();//当数据类型为CV_16UC3时,返回18
|
||||
|
||||
@ -21,7 +21,7 @@ public:
|
||||
CImage(QWidget* pParent = NULL);
|
||||
//~CImage();
|
||||
void SetRgbImageWidthAndHeight(int BandCount, int Sample, int FrameNumber);
|
||||
void FillRgbImage(unsigned short *datacube);
|
||||
void FillRgbImage(unsigned short *datacube, int rBandNumber, int gBandNumber, int bBandNumber);
|
||||
void FillFocusGrayImage(unsigned short *datacube);
|
||||
void FillFocusGrayQImage(unsigned short * datacube);
|
||||
|
||||
|
||||
@ -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,190 @@ 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::toggleTakePhoto()
|
||||
{
|
||||
//std::cout << "<22>ر<EFBFBD><D8B1><EFBFBD>Ƶ+++++++++++++++++++++++++++++++++++++++++++" << std::endl;
|
||||
m_RgbCamera->CloseCamera();
|
||||
emit ui.take_photo_btn->clicked();
|
||||
}
|
||||
|
||||
void rgbCameraWindow::setupCaptureCoordinator()
|
||||
{
|
||||
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,43 @@ 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);
|
||||
|
||||
void toggleTakePhoto();
|
||||
|
||||
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