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);
|
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
|
double AppSettings::scanSpeed() const
|
||||||
{
|
{
|
||||||
return m_settings.value("OneMotorControl/ScanSpeed", kDefaultScanSpeed).toDouble();
|
return m_settings.value("OneMotorControl/ScanSpeed", kDefaultScanSpeed).toDouble();
|
||||||
|
|||||||
@ -38,6 +38,16 @@ public:
|
|||||||
QString FiberImagerDataFolder() const;
|
QString FiberImagerDataFolder() const;
|
||||||
void setFiberImagerDataFolder(const QString& path);
|
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;
|
double scanSpeed() const;
|
||||||
void setScanSpeed(double value);
|
void setScanSpeed(double value);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "CaptureCoordinator.h"
|
#include "CaptureCoordinator.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
TwoMotionCaptureCoordinator::TwoMotionCaptureCoordinator(
|
TwoMotionCaptureCoordinator::TwoMotionCaptureCoordinator(
|
||||||
IrisMultiMotorController* motorCtrl,
|
IrisMultiMotorController* motorCtrl,
|
||||||
@ -458,7 +459,9 @@ OneMotionCaptureCoordinator::OneMotionCaptureCoordinator(
|
|||||||
connect(this, &OneMotionCaptureCoordinator::stopRecordHSISignal,
|
connect(this, &OneMotionCaptureCoordinator::stopRecordHSISignal,
|
||||||
m_cameraCtrl, &ImagerOperationBase::stop_record);
|
m_cameraCtrl, &ImagerOperationBase::stop_record);
|
||||||
connect(m_cameraCtrl, &ImagerOperationBase::RecordFinishedSignal_WhenFrameNumberMeet,
|
connect(m_cameraCtrl, &ImagerOperationBase::RecordFinishedSignal_WhenFrameNumberMeet,
|
||||||
this, &OneMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet);
|
this, &OneMotionCaptureCoordinator::handleHyperImagerCaptureComplete);
|
||||||
|
connect(m_cameraCtrl, &ImagerOperationBase::RecordFinishedSignal_WhenFrameNumberNotMeet,
|
||||||
|
this, &OneMotionCaptureCoordinator::handleHyperImagerCaptureComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
OneMotionCaptureCoordinator::~OneMotionCaptureCoordinator()
|
OneMotionCaptureCoordinator::~OneMotionCaptureCoordinator()
|
||||||
@ -497,12 +500,9 @@ void OneMotionCaptureCoordinator::stopStepMotion()
|
|||||||
{
|
{
|
||||||
m_cameraCtrl->stop_record();
|
m_cameraCtrl->stop_record();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit stopMotorSignal(0);
|
|
||||||
m_isHypercamStopRecord = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet()
|
void OneMotionCaptureCoordinator::handleHyperImagerCaptureComplete()
|
||||||
{
|
{
|
||||||
emit stopMotorSignal(0);
|
emit stopMotorSignal(0);
|
||||||
m_isHypercamStopRecord = true;
|
m_isHypercamStopRecord = true;
|
||||||
@ -587,13 +587,11 @@ void OneMotionCaptureCoordinator::handleMotorStoped(int motorID, double pos)
|
|||||||
}
|
}
|
||||||
move2LocBeforeStart();
|
move2LocBeforeStart();
|
||||||
|
|
||||||
emit sequenceComplete_cam_stop_before_motorback(0);
|
emit sequenceCompleteSignal_hyperImagerStopRecord(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// emit sequenceComplete last: the slot connected to it may delete this object,
|
emit sequenceCompleteSignal_motorBack2Origin(0);
|
||||||
// so no member access is allowed after this point.
|
|
||||||
emit sequenceComplete(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,3 +970,265 @@ double OneMotionCoordinator::getErrorRate(double targetLoc, double actualLoc)
|
|||||||
|
|
||||||
return errorRate;
|
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 startStepMotion(OneMotionCapturePathLine pathLine);
|
||||||
void stopStepMotion();
|
void stopStepMotion();
|
||||||
|
|
||||||
void handleCaptureCompleteWhenFrameNumberMeet();
|
void handleHyperImagerCaptureComplete();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sequenceComplete_cam_stop_before_motorback(int);
|
void sequenceCompleteSignal_hyperImagerStopRecord(int);
|
||||||
void sequenceComplete(int);
|
void sequenceCompleteSignal_motorBack2Origin(int);
|
||||||
void errorOccurred(const QString& error);
|
void errorOccurred(const QString& error);
|
||||||
void moveTo(int, double, double, int);
|
void moveTo(int, double, double, int);
|
||||||
void moveSignal(int, bool, double, int);
|
void moveSignal(int, bool, double, int);
|
||||||
@ -300,3 +300,75 @@ private:
|
|||||||
int m_retryTimes;
|
int m_retryTimes;
|
||||||
bool m_reached;
|
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:
|
public slots:
|
||||||
virtual void recordDark(QString path) = 0;
|
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;
|
virtual void autoExpose() = 0;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|||||||
@ -27,10 +27,9 @@ FodisWindow::FodisWindow(QWidget* parent)
|
|||||||
|
|
||||||
connect(this->ui.dataFolderBtn, SIGNAL(clicked()), this, SLOT(onSelectDataFolder()));
|
connect(this->ui.dataFolderBtn, SIGNAL(clicked()), this, SLOT(onSelectDataFolder()));
|
||||||
|
|
||||||
// 初始化数据保存路径显示(从 AppSettings 恢复或使用默认)
|
connect(ui.fileNameLineEdit, &QLineEdit::textChanged, this, &FodisWindow::onFileNameChanged);
|
||||||
ui.dataFolderLineEdit->setText(AppSettings::instance().depthCameraDataFolder());
|
|
||||||
|
|
||||||
setDataFolder(AppSettings::instance().FiberImagerDataFolder());
|
loadSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
FodisWindow::~FodisWindow()
|
FodisWindow::~FodisWindow()
|
||||||
@ -41,6 +40,12 @@ FodisWindow::~FodisWindow()
|
|||||||
m_JinspFiberImagerOperation = nullptr;
|
m_JinspFiberImagerOperation = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FodisWindow::loadSettings()
|
||||||
|
{
|
||||||
|
ui.dataFolderLineEdit->setText(AppSettings::instance().FiberImagerDataFolder());
|
||||||
|
ui.fileNameLineEdit->setText(AppSettings::instance().fodisCameraFileName());
|
||||||
|
}
|
||||||
|
|
||||||
void FodisWindow::onSelectDataFolder()
|
void FodisWindow::onSelectDataFolder()
|
||||||
{
|
{
|
||||||
QString dir = QFileDialog::getExistingDirectory(this,
|
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)
|
void FodisWindow::setCaptureInterval(int captureIntervalSeconds)
|
||||||
{
|
{
|
||||||
m_JinspFiberImagerOperation->setCaptureInterval(captureIntervalSeconds);
|
m_JinspFiberImagerOperation->setCaptureInterval(captureIntervalSeconds);
|
||||||
@ -69,11 +85,24 @@ void FodisWindow::openFiberImager()
|
|||||||
openFiberImager_expose_record("pos_null");
|
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())
|
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:
|
public Q_SLOTS:
|
||||||
void openFiberImager();
|
void openFiberImager();
|
||||||
void openFiberImager_expose_record(QString posInfo);
|
void openFiberImager_expose_record(QString posInfo, QString dataFolder = "");
|
||||||
void onCamOpened();
|
void onCamOpened();
|
||||||
void closeFiberImager();
|
void closeFiberImager();
|
||||||
void onCamClosed();
|
void onCamClosed();
|
||||||
|
|
||||||
void onSelectDataFolder();
|
void onSelectDataFolder();
|
||||||
|
void onFileNameChanged(const QString& text);
|
||||||
|
void setFileName(QString name);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void openFiberImagerSignal(QString posInfo);
|
void openFiberImagerSignal(QString filePath);
|
||||||
void PlotSpectralSignal();
|
void PlotSpectralSignal();
|
||||||
void FiberImagerClosedSignal();
|
void FiberImagerClosedSignal();
|
||||||
|
|
||||||
@ -53,4 +55,6 @@ private:
|
|||||||
QThread* m_FiberImagerThread;
|
QThread* m_FiberImagerThread;
|
||||||
|
|
||||||
JinspFiberImager* m_JinspFiberImagerOperation;
|
JinspFiberImager* m_JinspFiberImagerOperation;
|
||||||
|
|
||||||
|
void loadSettings();
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -10,34 +10,108 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QStateMachine>
|
||||||
|
#include <QSignalTransition>
|
||||||
|
#include <QFinalState>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QSerialPort>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
#include "ui_gonggashanCtl.h"
|
#include "ui_gonggashanCtl.h"
|
||||||
|
|
||||||
#include "CommunicationViaTCP.h"
|
#include "CommunicationViaTCP.h"
|
||||||
#include "AppSettings.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:
|
public:
|
||||||
enum class TaskState
|
explicit GonggashanTaskExecutor(QObject* parent = nullptr);
|
||||||
{
|
~GonggashanTaskExecutor();
|
||||||
Idle,
|
|
||||||
Running
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit GonggashanTaskScheduler(QObject* parent = nullptr);
|
bool isRunning() const { return m_machine && m_machine->isRunning() && !m_machine->configuration().isEmpty(); }
|
||||||
~GonggashanTaskScheduler();
|
|
||||||
|
|
||||||
bool isTaskRunning() const;
|
public slots:
|
||||||
void setTaskRunning(bool running);
|
void start(const QString& posInfo);
|
||||||
|
void stop();
|
||||||
|
|
||||||
Q_SIGNALS:
|
void onHyperExposureComplete(double exposureTime, double frameRate);
|
||||||
void taskStateChanged(TaskState state);
|
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:
|
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
|
class GonggaShanRecordCtl : public QDialog
|
||||||
@ -55,8 +129,18 @@ public Q_SLOTS:
|
|||||||
void onFiberImagerExposureCompleteSignal(int exposureTime);
|
void onFiberImagerExposureCompleteSignal(int exposureTime);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
// Emitted when user changes any of the R/G/B wavelength values
|
void gpsAcquisitionDoneSignal_gonggashan(double lat, double lon, double alt);
|
||||||
void startRcordSignal(QString posInfo);
|
|
||||||
|
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:
|
private Q_SLOTS:
|
||||||
void startListen();
|
void startListen();
|
||||||
@ -64,13 +148,202 @@ private Q_SLOTS:
|
|||||||
|
|
||||||
void startRecord(int position);
|
void startRecord(int position);
|
||||||
|
|
||||||
|
// GonggashanTaskExecutor 反馈槽
|
||||||
|
void onTaskExecutorFinished(bool success);
|
||||||
|
|
||||||
|
void onGpsAcquisition();
|
||||||
|
void onCalculateMotorSpeed(double hyperFrameRate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void logStatus(const QString& message, bool isHearderBlankLine = false, bool isTailBlankLine = false);
|
void logStatus(const QString& message, bool isHearderBlankLine = false, bool isTailBlankLine = false);
|
||||||
|
|
||||||
Ui::gongga_control ui;
|
Ui::gongga_control ui;
|
||||||
QPointer<MotorParams::CommunicationViaTCP> tcpServer6005;
|
QPointer<MotorParams::CommunicationViaTCP> tcpServer6005;
|
||||||
GonggashanTaskScheduler* m_taskScheduler;
|
GonggashanTaskExecutor* m_taskExecutor; // 新增
|
||||||
QString m_logFilePath;
|
QString m_logFilePath;
|
||||||
QFile m_logFile;
|
QFile m_logFile;
|
||||||
QTextStream m_logStream;
|
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()
|
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::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::onFiberImagerExposureCompleteSignal);
|
||||||
|
connect(m_fodisWindow, &FodisWindow::exposureCompleteSignal, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::fiberExposureDoneSignal_gonggashan);
|
||||||
|
|
||||||
connect(m_omc, &OneMotorControl::sequenceComplete, m_fodisWindow, &FodisWindow::closeFiberImager);
|
connect(m_gonggaShanRecordCtl, &GonggaShanRecordCtl::startRcordSignal_gonggashan, this, &HPPA::onGonggashanRecord);
|
||||||
connect(m_omc, &OneMotorControl::sequenceComplete, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::onRcordFinished);
|
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().setFrameRate(f);
|
||||||
//AppSettings::instance().setIntegrationTime(e);
|
//AppSettings::instance().setIntegrationTime(e);
|
||||||
//AppSettings::instance().setDataFolder(filePath);
|
AppSettings::instance().setDataFolder(dataFolder);
|
||||||
|
|
||||||
QString dateStr = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss");
|
QString dateStr = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss");
|
||||||
//QString fi = AppSettings::instance().fileName() + "_" + dateStr;
|
//QString fi = AppSettings::instance().fileName() + "_" + dateStr;
|
||||||
@ -1137,13 +1162,17 @@ void HPPA::onGonggashanRecord(QString posInfo)
|
|||||||
|
|
||||||
//连接马达和光谱仪
|
//连接马达和光谱仪
|
||||||
m_omc->connectMotor(false);
|
m_omc->connectMotor(false);
|
||||||
|
m_omc->setScanSpeed(motorRotationSpeed);
|
||||||
|
|
||||||
if (!testImagerVality())
|
if (!testImagerVality())
|
||||||
{
|
{
|
||||||
onconnect();
|
onconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_fodisWindow->openFiberImager_expose_record(posInfo);
|
onStartRecordStep1();
|
||||||
|
|
||||||
|
//采集rgb图像
|
||||||
|
m_rgbCameraControlWindow->toggleTakePhoto();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HPPA::recordFromRobotArm(int fileCounter)
|
void HPPA::recordFromRobotArm(int fileCounter)
|
||||||
@ -1645,6 +1674,7 @@ void HPPA::createGonggaRotatingPlatformScenario()
|
|||||||
|
|
||||||
m_tabManager->showTab(m_hic);
|
m_tabManager->showTab(m_hic);
|
||||||
m_tabManager->showTab(m_ic);
|
m_tabManager->showTab(m_ic);
|
||||||
|
m_tabManager->showTab(m_rgbCameraControlWindow);
|
||||||
m_tabManager->showTab(m_fodisWindow);
|
m_tabManager->showTab(m_fodisWindow);
|
||||||
m_tabManager->showTab(m_omc);
|
m_tabManager->showTab(m_omc);
|
||||||
m_tabManager->showTab(m_gonggaShanRecordCtl);
|
m_tabManager->showTab(m_gonggaShanRecordCtl);
|
||||||
@ -2571,7 +2601,7 @@ void HPPA::onconnect()
|
|||||||
connect(m_Imager, SIGNAL(RecordDarlFinishSignal()), this, SLOT(recordDarkFinish()));
|
connect(m_Imager, SIGNAL(RecordDarlFinishSignal()), this, SLOT(recordDarkFinish()));
|
||||||
|
|
||||||
// Connect LayerFileCreated from imager to HPPA slot
|
// 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()));
|
connect(this->ui.actionOpenDirectory, SIGNAL(triggered()), this, SLOT(onActionOpenDirectory()));
|
||||||
|
|
||||||
@ -3083,22 +3113,22 @@ void WorkerThread3::run()
|
|||||||
emit AutoFocusFinishedSignal();
|
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 (!m_LayerTreeModel || !m_RasterGroup) return;
|
||||||
|
|
||||||
if (ui.mAction3DPlantPhenotypeScenario->isChecked())
|
if (ui.mAction3DPlantPhenotypeScenario->isChecked())
|
||||||
{
|
{
|
||||||
//addLayer(baseName, filePath, false, false);
|
//addLayer(baseName, filePath, false, false);
|
||||||
addLayer(baseName, filePath, false);
|
addLayer(baseName, filePath, false, true, hyperimagerTppe);
|
||||||
}
|
}
|
||||||
else
|
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
|
// Create MapLayer first and attach it to a LayerTreeLayerNode
|
||||||
RasterLayer* ml = new RasterLayer(baseName, filePath);
|
RasterLayer* ml = new RasterLayer(baseName, filePath);
|
||||||
@ -3115,14 +3145,41 @@ void HPPA::addLayer(const QString& baseName, const QString& filePath,bool refres
|
|||||||
|
|
||||||
if (isAddImage)
|
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());
|
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*>();
|
QList<Mapcavas*> mapcavas = mapcavasContainer->findChildren<Mapcavas*>();
|
||||||
if (mapcavas.size() == 0)
|
if (mapcavas.size() == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
10
HPPA/HPPA.h
10
HPPA/HPPA.h
@ -430,9 +430,9 @@ public Q_SLOTS:
|
|||||||
void createMicroscopicMotionControlScenario();
|
void createMicroscopicMotionControlScenario();
|
||||||
void onCreated3DModelOneMotor();
|
void onCreated3DModelOneMotor();
|
||||||
|
|
||||||
void addLayer(const QString& baseName, const QString& filePath, bool refresh, bool isAddImage = true);
|
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);
|
void newImage(RasterLayer* ml, RasterImageLayer::RendererType, LayerTreeNode* parent, bool refresh=true, const QString& hyperimagerTppe="");
|
||||||
void onLayerCreatedFromFile(const QString& baseName, const QString& filePath, int fileIndex);
|
void onLayerCreatedFromFile(const QString& baseName, const QString& filePath, int fileIndex, const QString& hyperimagerTppe);
|
||||||
void removeLayerByTreeIndex();
|
void removeLayerByTreeIndex();
|
||||||
void removeLayerByNode(LayerTreeNode* node);
|
void removeLayerByNode(LayerTreeNode* node);
|
||||||
void showColorImageByTreeIndex();
|
void showColorImageByTreeIndex();
|
||||||
@ -457,7 +457,9 @@ public Q_SLOTS:
|
|||||||
void onStretchedImageReady(int fileNumber, const QString& filePath, QPixmap& pixmap);
|
void onStretchedImageReady(int fileNumber, const QString& filePath, QPixmap& pixmap);
|
||||||
void onStretchProcessingError(int fileNumber, const QString& filePath, const QString& error);
|
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:
|
protected:
|
||||||
void closeEvent(QCloseEvent* event) override;
|
void closeEvent(QCloseEvent* event) override;
|
||||||
|
|||||||
@ -160,6 +160,7 @@
|
|||||||
<ClCompile Include="recordFrameCounter.cpp" />
|
<ClCompile Include="recordFrameCounter.cpp" />
|
||||||
<ClCompile Include="resononImager.cpp" />
|
<ClCompile Include="resononImager.cpp" />
|
||||||
<ClCompile Include="ResononNirImager.cpp" />
|
<ClCompile Include="ResononNirImager.cpp" />
|
||||||
|
<ClCompile Include="RgbCameraCaptureCoordinator.cpp" />
|
||||||
<ClCompile Include="RgbCameraOperation.cpp" />
|
<ClCompile Include="RgbCameraOperation.cpp" />
|
||||||
<ClCompile Include="rgbCameraWindow.cpp" />
|
<ClCompile Include="rgbCameraWindow.cpp" />
|
||||||
<ClCompile Include="RobotArmControl.cpp" />
|
<ClCompile Include="RobotArmControl.cpp" />
|
||||||
@ -289,6 +290,7 @@
|
|||||||
<ClInclude Include="ResononNirImager.h" />
|
<ClInclude Include="ResononNirImager.h" />
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
<ClInclude Include="stdafx.h" />
|
<ClInclude Include="stdafx.h" />
|
||||||
|
<QtMoc Include="RgbCameraCaptureCoordinator.h" />
|
||||||
<QtMoc Include="RgbCameraOperation.h" />
|
<QtMoc Include="RgbCameraOperation.h" />
|
||||||
<QtMoc Include="resononImager.h" />
|
<QtMoc Include="resononImager.h" />
|
||||||
<QtMoc Include="QMotorDoubleSlider.h" />
|
<QtMoc Include="QMotorDoubleSlider.h" />
|
||||||
|
|||||||
@ -68,11 +68,12 @@ double ImagerOperationBase::auto_exposure()
|
|||||||
|
|
||||||
imagerStopCollect();
|
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()
|
void ImagerOperationBase::focus()
|
||||||
@ -251,7 +252,7 @@ void ImagerOperationBase::start_record()
|
|||||||
m_FileName2Save2 = m_FileName2Save + "_" + std::to_string(m_FileSavedCounter) + ".bil";
|
m_FileName2Save2 = m_FileName2Save + "_" + std::to_string(m_FileSavedCounter) + ".bil";
|
||||||
QString baseName = QString::fromStdString(getFileNameFromPath(m_FileName2Save2));
|
QString baseName = QString::fromStdString(getFileNameFromPath(m_FileName2Save2));
|
||||||
QString filePath = QString::fromStdString(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");
|
FILE* m_fImage = fopen(m_FileName2Save2.c_str(), "w+b");
|
||||||
|
|
||||||
@ -313,7 +314,7 @@ void ImagerOperationBase::start_record()
|
|||||||
fprintf(hTimesFile, "%ll\n", timeOs);
|
fprintf(hTimesFile, "%ll\n", timeOs);
|
||||||
|
|
||||||
//将rgb波段提取出来,以便在界面中显示
|
//将rgb波段提取出来,以便在界面中显示
|
||||||
m_RgbImage->FillRgbImage(buffer);//??????????????????????????????????????????????????????????????????????????????????????????????????????
|
m_RgbImage->FillRgbImage(buffer, 121, 79, 40);//??????????????????????????????????????????????????????????????????????????????????????????????????????
|
||||||
|
|
||||||
//std::cout << "第" << m_iFrameCounter << "帧写了" << x << "个unsigned short。" << std::endl;
|
//std::cout << "第" << m_iFrameCounter << "帧写了" << x << "个unsigned short。" << std::endl;
|
||||||
|
|
||||||
|
|||||||
@ -117,11 +117,11 @@ signals:
|
|||||||
|
|
||||||
|
|
||||||
void testImagerStatus();//表示可以测试相机连接状态:是否连接,并反映到界面上
|
void testImagerStatus();//表示可以测试相机连接状态:是否连接,并反映到界面上
|
||||||
void autoExposureSignal();
|
void autoExposureSignal(double exposureTime);
|
||||||
|
|
||||||
// 新增:当一组影像文件(.bil/.hdr)写入完成后发出(会从采集线程发出,Qt 会做 queued connection)
|
// 新增:当一组影像文件(.bil/.hdr)写入完成后发出(会从采集线程发出,Qt 会做 queued connection)
|
||||||
void ImageFileSaved(const QString& path, int fileIndex);
|
void ImageFileSaved(const QString& path, int fileIndex);
|
||||||
|
|
||||||
// 修改:不再直接发送 MapLayer*,而是发送文件名与文件路径,UI 层负责创建 MapLayer 对象并管理生命周期
|
// 修改:不再直接发送 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.
|
// Created by 73505 on 2023/5/7.
|
||||||
//
|
//
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
#include "JinspFiberImager.h"
|
#include "JinspFiberImager.h"
|
||||||
|
|
||||||
JinspFiberImager::JinspFiberImager(bool bIsUSBMode, std::string ucPortNumber, std::string strDeviceName)
|
JinspFiberImager::JinspFiberImager(bool bIsUSBMode, std::string ucPortNumber, std::string strDeviceName)
|
||||||
@ -132,7 +133,7 @@ void JinspFiberImager::recordDark(QString path)
|
|||||||
outfile.close();
|
outfile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JinspFiberImager::recordTarget(int recordTimes, QString path)
|
void JinspFiberImager::recordTarget2csv(int recordTimes, QString path)
|
||||||
{
|
{
|
||||||
//获取设备信息
|
//获取设备信息
|
||||||
DeviceAttribute attribute;
|
DeviceAttribute attribute;
|
||||||
@ -318,10 +319,8 @@ void JinspFiberImager::setCaptureInterval(int captureIntervalSeconds)
|
|||||||
m_captureIntervalMilliseconds = captureIntervalSeconds * 1000;
|
m_captureIntervalMilliseconds = captureIntervalSeconds * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JinspFiberImager::OpenFiberImagerAndRecord(QString posInfo)
|
void JinspFiberImager::OpenFiberImagerAndRecord(QString filePath)
|
||||||
{
|
{
|
||||||
m_posInfo = posInfo;
|
|
||||||
|
|
||||||
//连接光谱仪
|
//连接光谱仪
|
||||||
QString SN;
|
QString SN;
|
||||||
QString pixelCount;
|
QString pixelCount;
|
||||||
@ -335,13 +334,25 @@ void JinspFiberImager::OpenFiberImagerAndRecord(QString posInfo)
|
|||||||
emit exposureCompleteSignal(m_iExposureTime);
|
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;
|
m_record = true;
|
||||||
|
DataFrame data;
|
||||||
while (m_record)
|
while (m_record)
|
||||||
{
|
{
|
||||||
recordTarget(1, AppSettings::instance().FiberImagerDataFolder());
|
singleShot(data);
|
||||||
|
qfData.write((char*)&data, sizeof(DataFrame));
|
||||||
|
qfData.flush();
|
||||||
|
|
||||||
QThread::msleep(m_captureIntervalMilliseconds);
|
QThread::msleep(m_captureIntervalMilliseconds);
|
||||||
}
|
}
|
||||||
|
qfData.close();
|
||||||
|
|
||||||
std::cout << "close.........." << std::endl;
|
std::cout << "close.........." << std::endl;
|
||||||
m_FiberSpectrometer->Close();
|
m_FiberSpectrometer->Close();
|
||||||
|
|||||||
@ -61,10 +61,10 @@ private:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void recordDark(QString path);
|
void recordDark(QString path);
|
||||||
void recordTarget(int recordTimes, QString path);
|
void recordTarget2csv(int recordTimes, QString path);
|
||||||
void autoExpose();
|
void autoExpose();
|
||||||
|
|
||||||
void OpenFiberImagerAndRecord(QString posInfo);
|
void OpenFiberImagerAndRecord(QString filePath);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sendExposureTimeSignal(int exposureTime);
|
void sendExposureTimeSignal(int exposureTime);
|
||||||
|
|||||||
@ -42,6 +42,11 @@ void OneMotorControl::onConnectMotor()
|
|||||||
connectMotor(true);
|
connectMotor(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OneMotorControl::setScanSpeed(double speed)
|
||||||
|
{
|
||||||
|
ui.speed_lineEdit->setText(QString::number(speed));
|
||||||
|
}
|
||||||
|
|
||||||
void OneMotorControl::connectMotor(bool isNotification)
|
void OneMotorControl::connectMotor(bool isNotification)
|
||||||
{
|
{
|
||||||
if (getMotorsConnectionStatus())
|
if (getMotorsConnectionStatus())
|
||||||
@ -225,16 +230,20 @@ void OneMotorControl::run()
|
|||||||
{
|
{
|
||||||
if (m_coordinator)//当高光谱相机停止采集后,马达还未回到原点时,上次任务的m_coordinator还没有被销毁
|
if (m_coordinator)//当高光谱相机停止采集后,马达还未回到原点时,上次任务的m_coordinator还没有被销毁
|
||||||
{
|
{
|
||||||
onSequenceComplete(0);
|
onSequenceComplete_motorBack2Origin(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
qRegisterMetaType<OneMotionCapturePathLine>("OneMotionCapturePathLine");
|
qRegisterMetaType<OneMotionCapturePathLine>("OneMotionCapturePathLine");
|
||||||
m_coordinator = new OneMotionCaptureCoordinator(m_multiAxisController, m_Imager);
|
m_coordinator = new OneMotionCaptureCoordinator(m_multiAxisController, m_Imager);
|
||||||
m_coordinator->setObjectName("testOneMotionCaptureCoordinator");
|
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;
|
OneMotionCapturePathLine tmp;
|
||||||
tmp.speedRecord = ui.speed_lineEdit->text().toDouble();
|
tmp.speedRecord = ui.speed_lineEdit->text().toDouble();
|
||||||
@ -248,13 +257,37 @@ void OneMotorControl::stop()
|
|||||||
emit stopStepMotionSignal();
|
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)));
|
std::vector<double> locations;
|
||||||
disconnect(this, SIGNAL(stopStepMotionSignal()), m_coordinator, SLOT(stopStepMotion()));
|
locations.push_back(maxPos * 0.2);
|
||||||
disconnect(m_coordinator, SIGNAL(sequenceComplete(int)), this, SLOT(onSequenceComplete(int)));
|
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
|
// Use deleteLater() instead of delete: this slot may have been called directly
|
||||||
// from OneMotionCaptureCoordinator's call stack (direct connection), so deleting
|
// from OneMotionCaptureCoordinator's call stack (direct connection), so deleting
|
||||||
|
|||||||
@ -26,6 +26,8 @@ public:
|
|||||||
void run();
|
void run();
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
void multiPosHyperAutoExposure();
|
||||||
|
|
||||||
void record_dark();
|
void record_dark();
|
||||||
void record_white();
|
void record_white();
|
||||||
|
|
||||||
@ -33,6 +35,8 @@ public:
|
|||||||
|
|
||||||
void connectMotor(bool isNotification);
|
void connectMotor(bool isNotification);
|
||||||
|
|
||||||
|
void setScanSpeed(double speed);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void onConnectMotor();
|
void onConnectMotor();
|
||||||
|
|
||||||
@ -46,7 +50,8 @@ public Q_SLOTS:
|
|||||||
void onxMotorLeft();
|
void onxMotorLeft();
|
||||||
void onxMotorStop();
|
void onxMotorStop();
|
||||||
|
|
||||||
void onSequenceComplete(int state);
|
void onSequenceComplete_motorBack2Origin(int state);
|
||||||
|
void onSequenceComplete_gonggashan_autoexpose(int state);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void moveSignal(int, bool, double, int);
|
void moveSignal(int, bool, double, int);
|
||||||
@ -62,9 +67,16 @@ signals:
|
|||||||
void stopStepMotionSignal();
|
void stopStepMotionSignal();
|
||||||
|
|
||||||
void sequenceComplete();
|
void sequenceComplete();
|
||||||
|
void sequenceComplete_motorBack2Origin();
|
||||||
|
|
||||||
void broadcastLocationSignal(std::vector<double>);
|
void broadcastLocationSignal(std::vector<double>);
|
||||||
|
|
||||||
|
void hyperAutoExposureDoneSignal_gonggashan(double exposureTime, double frameRate);
|
||||||
|
|
||||||
|
void multiPosAutoexposeSequenceCompleteSignal();
|
||||||
|
|
||||||
|
void sequenceCompleteSignal_hyperImagerStopRecord(int);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::OneMotorControl_UI ui;
|
Ui::OneMotorControl_UI ui;
|
||||||
|
|
||||||
@ -78,6 +90,8 @@ private:
|
|||||||
DarkAndWhiteCaptureCoordinator* m_whiteCaptureCoordinator = nullptr;
|
DarkAndWhiteCaptureCoordinator* m_whiteCaptureCoordinator = nullptr;
|
||||||
|
|
||||||
bool m_xMotorConnectionStatus = false;
|
bool m_xMotorConnectionStatus = false;
|
||||||
|
|
||||||
|
QPointer<OneMotorMultiPosCoordinator> m_coordinator_gonggashan_autoexpose;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OneMotorControl_LiftingPlatform : public QDialog, public MotorWindowBase
|
class OneMotorControl_LiftingPlatform : public QDialog, public MotorWindowBase
|
||||||
@ -128,6 +142,7 @@ signals:
|
|||||||
|
|
||||||
void broadcastLocationSignal(std::vector<double>);
|
void broadcastLocationSignal(std::vector<double>);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::OneMotorControl_UI ui;
|
Ui::OneMotorControl_UI ui;
|
||||||
|
|
||||||
|
|||||||
@ -5,11 +5,39 @@
|
|||||||
#include "MultibandRasterRenderer.h"
|
#include "MultibandRasterRenderer.h"
|
||||||
#include "SinglebandRasterRenderer.h"
|
#include "SinglebandRasterRenderer.h"
|
||||||
|
|
||||||
RasterImageLayer::RasterImageLayer(RasterLayer* layer, RendererType type)
|
RasterImageLayer::RasterImageLayer(RasterLayer* layer, RendererType type, bool initRenderParamsFromFile)
|
||||||
: m_layer(layer)
|
: m_layer(layer)
|
||||||
, m_rendererType(type)
|
, m_rendererType(type)
|
||||||
, m_rendererInitialized(false)
|
, 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()
|
void RasterImageLayer::ensureRenderer()
|
||||||
|
|||||||
@ -19,7 +19,7 @@ public:
|
|||||||
Singleband
|
Singleband
|
||||||
};
|
};
|
||||||
|
|
||||||
RasterImageLayer(RasterLayer* layer, RendererType type);
|
RasterImageLayer(RasterLayer* layer, RendererType type, bool initRenderParamsFromFile);
|
||||||
~RasterImageLayer();
|
~RasterImageLayer();
|
||||||
|
|
||||||
void ensureRenderer();
|
void ensureRenderer();
|
||||||
|
|||||||
@ -104,20 +104,25 @@ void ResononNirImager::setSpectraBin(int new_spectral_bin)
|
|||||||
double ResononNirImager::auto_exposure()
|
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();
|
reConnectImage();
|
||||||
setIntegrationTime(x);
|
setIntegrationTime(x);
|
||||||
|
|
||||||
//第二步:通过循环寻找最佳曝光时间
|
//第二步:通过循环寻找最佳曝光时间
|
||||||
imagerStartCollect();
|
imagerStartCollect();
|
||||||
|
|
||||||
|
double tmpTime;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
getFrame(buffer);
|
getFrame(buffer);
|
||||||
if (GetMaxValue(buffer, m_FrameSize) >= 4095)
|
if (GetMaxValue(buffer, m_FrameSize) >= 16383)
|
||||||
{
|
{
|
||||||
setIntegrationTime(getIntegrationTime() * 0.8);
|
tmpTime = getIntegrationTime() * 0.8;
|
||||||
std::cout << "自动曝光-----------" << std::endl;
|
setIntegrationTime(tmpTime);
|
||||||
|
std::cout << "自动曝光-----------:" << tmpTime << std::endl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -128,9 +133,28 @@ double ResononNirImager::auto_exposure()
|
|||||||
reConnectImage();
|
reConnectImage();
|
||||||
//imagerStopCollect();
|
//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)
|
double ResononNirImager::getWavelengthAtBand(int band)
|
||||||
@ -290,7 +314,7 @@ void ResononNirImager::start_record()
|
|||||||
m_FileName2Save2 = m_FileName2Save + "_" + std::to_string(m_FileSavedCounter) + ".bil";
|
m_FileName2Save2 = m_FileName2Save + "_" + std::to_string(m_FileSavedCounter) + ".bil";
|
||||||
QString baseName = QString::fromStdString(getFileNameFromPath(m_FileName2Save2));
|
QString baseName = QString::fromStdString(getFileNameFromPath(m_FileName2Save2));
|
||||||
QString filePath = QString::fromStdString(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");
|
FILE* m_fImage = fopen(m_FileName2Save2.c_str(), "w+b");
|
||||||
|
|
||||||
@ -352,7 +376,8 @@ void ResononNirImager::start_record()
|
|||||||
fprintf(hTimesFile, "%ll\n", timeOs);
|
fprintf(hTimesFile, "%ll\n", timeOs);
|
||||||
|
|
||||||
//将rgb波段提取出来,以便在界面中显示
|
//将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;
|
//std::cout << "第" << m_iFrameCounter << "帧写了" << x << "个unsigned short。" << std::endl;
|
||||||
|
|
||||||
@ -408,7 +433,7 @@ void ResononNirImager::WriteHdr()
|
|||||||
outfile << "ENVI\n";
|
outfile << "ENVI\n";
|
||||||
outfile << "interleave = bil\n";
|
outfile << "interleave = bil\n";
|
||||||
outfile << "data type = 12\n";
|
outfile << "data type = 12\n";
|
||||||
outfile << "bit depth = 12\n";
|
outfile << "bit depth = 14\n";
|
||||||
outfile << "byte order = 0\n";
|
outfile << "byte order = 0\n";
|
||||||
outfile << "samples = " << getSampleCount() << "\n";
|
outfile << "samples = " << getSampleCount() << "\n";
|
||||||
outfile << "bands = " << getBandCount() << "\n";
|
outfile << "bands = " << getBandCount() << "\n";
|
||||||
|
|||||||
@ -38,6 +38,8 @@ public:
|
|||||||
void WriteHdr();
|
void WriteHdr();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
unsigned short GetMaxValue(unsigned short* dark, int number);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reConnectImage();
|
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 "stdafx.h"
|
||||||
#include "RgbCameraOperation.h"
|
#include "RgbCameraOperation.h"
|
||||||
|
#include "AppSettings.h"
|
||||||
|
|
||||||
RgbCameraOperation::RgbCameraOperation()
|
RgbCameraOperation::RgbCameraOperation()
|
||||||
{
|
{
|
||||||
cam = nullptr;
|
cam = nullptr;
|
||||||
m_ImageProcessor = new ImageProcessor();
|
m_ImageProcessor = new ImageProcessor();
|
||||||
m_func = nullptr;
|
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()
|
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()
|
void RgbCameraOperation::OpenCamera()
|
||||||
@ -17,21 +57,80 @@ void RgbCameraOperation::OpenCamera()
|
|||||||
std::cout << "打开摄像头+++++++++++++++++++++++++++++++++++++++++++" << std::endl;
|
std::cout << "打开摄像头+++++++++++++++++++++++++++++++++++++++++++" << std::endl;
|
||||||
cam = new cv::VideoCapture(0);
|
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;
|
record = true;
|
||||||
|
|
||||||
while (record)
|
// 使用定时器定期获取图像,不再阻塞线程
|
||||||
{
|
m_captureTimer->start(33); // ~30fps
|
||||||
//std::cout << "采集影像+++++++++++++++++++++++++++++++++++++++++++" << std::endl;
|
m_frameCounter = 0;
|
||||||
cam->read(frame);
|
}
|
||||||
m_qImage = m_ImageProcessor->Mat2QImage(frame);
|
|
||||||
|
|
||||||
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()
|
void RgbCameraOperation::OpenCamera_callback()
|
||||||
@ -66,5 +165,117 @@ void RgbCameraOperation::CloseCamera()
|
|||||||
|
|
||||||
record = false;
|
record = false;
|
||||||
|
|
||||||
|
// 停止定时器
|
||||||
|
m_captureTimer->stop();
|
||||||
|
m_photoSaveTimer->stop();
|
||||||
|
|
||||||
|
// 停止视频录制
|
||||||
|
if (m_isRecording)
|
||||||
|
{
|
||||||
|
stopVideoRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放摄像头
|
||||||
|
if (cam != nullptr)
|
||||||
|
{
|
||||||
|
cam->release();
|
||||||
|
//delete cam;
|
||||||
|
cam = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
emit CamClosedSignal();
|
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 <QObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <opencv2/opencv.hpp>
|
#include <opencv2/opencv.hpp>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
|
||||||
@ -24,6 +27,12 @@ public:
|
|||||||
QImage m_qImage;
|
QImage m_qImage;
|
||||||
void setCallback(void(*func)());
|
void setCallback(void(*func)());
|
||||||
|
|
||||||
|
// 保存图片和视频的公共接口
|
||||||
|
void saveImage(); // 保存当前帧为图片
|
||||||
|
void startVideoRecording(); // 开始视频录制
|
||||||
|
void stopVideoRecording(); // 停止视频录制
|
||||||
|
bool isRecording() const { return m_isRecording; } // 获取录制状态
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cv::Mat frame;
|
cv::Mat frame;
|
||||||
cv::VideoCapture *cam;
|
cv::VideoCapture *cam;
|
||||||
@ -34,15 +43,33 @@ private:
|
|||||||
|
|
||||||
bool record;
|
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:
|
public slots:
|
||||||
void OpenCamera();
|
void OpenCamera();
|
||||||
void OpenCamera_callback();//不使用信号而使用回调函数来通知界面刷新视频
|
void OpenCamera_callback();//不使用信号而使用回调函数来通知界面刷新视频
|
||||||
void CloseCamera();
|
void CloseCamera();
|
||||||
|
void startPhotoSaveTimer();
|
||||||
signals:
|
void stopPhotoSaveTimer();
|
||||||
void PlotSignal();
|
|
||||||
|
|
||||||
void CamOpenedSignal();
|
|
||||||
void CamClosedSignal();
|
|
||||||
};
|
};
|
||||||
#endif // !RGBCAMERAOPERATION_H
|
#endif // !RGBCAMERAOPERATION_H
|
||||||
|
|||||||
@ -288,7 +288,7 @@ QPushButton:pressed
|
|||||||
}</string>
|
}</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>版本:3.1.3</string>
|
<string>版本:3.1.4</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
100
HPPA/fodis.ui
100
HPPA/fodis.ui
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>857</width>
|
<width>438</width>
|
||||||
<height>477</height>
|
<height>330</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -83,7 +83,7 @@ QPushButton:pressed
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1" colspan="2">
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QPushButton" name="close_btn">
|
<widget class="QPushButton" name="close_btn">
|
||||||
@ -113,33 +113,7 @@ QPushButton:pressed
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="1" colspan="2">
|
||||||
<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">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
@ -184,7 +158,71 @@ QPushButton:pressed
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</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">
|
<spacer name="verticalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
|
|||||||
@ -64,7 +64,7 @@ void CImage::SetRgbImageWidthAndHeight(int BandCount, int Sample, int FrameNumbe
|
|||||||
//std::cout << "rgb影像内存地址为:" << m_QRgbImage << std::endl;
|
//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==unsigned char,内存大小:1个字节,范围为0-255
|
||||||
//uchar * imagebits24 = m_QRgbImage->bits();
|
//uchar * imagebits24 = m_QRgbImage->bits();
|
||||||
@ -78,9 +78,9 @@ void CImage::FillRgbImage(unsigned short *datacube)
|
|||||||
//std::cout << "rgb图像写入数据帧数:" << j << std::endl;
|
//std::cout << "rgb图像写入数据帧数:" << j << std::endl;
|
||||||
|
|
||||||
//取值:一帧影像中,从左到右的rgb像元值
|
//取值:一帧影像中,从左到右的rgb像元值
|
||||||
r = *(datacube + 121 * m_iSampleNumber + j);
|
r = *(datacube + rBandNumber * m_iSampleNumber + j);
|
||||||
g = *(datacube + 79 * m_iSampleNumber + j);
|
g = *(datacube + gBandNumber * m_iSampleNumber + j);
|
||||||
b = *(datacube + 40 * m_iSampleNumber + j);
|
b = *(datacube + bBandNumber * m_iSampleNumber + j);
|
||||||
|
|
||||||
//将像元值赋值到cv::Mat中,操作像元值:https://zhuanlan.zhihu.com/p/51842288
|
//将像元值赋值到cv::Mat中,操作像元值:https://zhuanlan.zhihu.com/p/51842288
|
||||||
//int dataType = m_matRgbImage->type();//当数据类型为CV_16UC3时,返回18
|
//int dataType = m_matRgbImage->type();//当数据类型为CV_16UC3时,返回18
|
||||||
|
|||||||
@ -21,7 +21,7 @@ public:
|
|||||||
CImage(QWidget* pParent = NULL);
|
CImage(QWidget* pParent = NULL);
|
||||||
//~CImage();
|
//~CImage();
|
||||||
void SetRgbImageWidthAndHeight(int BandCount, int Sample, int FrameNumber);
|
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 FillFocusGrayImage(unsigned short *datacube);
|
||||||
void FillFocusGrayQImage(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);
|
QImage::Format_RGB888);
|
||||||
}
|
}
|
||||||
|
|
||||||
return qImg;
|
return qImg.copy(); // 返回独立数据副本,避免cvImg被覆盖导致QImage数据失效
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::Mat ImageProcessor::CStretchDeal(const cv::Mat img, const uint minnum, const uint maxnum)
|
cv::Mat ImageProcessor::CStretchDeal(const cv::Mat img, const uint minnum, const uint maxnum)
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>416</width>
|
<width>489</width>
|
||||||
<height>219</height>
|
<height>329</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -70,18 +70,50 @@ QPushButton:pressed
|
|||||||
}</string>
|
}</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="0" column="1">
|
<item row="2" column="1">
|
||||||
<spacer name="verticalSpacer">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<property name="orientation">
|
<item>
|
||||||
<enum>Qt::Vertical</enum>
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QLabel {
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
}</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="text">
|
||||||
<size>
|
<string>数据路径</string>
|
||||||
<width>18</width>
|
|
||||||
<height>100</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</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>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
@ -96,6 +128,19 @@ QPushButton:pressed
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</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">
|
<item row="1" column="1">
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
@ -165,7 +210,7 @@ QPushButton:pressed
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="4" column="1">
|
||||||
<spacer name="verticalSpacer_3">
|
<spacer name="verticalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
@ -178,6 +223,44 @@ QPushButton:pressed
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</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>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
#include "rgbCameraWindow.h"
|
#include "rgbCameraWindow.h"
|
||||||
#include <Qthread>
|
#include <QThread>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include "AppSettings.h"
|
||||||
|
|
||||||
rgbCameraWindow::rgbCameraWindow(QWidget* parent)
|
rgbCameraWindow::rgbCameraWindow(QWidget* parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
|
, m_captureCoordinator(nullptr)
|
||||||
{
|
{
|
||||||
ui.setupUi(this);
|
ui.setupUi(this);
|
||||||
|
|
||||||
@ -11,22 +14,190 @@ rgbCameraWindow::rgbCameraWindow(QWidget* parent)
|
|||||||
m_RgbCamera->moveToThread(m_RgbCameraThread);
|
m_RgbCamera->moveToThread(m_RgbCameraThread);
|
||||||
m_RgbCameraThread->start();
|
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()));
|
connect(m_RgbCamera, SIGNAL(PlotSignal()), this, SIGNAL(PlotRgbImageSignal()));
|
||||||
|
|
||||||
//m_RgbCamera->setCallback(onPlotRgbImage);
|
connect(ui.open_rgb_camera_btn, &QPushButton::clicked,
|
||||||
//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>
|
this, [this]() { if (m_captureCoordinator) m_captureCoordinator->openCamera(); });
|
||||||
|
|
||||||
connect(ui.close_rgb_camera_btn, SIGNAL(clicked()), this, SLOT(onCloseRgbCamera()));//<2F>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
connect(m_RgbCamera, SIGNAL(CamClosedSignal()), this, SIGNAL(CamClosedSignal()));
|
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()
|
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;
|
emit ui.take_photo_btn->clicked();
|
||||||
m_RgbCamera->CloseCamera();
|
}
|
||||||
|
|
||||||
|
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 <QDialog>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
@ -8,6 +8,7 @@
|
|||||||
#include "ui_rgbCamera.h"
|
#include "ui_rgbCamera.h"
|
||||||
|
|
||||||
#include "RgbCameraOperation.h"
|
#include "RgbCameraOperation.h"
|
||||||
|
#include "RgbCameraCaptureCoordinator.h"
|
||||||
|
|
||||||
class rgbCameraWindow : public QDialog
|
class rgbCameraWindow : public QDialog
|
||||||
{
|
{
|
||||||
@ -19,16 +20,43 @@ public:
|
|||||||
|
|
||||||
RgbCameraOperation* m_RgbCamera;
|
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 PlotRgbImageSignal();
|
||||||
void CamClosedSignal();
|
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:
|
private:
|
||||||
Ui::rgbCameraClass ui;
|
Ui::rgbCameraClass ui;
|
||||||
|
|
||||||
|
QThread* m_RgbCameraThread;//rgb相机获取图像线程
|
||||||
|
RgbCameraCaptureCoordinator* m_captureCoordinator;
|
||||||
|
|
||||||
QThread* m_RgbCameraThread;//rgb<67><62><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡͼ<C8A1><CDBC><EFBFBD>߳<EFBFBD>
|
void setDataFolder(QString dir);
|
||||||
|
void setFileName(QString name);
|
||||||
|
void loadSettings();
|
||||||
|
void saveSettings();
|
||||||
|
void setupCaptureCoordinator();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user