Compare commits
9 Commits
3feefe45c1
...
3.1.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 392bc98ebf | |||
| 0866b9cd56 | |||
| 33e34aa125 | |||
| abdb27b228 | |||
| 64cdc7591d | |||
| f00fc6fdea | |||
| 10beb03843 | |||
| 64bc8a9d27 | |||
| 6b63d28d2c |
@ -467,7 +467,7 @@ OneMotionCaptureCoordinator::~OneMotionCaptureCoordinator()
|
||||
this, &OneMotionCaptureCoordinator::handleMotorStoped);
|
||||
}
|
||||
|
||||
void OneMotionCaptureCoordinator::startStepMotion(OneMotionCapturePathLine pathLine)
|
||||
void OneMotionCaptureCoordinator::startStepMotion(OneMotionCapturePathLine pathLine)//这个函数为啥被调用了2次?
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
@ -498,13 +498,14 @@ void OneMotionCaptureCoordinator::stopStepMotion()
|
||||
m_cameraCtrl->stop_record();
|
||||
}
|
||||
|
||||
//emit stopMotorSignal(0);
|
||||
move2LocBeforeStart();
|
||||
emit stopMotorSignal(0);
|
||||
m_isHypercamStopRecord = true;
|
||||
}
|
||||
|
||||
void OneMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet()
|
||||
{
|
||||
emit stopMotorSignal(0);
|
||||
m_isHypercamStopRecord = true;
|
||||
}
|
||||
|
||||
void OneMotionCaptureCoordinator::getLocBeforeStart()
|
||||
@ -568,10 +569,12 @@ bool OneMotionCaptureCoordinator::saveToCsv(const QString& filename)
|
||||
|
||||
void OneMotionCaptureCoordinator::handleMotorStoped(int motorID, double pos)
|
||||
{
|
||||
if (!m_isRunning) return;
|
||||
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
if (m_isHypercamStopRecord == true)
|
||||
{
|
||||
m_isHypercamStopRecord = false;
|
||||
|
||||
// 记录位置信息
|
||||
m_pathLine.stopPosition = pos;
|
||||
m_pathLine.timestamp2 = QDateTime::currentDateTime();
|
||||
@ -584,9 +587,14 @@ void OneMotionCaptureCoordinator::handleMotorStoped(int motorID, double pos)
|
||||
}
|
||||
move2LocBeforeStart();
|
||||
|
||||
emit sequenceComplete_cam_stop_before_motorback(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// emit sequenceComplete last: the slot connected to it may delete this object,
|
||||
// so no member access is allowed after this point.
|
||||
emit sequenceComplete(0);
|
||||
}
|
||||
}
|
||||
|
||||
void OneMotionCaptureCoordinator::handleCaptureComplete(double index)
|
||||
@ -716,3 +724,251 @@ void DarkAndWhiteCaptureCoordinator::handleCaptureComplete(double index)
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
}
|
||||
|
||||
|
||||
TwoMotor1PosCoordinator::TwoMotor1PosCoordinator(
|
||||
IrisMultiMotorController* motorCtrl,
|
||||
QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_motorCtrl(motorCtrl)
|
||||
, m_isMoving2Target(false)
|
||||
, m_isMoving2Origin(false)
|
||||
, m_targetX(0)
|
||||
, m_targetY(0)
|
||||
, m_speedX(0)
|
||||
, m_speedY(0)
|
||||
, m_actualX(0)
|
||||
, m_actualY(0)
|
||||
, m_retryTimesX(0)
|
||||
, m_retryTimesY(0)
|
||||
, m_xReached(false)
|
||||
, m_yReached(false)
|
||||
{
|
||||
//因为IrisMultiMotorController::moveTo有多个重载版本,所以使用信号槽连接时需要使用SIGNAL和SLOT宏来指定参数类型,避免编译器无法推断出正确的函数签名。
|
||||
//connect(this, &TwoMotor1PosCoordinator::moveTo, m_motorCtrl, &IrisMultiMotorController::moveTo);//这行代码会报错,因为moveTo有多个重载版本,编译器无法推断出正确的函数签名。
|
||||
connect(this, SIGNAL(moveTo(int, double, double, int)), m_motorCtrl, SLOT(moveTo(int, double, double, int)));
|
||||
connect(this, SIGNAL(moveTo(const std::vector<double>, const std::vector<double>, int)), m_motorCtrl, SLOT(moveTo(const std::vector<double>, const std::vector<double>, int)));
|
||||
|
||||
|
||||
connect(this, &TwoMotor1PosCoordinator::stopMotorSignal, m_motorCtrl, &IrisMultiMotorController::stop);
|
||||
|
||||
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal, this, &TwoMotor1PosCoordinator::handlePositionReached);
|
||||
}
|
||||
|
||||
TwoMotor1PosCoordinator::~TwoMotor1PosCoordinator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TwoMotor1PosCoordinator::moveToTarget(double xTarget, double yTarget, double xSpeed, double ySpeed)
|
||||
{
|
||||
m_isMoving2Target = true;
|
||||
m_isMoving2Origin = false;
|
||||
|
||||
moveToTargetPrivate(xTarget, yTarget, xSpeed, ySpeed);
|
||||
}
|
||||
|
||||
void TwoMotor1PosCoordinator::back2origin()
|
||||
{
|
||||
m_isMoving2Target = false;
|
||||
m_isMoving2Origin = true;
|
||||
|
||||
moveToTargetPrivate(0, 0, m_speedX, m_speedY);
|
||||
}
|
||||
|
||||
void TwoMotor1PosCoordinator::moveToTargetPrivate(double xTarget, double yTarget, double xSpeed, double ySpeed)
|
||||
{
|
||||
m_targetX = xTarget;
|
||||
m_targetY = yTarget;
|
||||
m_speedX = xSpeed;
|
||||
m_speedY = ySpeed;
|
||||
|
||||
m_xReached = false;
|
||||
m_yReached = false;
|
||||
m_retryTimesX = 0;
|
||||
m_retryTimesY = 0;
|
||||
|
||||
std::vector<double> loc = { m_targetX, m_targetY };
|
||||
std::vector<double> speed = { m_speedX, m_speedY };
|
||||
|
||||
std::cout << "TwoMotor1PosCoordinator: moving to (" << m_targetX << ", " << m_targetY << ")" << std::endl;
|
||||
emit moveTo(loc, speed, 1000);
|
||||
}
|
||||
|
||||
void TwoMotor1PosCoordinator::handlePositionReached(int motorID, double pos)
|
||||
{
|
||||
if (!m_isMoving2Target && !m_isMoving2Origin)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double errorRateThreshold = 5;
|
||||
if (motorID == 0)
|
||||
{
|
||||
m_actualX = pos;
|
||||
|
||||
double errorRate = getErrorRate(m_targetX, m_actualX);
|
||||
|
||||
if (errorRate > errorRateThreshold && m_retryTimesX < m_retryLimit)
|
||||
{
|
||||
m_retryTimesX++;
|
||||
std::cout << "X motor retry " << m_retryTimesX << ", target: " << m_targetX << ", actual: " << m_actualX << std::endl;
|
||||
emit moveTo(0, m_targetX, m_speedX, 1000);
|
||||
return;
|
||||
}
|
||||
m_retryTimesX = 0;
|
||||
m_xReached = true;
|
||||
|
||||
std::cout << "X motor reached: " << m_actualX << std::endl;
|
||||
}
|
||||
else if (motorID == 1)
|
||||
{
|
||||
m_actualY = pos;
|
||||
|
||||
double errorRate = getErrorRate(m_targetY, m_actualY);
|
||||
if (errorRate > errorRateThreshold && m_retryTimesY < m_retryLimit)
|
||||
{
|
||||
m_retryTimesY++;
|
||||
std::cout << "Y motor retry " << m_retryTimesY << ", target: " << m_targetY << ", actual: " << m_actualY << std::endl;
|
||||
emit moveTo(1, m_targetY, m_speedY, 1000);
|
||||
return;
|
||||
}
|
||||
m_retryTimesY = 0;
|
||||
m_yReached = true;
|
||||
|
||||
std::cout << "Y motor reached: " << m_actualY << std::endl;
|
||||
}
|
||||
|
||||
if (checkArrival())
|
||||
{
|
||||
std::cout << "TwoMotor1PosCoordinator: Arrived at (" << m_actualX << ", " << m_actualY << ")" << std::endl;
|
||||
|
||||
if (m_isMoving2Origin)
|
||||
{
|
||||
m_isMoving2Origin = false;
|
||||
|
||||
emit back2OriginSignal();
|
||||
}
|
||||
|
||||
if (m_isMoving2Target)
|
||||
{
|
||||
m_isMoving2Target = false;
|
||||
|
||||
emit ArrivalSignal(m_actualX, m_actualY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double TwoMotor1PosCoordinator::getErrorRate(double targetLoc, double actualLoc)
|
||||
{
|
||||
double targetLocTmp;
|
||||
if (targetLoc == 0)
|
||||
{
|
||||
targetLocTmp = 0.001;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetLocTmp = targetLoc;
|
||||
}
|
||||
double errorRate = abs(targetLoc - actualLoc) / targetLocTmp * 100;
|
||||
|
||||
return errorRate;
|
||||
}
|
||||
|
||||
bool TwoMotor1PosCoordinator::checkArrival()
|
||||
{
|
||||
return m_xReached && m_yReached;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
OneMotionCoordinator::OneMotionCoordinator(IrisMultiMotorController* motorCtrl, QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_motorCtrl(motorCtrl)
|
||||
, m_targetPosition(0)
|
||||
, m_speed(0)
|
||||
, m_actualPosition(0)
|
||||
, m_isMoving(false)
|
||||
, m_retryTimes(0)
|
||||
, m_reached(false)
|
||||
{
|
||||
connect(this, SIGNAL(moveTo(int, double, double, int)), m_motorCtrl, SLOT(moveTo(int, double, double, int)));
|
||||
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal, this, &OneMotionCoordinator::handlePositionReached);
|
||||
}
|
||||
|
||||
OneMotionCoordinator::~OneMotionCoordinator()
|
||||
{
|
||||
}
|
||||
|
||||
void OneMotionCoordinator::moveToTarget(double position, double speed)
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
m_targetPosition = position;
|
||||
m_speed = speed;
|
||||
m_retryTimes = 0;
|
||||
m_reached = false;
|
||||
m_isMoving = true;
|
||||
|
||||
qDebug() << "OneMotionCoordinator: moving to" << position;
|
||||
emit moveTo(0, position, speed, 1000);
|
||||
}
|
||||
|
||||
void OneMotionCoordinator::handlePositionReached(int motorID, double position)
|
||||
{
|
||||
if (!m_isMoving || motorID != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
m_actualPosition = position;
|
||||
|
||||
double errorRate = getErrorRate(m_targetPosition, m_actualPosition);
|
||||
|
||||
if (errorRate > 5 && m_retryTimes < m_retryLimit)
|
||||
{
|
||||
m_retryTimes++;
|
||||
qDebug() << "OneMotionCoordinator: retry" << m_retryTimes << ", target:" << m_targetPosition << ", actual:" << m_actualPosition;
|
||||
emit moveTo(0, m_targetPosition, m_speed, 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
m_retryTimes = 0;
|
||||
m_reached = true;
|
||||
m_isMoving = false;
|
||||
|
||||
qDebug() << "OneMotionCoordinator: Arrived at" << m_actualPosition;
|
||||
|
||||
emit sequenceComplete(0);
|
||||
emit ArrivalSignal(m_actualPosition);
|
||||
}
|
||||
|
||||
double OneMotionCoordinator::getErrorRate(double targetLoc, double actualLoc)
|
||||
{
|
||||
double targetLocTmp;
|
||||
if (targetLoc == 0)
|
||||
{
|
||||
targetLocTmp = 0.001;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetLocTmp = targetLoc;
|
||||
}
|
||||
double errorRate = abs(targetLoc - actualLoc) / targetLocTmp * 100;
|
||||
|
||||
return errorRate;
|
||||
}
|
||||
|
||||
@ -144,6 +144,7 @@ public slots:
|
||||
void handleCaptureCompleteWhenFrameNumberMeet();
|
||||
|
||||
signals:
|
||||
void sequenceComplete_cam_stop_before_motorback(int);
|
||||
void sequenceComplete(int);
|
||||
void errorOccurred(const QString& error);
|
||||
void moveTo(int, double, double, int);
|
||||
@ -165,6 +166,7 @@ private:
|
||||
mutable QMutex m_dataMutex;
|
||||
|
||||
bool m_isRunning;
|
||||
bool m_isHypercamStopRecord = false;
|
||||
|
||||
std::vector<double> m_locBeforeStart;
|
||||
void getLocBeforeStart();
|
||||
@ -211,3 +213,90 @@ private:
|
||||
void getLocBeforeStart();
|
||||
void move2LocBeforeStart();
|
||||
};
|
||||
|
||||
|
||||
class TwoMotor1PosCoordinator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TwoMotor1PosCoordinator(IrisMultiMotorController* motorCtrl,
|
||||
QObject* parent = nullptr);
|
||||
~TwoMotor1PosCoordinator();
|
||||
|
||||
public slots:
|
||||
void moveToTarget(double xTarget, double yTarget, double xSpeed, double ySpeed);
|
||||
void back2origin();
|
||||
|
||||
signals:
|
||||
void ArrivalSignal(double xPos, double yPos);
|
||||
void back2OriginSignal();
|
||||
void errorOccurred(const QString& error);
|
||||
void moveTo(int, double, double, int);
|
||||
void moveTo(const std::vector<double>, const std::vector<double>, int);
|
||||
void stopMotorSignal(int axis);
|
||||
|
||||
private slots:
|
||||
void handlePositionReached(int motorID, double pos);
|
||||
|
||||
private:
|
||||
void moveToTargetPrivate(double xTarget, double yTarget, double xSpeed, double ySpeed);
|
||||
double getErrorRate(double targetLoc, double actualLoc);
|
||||
bool checkArrival();
|
||||
void move2Origin();
|
||||
|
||||
IrisMultiMotorController* m_motorCtrl;
|
||||
mutable QMutex m_dataMutex;
|
||||
|
||||
bool m_isMoving2Target;
|
||||
bool m_isMoving2Origin;
|
||||
|
||||
double m_targetX;
|
||||
double m_targetY;
|
||||
double m_speedX;
|
||||
double m_speedY;
|
||||
|
||||
double m_actualX;
|
||||
double m_actualY;
|
||||
|
||||
int m_retryLimit = 3;
|
||||
int m_retryTimesX;
|
||||
int m_retryTimesY;
|
||||
|
||||
bool m_xReached;
|
||||
bool m_yReached;
|
||||
};
|
||||
|
||||
class OneMotionCoordinator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OneMotionCoordinator(IrisMultiMotorController* motorCtrl, QObject* parent = nullptr);
|
||||
~OneMotionCoordinator();
|
||||
|
||||
public slots:
|
||||
void moveToTarget(double position, double speed);
|
||||
|
||||
signals:
|
||||
void sequenceComplete(int status);
|
||||
void ArrivalSignal(double position);
|
||||
void moveTo(int, double, double, int);
|
||||
|
||||
private slots:
|
||||
void handlePositionReached(int motorID, double position);
|
||||
|
||||
private:
|
||||
bool checkArrival();
|
||||
double getErrorRate(double targetLoc, double actualLoc);
|
||||
|
||||
IrisMultiMotorController* m_motorCtrl;
|
||||
mutable QMutex m_dataMutex;
|
||||
|
||||
double m_targetPosition;
|
||||
double m_speed;
|
||||
double m_actualPosition;
|
||||
bool m_isMoving;
|
||||
|
||||
int m_retryLimit = 3;
|
||||
int m_retryTimes;
|
||||
bool m_reached;
|
||||
};
|
||||
|
||||
@ -14,6 +14,7 @@ DepthCameraWindow::DepthCameraWindow(QWidget* parent)
|
||||
connect(ui.closeDepthCamera_btn, &QPushButton::clicked, this, &DepthCameraWindow::closeDepthCamera);
|
||||
|
||||
connect(this, &DepthCameraWindow::openDepthCameraSignal, m_DepthCameraOperation, &DepthCameraOperation::OpenDepthCamera);
|
||||
connect(this, &DepthCameraWindow::OpenDepthCamera_getDepthValueSignal, m_DepthCameraOperation, &DepthCameraOperation::OpenDepthCamera_getDepthValue);
|
||||
|
||||
connect(m_DepthCameraOperation, &DepthCameraOperation::CamOpenedSignal, this, &DepthCameraWindow::onCamOpened);
|
||||
connect(m_DepthCameraOperation, &DepthCameraOperation::CamClosedSignal, this, &DepthCameraWindow::onCamClosed);
|
||||
@ -66,6 +67,14 @@ void DepthCameraWindow::openDepthCamera()
|
||||
}
|
||||
}
|
||||
|
||||
void DepthCameraWindow::OpenDepthCamera_getDepthValue()
|
||||
{
|
||||
if (!m_DepthCameraOperation->getRecordStatus())
|
||||
{
|
||||
emit OpenDepthCamera_getDepthValueSignal();
|
||||
}
|
||||
}
|
||||
|
||||
void DepthCameraWindow::onCamOpened()
|
||||
{
|
||||
ui.openDepthCamera_btn->setEnabled(false);
|
||||
@ -279,6 +288,274 @@ void DepthCameraOperation::OpenDepthCamera()
|
||||
m_pipe = nullptr;
|
||||
}
|
||||
|
||||
void DepthCameraOperation::OpenDepthCamera_getDepthValue()
|
||||
{
|
||||
if (m_pipe)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_pipe = new ob::Pipeline();
|
||||
|
||||
std::shared_ptr<ob::Config> config = std::make_shared<ob::Config>();
|
||||
|
||||
// Get device from pipeline.
|
||||
auto device = m_pipe->getDevice();
|
||||
auto devInfo = device->getDeviceInfo();
|
||||
auto pid = devInfo->getPid();
|
||||
auto vid = devInfo->getVid();
|
||||
|
||||
config->enableVideoStream(OB_STREAM_DEPTH, 640, 480, 15, OB_FORMAT_Y16);
|
||||
config->enableVideoStream(OB_STREAM_COLOR, 640, 480, 15, OB_FORMAT_YUYV);
|
||||
config->setFrameAggregateOutputMode(OB_FRAME_AGGREGATE_OUTPUT_ALL_TYPE_FRAME_REQUIRE);
|
||||
|
||||
m_pipe->enableFrameSync();
|
||||
|
||||
// Create a format converter filter.
|
||||
auto formatConverter = std::make_shared<ob::FormatConvertFilter>();
|
||||
|
||||
m_pipe->start(config);
|
||||
|
||||
// Drop several frames
|
||||
for (int i = 0; i < 15; ++i) {
|
||||
auto lost = m_pipe->waitForFrameset(m_captureIntervalMilliseconds);
|
||||
}
|
||||
|
||||
auto pointCloud = std::make_shared<ob::PointCloudFilter>();
|
||||
|
||||
int frameIndex = 0;
|
||||
record = true;
|
||||
QString fileNamePrefix = AppSettings::instance().depthCameraDataFolder() + QDir::separator() + "Gemini336L";
|
||||
|
||||
// 增量平均所需的变量
|
||||
cv::Mat avgRgbMat, avgDepthMat;
|
||||
int avgFrameCount = 0;
|
||||
|
||||
for (size_t i = 0; i < m_averageNumberOfTimes; i++)
|
||||
{
|
||||
if(frameIndex==0)
|
||||
{
|
||||
emit CamOpenedSignal();
|
||||
std::cout << "Start recording..." << std::endl;
|
||||
}
|
||||
|
||||
auto frameSet = m_pipe->waitForFrameset(m_captureIntervalMilliseconds);
|
||||
if (frameSet == nullptr)
|
||||
{
|
||||
std::cout << "No frames received in 100ms..." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << "DepthCamera frameIndex:"<< frameIndex << std::endl;
|
||||
|
||||
// 彩色和深度图像
|
||||
auto depthFrame = frameSet->getFrame(OB_FRAME_DEPTH)->as<ob::DepthFrame>();
|
||||
auto colorFrame = frameSet->getFrame(OB_FRAME_COLOR)->as<ob::ColorFrame>();
|
||||
|
||||
// Convert the color frame to RGB format.
|
||||
if (colorFrame->format() != OB_FORMAT_RGB) {
|
||||
if (colorFrame->format() == OB_FORMAT_MJPG) {
|
||||
formatConverter->setFormatConvertType(FORMAT_MJPG_TO_RGB);
|
||||
}
|
||||
else if (colorFrame->format() == OB_FORMAT_UYVY) {
|
||||
formatConverter->setFormatConvertType(FORMAT_UYVY_TO_RGB);
|
||||
}
|
||||
else if (colorFrame->format() == OB_FORMAT_YUYV) {
|
||||
formatConverter->setFormatConvertType(FORMAT_YUYV_TO_RGB);
|
||||
}
|
||||
else {
|
||||
std::cout << "Color format is not support!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
colorFrame = formatConverter->process(colorFrame)->as<ob::ColorFrame>();
|
||||
}
|
||||
// Processed the color frames to BGR format, use OpenCV to save to disk.
|
||||
formatConverter->setFormatConvertType(FORMAT_RGB_TO_BGR);
|
||||
colorFrame = formatConverter->process(colorFrame)->as<ob::ColorFrame>();
|
||||
|
||||
//用于测试:保存深度图像
|
||||
//saveDepthFrame(depthFrame, frameIndex, fileNamePrefix.toStdString());
|
||||
//saveColorFrame(colorFrame, frameIndex, fileNamePrefix.toStdString());
|
||||
|
||||
cv::Mat colorMat(colorFrame->height(), colorFrame->width(), CV_8UC3, colorFrame->data());
|
||||
cv::Mat rgbMat;
|
||||
cv::cvtColor(colorMat, rgbMat, cv::COLOR_BGR2RGB);
|
||||
//m_colorImage = QImage(rgbMat.data, rgbMat.cols, rgbMat.rows, static_cast<int>(rgbMat.step), QImage::Format_RGB888).copy();
|
||||
|
||||
|
||||
cv::Mat depthMat(depthFrame->height(), depthFrame->width(), CV_16UC1, depthFrame->data());
|
||||
|
||||
// 增量平均计算
|
||||
if (avgFrameCount == 0)
|
||||
{
|
||||
avgRgbMat = cv::Mat::zeros(rgbMat.size(), CV_32FC3);
|
||||
avgDepthMat = cv::Mat::zeros(depthMat.size(), CV_32F);
|
||||
}
|
||||
avgFrameCount++;
|
||||
cv::Mat rgbFloat;
|
||||
rgbMat.convertTo(rgbFloat, CV_32FC3);
|
||||
avgRgbMat = avgRgbMat + (rgbFloat - avgRgbMat) / avgFrameCount;
|
||||
|
||||
cv::Mat depthMatTmp;
|
||||
depthMat.convertTo(depthMatTmp, CV_32F);
|
||||
avgDepthMat = avgDepthMat + (depthMatTmp - avgDepthMat) / avgFrameCount;
|
||||
|
||||
|
||||
cv::Mat depthMat8U;
|
||||
depthMat.convertTo(depthMat8U, CV_8UC1, 255.0 / 4096.0);
|
||||
cv::Mat depthColorMap;
|
||||
cv::applyColorMap(depthMat8U, depthColorMap, cv::COLORMAP_JET);
|
||||
cv::Mat depthRgbMat;
|
||||
cv::cvtColor(depthColorMap, depthRgbMat, cv::COLOR_BGR2RGB);
|
||||
m_depthImage = QImage(depthRgbMat.data, depthRgbMat.cols, depthRgbMat.rows, static_cast<int>(depthRgbMat.step), QImage::Format_RGB888).copy();
|
||||
//m_depthImage = QImage(depthMat.data, depthMat.cols, depthMat.rows, static_cast<int>(depthMat.step), QImage::Format_Grayscale16).copy();
|
||||
|
||||
emit PlotSignal();
|
||||
|
||||
frameIndex++;
|
||||
}
|
||||
m_pipe->stop();
|
||||
|
||||
// 对累积平均后的图像进行处理
|
||||
double depthValue;
|
||||
if (avgFrameCount > 0)
|
||||
{
|
||||
cv::Mat avgRgbResult, avgDepthResult;
|
||||
avgRgbMat.convertTo(avgRgbResult, CV_8UC3);
|
||||
avgDepthMat.convertTo(avgDepthResult, CV_16UC1);
|
||||
|
||||
// 保存平均结果图像
|
||||
std::vector<int> pngParams;
|
||||
pngParams.push_back(cv::IMWRITE_PNG_COMPRESSION);
|
||||
pngParams.push_back(0);
|
||||
pngParams.push_back(cv::IMWRITE_PNG_STRATEGY);
|
||||
pngParams.push_back(cv::IMWRITE_PNG_STRATEGY_DEFAULT);
|
||||
cv::imwrite(getTestFilePath("_AvgRGB_").toStdString(), avgRgbResult, pngParams);
|
||||
cv::imwrite(getTestFilePath("_AvgDepth_").toStdString(), avgDepthResult, pngParams);
|
||||
|
||||
// 创建掩膜,排除深度值为0的区域
|
||||
cv::Mat mask = avgDepthResult != 0;
|
||||
|
||||
// 保存掩膜
|
||||
cv::Mat mask8U;
|
||||
mask.convertTo(mask8U, CV_8UC1, 255.0);
|
||||
std::string maskName = fileNamePrefix.toStdString() + "_Mask_" + std::to_string(mask.cols) + "x" + std::to_string(mask.rows) + ".png";
|
||||
cv::imwrite(maskName, mask8U, pngParams);
|
||||
|
||||
if (m_depthAlgorithm == 0)
|
||||
{
|
||||
depthValue = processAveragedImages_roiAvg(avgDepthResult, mask);
|
||||
}
|
||||
else if (m_depthAlgorithm == 1)
|
||||
{
|
||||
depthValue = processAveragedImages_depthRangePercentage(avgDepthResult, mask);
|
||||
}
|
||||
else if (m_depthAlgorithm == 2)
|
||||
{
|
||||
depthValue = processAveragedImages_segmentation(avgRgbResult, avgDepthResult, mask);
|
||||
}
|
||||
}
|
||||
|
||||
//计算平均深度值
|
||||
std::cout << "Depth value: " << depthValue << " m" << std::endl;
|
||||
emit DepthValueSignal(depthValue);
|
||||
|
||||
delete m_pipe;
|
||||
m_pipe = nullptr;
|
||||
|
||||
record = false;
|
||||
}
|
||||
|
||||
double DepthCameraOperation::processAveragedImages_roiAvg(const cv::Mat& avgDepthResult, const cv::Mat& mask)
|
||||
{
|
||||
//裁剪边缘区域
|
||||
int cropRows = static_cast<int>(avgDepthResult.rows * (1 - m_percentageOfEffectiveArea) / 2);
|
||||
int cropCols = static_cast<int>(avgDepthResult.cols * (1 - m_percentageOfEffectiveArea) / 2);
|
||||
cv::Rect roi(cropCols, cropRows,
|
||||
avgDepthResult.cols - 2 * cropCols,
|
||||
avgDepthResult.rows - 2 * cropRows);
|
||||
cv::Mat depthRoi = avgDepthResult(roi);
|
||||
cv::Mat maskRoi = mask(roi);
|
||||
//计算平均深度值,使用掩膜排除深度值为0的区域
|
||||
cv::Scalar meanDepth = cv::mean(depthRoi, maskRoi);
|
||||
double depthValue = meanDepth[0] / 1000.0; // 转换为米
|
||||
|
||||
return depthValue;
|
||||
}
|
||||
|
||||
double DepthCameraOperation::processAveragedImages_depthRangePercentage(const cv::Mat& avgDepthResult, const cv::Mat& mask)
|
||||
{
|
||||
// 找出最大最小值
|
||||
double minVal, maxVal;
|
||||
cv::minMaxLoc(avgDepthResult, &minVal, &maxVal, nullptr, nullptr, mask);
|
||||
|
||||
// 检查是否有有效数据
|
||||
if (minVal == std::numeric_limits<double>::max())
|
||||
{
|
||||
std::cout << "Warning: No valid depth pixels found in masked region!" << std::endl;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// 返回最小值乘以m_depthRangePercentage
|
||||
double depthValue = minVal * m_depthRangePercentage / 1000.0; // 转换为米
|
||||
|
||||
return depthValue;
|
||||
}
|
||||
|
||||
double DepthCameraOperation::processAveragedImages_segmentation(const cv::Mat& avgRgbResult, const cv::Mat& avgDepthResult, const cv::Mat& mask)
|
||||
{
|
||||
// 转换到 HSV 颜色空间进行植被分割
|
||||
cv::Mat hsvMat;
|
||||
cv::cvtColor(avgRgbResult, hsvMat, cv::COLOR_RGB2HSV);
|
||||
|
||||
// 分离通道
|
||||
std::vector<cv::Mat> hsvChannels;
|
||||
cv::split(hsvMat, hsvChannels);
|
||||
cv::Mat hue = hsvChannels[0];
|
||||
cv::Mat sat = hsvChannels[1];
|
||||
cv::Mat val = hsvChannels[2];
|
||||
|
||||
// 定义绿色植被的Hue范围 (OpenCV中Hue范围是0-180,实际绿色约35-90度)
|
||||
// 扩展范围以覆盖不同光照条件下的绿色
|
||||
cv::Mat hueMask1 = (hue >= 35) & (hue <= 85);
|
||||
cv::Mat satMask = sat > 30; // 饱和度阈值,去除灰色区域
|
||||
cv::Mat valMask = val > 50; // 亮度阈值,去除过暗区域
|
||||
|
||||
// 组合条件生成植被掩膜
|
||||
cv::Mat vmask;
|
||||
cv::bitwise_and(hueMask1, satMask, vmask);
|
||||
cv::bitwise_and(vmask, valMask, vmask);
|
||||
|
||||
// 结合深度掩膜,计算两个mask的交集
|
||||
cv::Mat combinedMask;
|
||||
cv::bitwise_and(mask, vmask, combinedMask);
|
||||
|
||||
// 保存 vmask 和 combinedMask 到 exe 所在文件夹的文件夹
|
||||
cv::Mat vmask8U, combinedMask8U;
|
||||
vmask.convertTo(vmask8U, CV_8UC1, 255.0);
|
||||
combinedMask.convertTo(combinedMask8U, CV_8UC1, 255.0);
|
||||
cv::imwrite(getTestFilePath("vmask").toStdString(), vmask8U);
|
||||
cv::imwrite(getTestFilePath("combinedMask").toStdString(), combinedMask8U);
|
||||
|
||||
// 计算 avgRgbResult 在 combinedMask 区域内的平均深度值
|
||||
double depthValue = 0.0;
|
||||
if (cv::countNonZero(combinedMask) > 0) {
|
||||
cv::Scalar meanDepth = cv::mean(avgDepthResult, combinedMask);
|
||||
depthValue = meanDepth[0] / 1000.0; // 转换为米
|
||||
} else {
|
||||
std::cout << "Warning: No valid pixels in combined mask!" << std::endl;
|
||||
}
|
||||
|
||||
return depthValue;
|
||||
}
|
||||
|
||||
QString DepthCameraOperation::getTestFilePath(const QString& fileName)
|
||||
{
|
||||
QString testFolder = QCoreApplication::applicationDirPath() + QDir::separator() + "depthValueTest";
|
||||
QDir().mkpath(testFolder);
|
||||
QString timestamp = QString::number(QDateTime::currentMSecsSinceEpoch());
|
||||
return testFolder + QDir::separator() + fileName + "_" + timestamp + ".png";
|
||||
}
|
||||
|
||||
void DepthCameraOperation::saveDepthFrame(const std::shared_ptr<ob::DepthFrame> depthFrame, const uint32_t frameIndex, std::string fileNamePrefix_)
|
||||
{
|
||||
std::vector<int> params;
|
||||
|
||||
@ -5,8 +5,10 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QImage>
|
||||
#include <Qthread>
|
||||
#include <QThread>
|
||||
#include <QDir>
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
//#include <QLabel>
|
||||
#include <QFileDialog>
|
||||
|
||||
@ -35,6 +37,11 @@ public:
|
||||
|
||||
void setCaptureInterval(int captureIntervalSeconds);
|
||||
|
||||
void setDepthAlgorithm(int depthAlgorithm) { m_depthAlgorithm = depthAlgorithm; }
|
||||
void setAverageNumberOfTimes(double averageNumberOfTimes) { m_averageNumberOfTimes = averageNumberOfTimes; }
|
||||
void setPercentageOfEffectiveArea(double percentageOfEffectiveArea) { m_percentageOfEffectiveArea = percentageOfEffectiveArea; }
|
||||
void setDepthRangePercentage(double depthRangePercentage) { m_depthRangePercentage = depthRangePercentage; }
|
||||
|
||||
private:
|
||||
ob::Pipeline* m_pipe;
|
||||
cv::Mat frame;
|
||||
@ -50,13 +57,26 @@ private:
|
||||
|
||||
int m_captureIntervalMilliseconds;
|
||||
|
||||
int m_depthAlgorithm;
|
||||
double m_averageNumberOfTimes;
|
||||
double m_percentageOfEffectiveArea;
|
||||
double m_depthRangePercentage;
|
||||
|
||||
double processAveragedImages_roiAvg(const cv::Mat& avgDepthResult, const cv::Mat& mask);
|
||||
double processAveragedImages_depthRangePercentage(const cv::Mat& avgDepthResult, const cv::Mat& mask);
|
||||
double processAveragedImages_segmentation(const cv::Mat& avgRgbResult, const cv::Mat& avgDepthResult, const cv::Mat& mask);
|
||||
|
||||
QString getTestFilePath(const QString& fileName);
|
||||
|
||||
public slots:
|
||||
void OpenDepthCamera();
|
||||
void OpenDepthCamera_getDepthValue();
|
||||
void OpenDepthCamera_callback();//不使用信号而使用回调函数来通知界面刷新视频
|
||||
void CloseDepthCamera();
|
||||
|
||||
signals:
|
||||
void PlotSignal();
|
||||
void DepthValueSignal(double depthValue);
|
||||
|
||||
void CamOpenedSignal();
|
||||
void CamClosedSignal();
|
||||
@ -77,6 +97,7 @@ public:
|
||||
|
||||
public Q_SLOTS:
|
||||
void openDepthCamera();
|
||||
void OpenDepthCamera_getDepthValue();
|
||||
void onCamOpened();
|
||||
void closeDepthCamera();
|
||||
void onCamClosed();
|
||||
@ -84,12 +105,12 @@ public Q_SLOTS:
|
||||
void onSelectDataFolder();
|
||||
|
||||
signals:
|
||||
void openDepthCameraSignal();
|
||||
void PlotDepthImageSignal();
|
||||
void DepthCamClosedSignal();
|
||||
void openDepthCameraSignal();
|
||||
void OpenDepthCamera_getDepthValueSignal();
|
||||
void PlotDepthImageSignal();
|
||||
void DepthCamClosedSignal();
|
||||
|
||||
private:
|
||||
Ui::DepthCameraClass ui;
|
||||
QThread* m_DepthCameraThread;
|
||||
|
||||
};
|
||||
|
||||
138
HPPA/DepthValueLogger.cpp
Normal file
138
HPPA/DepthValueLogger.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "stdafx.h"
|
||||
#include "DepthValueLogger.h"
|
||||
#include "AppSettings.h"
|
||||
#include "fileOperation.h"
|
||||
#include <QDir>
|
||||
|
||||
DepthValueLogger& DepthValueLogger::instance()
|
||||
{
|
||||
static DepthValueLogger instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
DepthValueLogger::DepthValueLogger()
|
||||
{
|
||||
}
|
||||
|
||||
DepthValueLogger::~DepthValueLogger()
|
||||
{
|
||||
}
|
||||
|
||||
QString DepthValueLogger::getLogFilePath(DepthValueType type) const
|
||||
{
|
||||
FileOperation* fileOperation = new FileOperation();
|
||||
QString directory = QString::fromStdString(fileOperation->getDirectoryOfExe());
|
||||
QString basePath = directory + QDir::separator() + "3DPlantPhenotypeScenario";
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DepthValueType::Plant:
|
||||
return basePath + QDir::separator() + "plant_depth_values.txt";
|
||||
case DepthValueType::LiftingPlatform:
|
||||
return basePath + QDir::separator() + "LiftingPlatform_depth_values.txt";
|
||||
default:
|
||||
return basePath + QDir::separator() + "plant_depth_values.txt";
|
||||
}
|
||||
}
|
||||
|
||||
void DepthValueLogger::appendDepthValue(double depthValue, DepthValueType type)
|
||||
{
|
||||
QString filePath = getLogFilePath(type);
|
||||
QFileInfo fileInfo(filePath);
|
||||
QDir dir = fileInfo.absoluteDir();
|
||||
if (!dir.exists())
|
||||
{
|
||||
dir.mkpath(".");
|
||||
}
|
||||
|
||||
QFile file(filePath);
|
||||
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
|
||||
{
|
||||
QTextStream out(&file);
|
||||
QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
|
||||
out << timestamp << "\t" << QString::number(depthValue, 'f', 6) << "\n";
|
||||
file.close();
|
||||
|
||||
emit depthValueLogged(depthValue, type);
|
||||
}
|
||||
}
|
||||
|
||||
double DepthValueLogger::readLatestDepthValue(DepthValueType type) const
|
||||
{
|
||||
QString filePath = getLogFilePath(type);
|
||||
QFile file(filePath);
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double latestValue = 0.0;
|
||||
QTextStream in(&file);
|
||||
|
||||
while (!in.atEnd())
|
||||
{
|
||||
QString line = in.readLine().trimmed();
|
||||
if (line.isEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QStringList parts = line.split("\t");
|
||||
if (parts.size() >= 2)
|
||||
{
|
||||
latestValue = parts.last().toDouble();
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
return latestValue;
|
||||
}
|
||||
|
||||
bool DepthValueLogger::hasValidDepthValue(DepthValueType type) const
|
||||
{
|
||||
QString filePath = getLogFilePath(type);
|
||||
QFile file(filePath);
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasValue = false;
|
||||
QTextStream in(&file);
|
||||
|
||||
while (!in.atEnd())
|
||||
{
|
||||
QString line = in.readLine().trimmed();
|
||||
if (!line.isEmpty())
|
||||
{
|
||||
hasValue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
return hasValue;
|
||||
}
|
||||
|
||||
void DepthValueLogger::appendPlantDepthValue(double depthValue)
|
||||
{
|
||||
appendDepthValue(depthValue, DepthValueType::Plant);
|
||||
}
|
||||
|
||||
void DepthValueLogger::appendLiftingPlatformDepthValue(double depthValue)
|
||||
{
|
||||
appendDepthValue(depthValue, DepthValueType::LiftingPlatform);
|
||||
}
|
||||
|
||||
double DepthValueLogger::readLatestPlantDepthValue() const
|
||||
{
|
||||
return readLatestDepthValue(DepthValueType::Plant);
|
||||
}
|
||||
|
||||
double DepthValueLogger::readLatestLiftingPlatformDepthValue() const
|
||||
{
|
||||
return readLatestDepthValue(DepthValueType::LiftingPlatform);
|
||||
}
|
||||
41
HPPA/DepthValueLogger.h
Normal file
41
HPPA/DepthValueLogger.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef DEPTH_VALUE_LOGGER_H
|
||||
#define DEPTH_VALUE_LOGGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
enum class DepthValueType
|
||||
{
|
||||
Plant,
|
||||
LiftingPlatform
|
||||
};
|
||||
|
||||
class DepthValueLogger : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static DepthValueLogger& instance();
|
||||
|
||||
void appendDepthValue(double depthValue, DepthValueType type);
|
||||
double readLatestDepthValue(DepthValueType type) const;
|
||||
bool hasValidDepthValue(DepthValueType type) const;
|
||||
|
||||
void appendPlantDepthValue(double depthValue);
|
||||
void appendLiftingPlatformDepthValue(double depthValue);
|
||||
double readLatestPlantDepthValue() const;
|
||||
double readLatestLiftingPlatformDepthValue() const;
|
||||
|
||||
signals:
|
||||
void depthValueLogged(double value, DepthValueType type);
|
||||
|
||||
private:
|
||||
DepthValueLogger();
|
||||
~DepthValueLogger();
|
||||
DepthValueLogger(const DepthValueLogger&) = delete;
|
||||
DepthValueLogger& operator=(const DepthValueLogger&) = delete;
|
||||
|
||||
QString getLogFilePath(DepthValueType type) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>650</width>
|
||||
<height>530</height>
|
||||
<width>582</width>
|
||||
<height>465</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -279,13 +279,28 @@ QRadioButton
|
||||
<item row="0" column="1">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>连接调焦模块</string>
|
||||
<string>连接调焦线性平台</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="connectMotor_btn">
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="is_new_version_radioButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>连接线性平台</string>
|
||||
<string>新版</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoExclusive">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -296,7 +311,7 @@ QRadioButton
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>107</width>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -359,22 +374,72 @@ QRadioButton
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="is_new_version_radioButton">
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="connectMotor_btn">
|
||||
<property name="text">
|
||||
<string>新版</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoExclusive">
|
||||
<bool>false</bool>
|
||||
<string>连接</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>状态</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="motor_state_label">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>8</width>
|
||||
<height>8</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeIncrement">
|
||||
<size>
|
||||
<width>8</width>
|
||||
<height>8</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QLabel#motor_state_label
|
||||
{
|
||||
background-color: red;
|
||||
border-radius: 4px;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -446,7 +511,7 @@ QRadioButton
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
<string>0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
@ -462,7 +527,7 @@ QRadioButton
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
<string>1</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
@ -518,7 +583,7 @@ QRadioButton
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
<string>1</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include "FodisWindow.h"
|
||||
#include "FodisWindow.h"
|
||||
#include "JinspFiberImagerConfig.h"
|
||||
|
||||
FodisWindow::FodisWindow(QWidget* parent)
|
||||
@ -27,7 +27,7 @@ FodisWindow::FodisWindow(QWidget* parent)
|
||||
|
||||
connect(this->ui.dataFolderBtn, SIGNAL(clicked()), this, SLOT(onSelectDataFolder()));
|
||||
|
||||
// <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݱ<EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> AppSettings <EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Ĭ<EFBFBD>ϣ<EFBFBD>
|
||||
// 初始化数据保存路径显示(从 AppSettings 恢复或使用默认)
|
||||
ui.dataFolderLineEdit->setText(AppSettings::instance().depthCameraDataFolder());
|
||||
|
||||
setDataFolder(AppSettings::instance().FiberImagerDataFolder());
|
||||
@ -44,7 +44,7 @@ FodisWindow::~FodisWindow()
|
||||
void FodisWindow::onSelectDataFolder()
|
||||
{
|
||||
QString dir = QFileDialog::getExistingDirectory(this,
|
||||
QString::fromLocal8Bit("ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݱ<EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>"),
|
||||
QString::fromLocal8Bit("选择数据保存路径"),
|
||||
ui.dataFolderLineEdit->text());
|
||||
|
||||
setDataFolder(dir);
|
||||
@ -65,10 +65,15 @@ void FodisWindow::setCaptureInterval(int captureIntervalSeconds)
|
||||
}
|
||||
|
||||
void FodisWindow::openFiberImager()
|
||||
{
|
||||
openFiberImager_expose_record("pos_null");
|
||||
}
|
||||
|
||||
void FodisWindow::openFiberImager_expose_record(QString posInfo)
|
||||
{
|
||||
if (!m_JinspFiberImagerOperation->getRecordStatus())
|
||||
{
|
||||
emit openFiberImagerSignal();
|
||||
emit openFiberImagerSignal(posInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +82,7 @@ void FodisWindow::onCamOpened()
|
||||
ui.open_btn->setEnabled(false);
|
||||
ui.close_btn->setEnabled(true);
|
||||
|
||||
ui.open_btn->setText(QString::fromLocal8Bit("<EFBFBD>Ѵ<EFBFBD><EFBFBD><EFBFBD>"));
|
||||
ui.open_btn->setText(QString::fromLocal8Bit("已打开"));
|
||||
}
|
||||
|
||||
void FodisWindow::closeFiberImager()
|
||||
@ -90,5 +95,5 @@ void FodisWindow::onCamClosed()
|
||||
ui.open_btn->setEnabled(true);
|
||||
ui.close_btn->setEnabled(false);
|
||||
|
||||
ui.open_btn->setText(QString::fromLocal8Bit("<EFBFBD><EFBFBD> <EFBFBD><EFBFBD>"));
|
||||
ui.open_btn->setText(QString::fromLocal8Bit("打 开"));
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QNetworkRequest>
|
||||
@ -31,6 +31,7 @@ public:
|
||||
|
||||
public Q_SLOTS:
|
||||
void openFiberImager();
|
||||
void openFiberImager_expose_record(QString posInfo);
|
||||
void onCamOpened();
|
||||
void closeFiberImager();
|
||||
void onCamClosed();
|
||||
@ -38,7 +39,7 @@ public Q_SLOTS:
|
||||
void onSelectDataFolder();
|
||||
|
||||
signals:
|
||||
void openFiberImagerSignal();
|
||||
void openFiberImagerSignal(QString posInfo);
|
||||
void PlotSpectralSignal();
|
||||
void FiberImagerClosedSignal();
|
||||
|
||||
|
||||
@ -21,13 +21,32 @@ void GonggashanTaskScheduler::setTaskRunning(bool running)
|
||||
Q_EMIT taskStateChanged(m_taskState);
|
||||
}
|
||||
|
||||
void GonggaShanRecordCtl::logStatus(const QString& message)
|
||||
void GonggaShanRecordCtl::logStatus(const QString& message, bool isHearderBlankLine, bool isTailBlankLine)
|
||||
{
|
||||
QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
|
||||
ui.status_textEdit->append(QString("[%1] %2").arg(timestamp, message));
|
||||
|
||||
if (m_logStream.device()) {
|
||||
if (isHearderBlankLine)
|
||||
{
|
||||
ui.status_textEdit->append("\n");
|
||||
}
|
||||
ui.status_textEdit->append(QString("[%1] %2").arg(timestamp, message));
|
||||
if (isTailBlankLine)
|
||||
{
|
||||
ui.status_textEdit->append("\n");
|
||||
}
|
||||
|
||||
if (m_logStream.device())
|
||||
{
|
||||
if (isHearderBlankLine)
|
||||
{
|
||||
m_logStream << "\n";
|
||||
}
|
||||
m_logStream << "[" << timestamp << "] " << message << "\n";
|
||||
if (isTailBlankLine)
|
||||
{
|
||||
m_logStream << "\n";
|
||||
}
|
||||
|
||||
m_logStream.flush();
|
||||
m_logFile.flush();
|
||||
}
|
||||
@ -66,13 +85,13 @@ void GonggaShanRecordCtl::startListen()
|
||||
}
|
||||
|
||||
QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss");
|
||||
QString logFileName = QString("log%1.txt").arg(timestamp);
|
||||
QString logFileName = QString("%1_log.txt").arg(timestamp);
|
||||
m_logFilePath = AppSettings::instance().dataFolder() + QDir::separator() + logFileName;
|
||||
m_logFile.setFileName(m_logFilePath);
|
||||
m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
|
||||
m_logStream.setDevice(&m_logFile);
|
||||
|
||||
logStatus("Start listen....");
|
||||
logStatus("Start listen....", true, true);
|
||||
|
||||
MotorParams::TCPConnectionParams tcpConnectionParams6005;
|
||||
tcpConnectionParams6005.port = ui.spinbox_Port->text().toInt();
|
||||
@ -84,7 +103,7 @@ void GonggaShanRecordCtl::startListen()
|
||||
|
||||
void GonggaShanRecordCtl::stopListen()
|
||||
{
|
||||
logStatus("Stop listen");
|
||||
logStatus("Stop listen", true, true);
|
||||
|
||||
disconnect(tcpServer6005, &MotorParams::CommunicationViaTCP::positionReceived, this, &GonggaShanRecordCtl::startRecord);
|
||||
|
||||
@ -100,10 +119,11 @@ void GonggaShanRecordCtl::startRecord(int position)
|
||||
return;
|
||||
}
|
||||
|
||||
logStatus("Reach pos: " + QString::number(position));
|
||||
QString pos = QString::number(position);
|
||||
logStatus("Reach pos: " + pos, true);
|
||||
|
||||
m_taskScheduler->setTaskRunning(true);
|
||||
emit startRcordSignal();
|
||||
emit startRcordSignal("pos_" + pos);
|
||||
}
|
||||
|
||||
void GonggaShanRecordCtl::onFiberImagerStartExposureSignal()
|
||||
|
||||
@ -56,7 +56,7 @@ public Q_SLOTS:
|
||||
|
||||
Q_SIGNALS:
|
||||
// Emitted when user changes any of the R/G/B wavelength values
|
||||
void startRcordSignal();
|
||||
void startRcordSignal(QString posInfo);
|
||||
|
||||
private Q_SLOTS:
|
||||
void startListen();
|
||||
@ -65,7 +65,7 @@ private Q_SLOTS:
|
||||
void startRecord(int position);
|
||||
|
||||
private:
|
||||
void logStatus(const QString& message);
|
||||
void logStatus(const QString& message, bool isHearderBlankLine = false, bool isTailBlankLine = false);
|
||||
|
||||
Ui::gongga_control ui;
|
||||
QPointer<MotorParams::CommunicationViaTCP> tcpServer6005;
|
||||
|
||||
@ -659,6 +659,7 @@ void HPPA::initTimedDataCollection()
|
||||
m_tdc->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
m_tmc->connectMotor(false);
|
||||
m_omc_LiftingPlatform->connectMotor(false);
|
||||
|
||||
// 定时采集控制器 → 相机/马达
|
||||
connect(m_tdc, &TimedDataCollection::hyperCamParm, this, &HPPA::setTimedDataCollectionHyperCamParm);
|
||||
@ -666,6 +667,8 @@ void HPPA::initTimedDataCollection()
|
||||
connect(m_tdc, &TimedDataCollection::motorParm, this, &HPPA::setTimedDataCollectionMotorParm);
|
||||
connect(m_tdc, &TimedDataCollection::startRecordSignal, this, &HPPA::onStartTimedDataCollection);
|
||||
|
||||
connect(m_tdc, &TimedDataCollection::ObtainingDepthInformationSignals, this, &HPPA::onObtainTargetDepthInformation);
|
||||
|
||||
connect(m_tdc, &TimedDataCollection::switchHalogenLampSignal, m_pc3D, &PowerControl3D::switchHalogenLampPower);
|
||||
connect(m_tdc, &TimedDataCollection::switchD65LampSignal, m_pc3D, &PowerControl3D::switchD65LampPower);
|
||||
connect(m_tdc, &TimedDataCollection::switchSlrSignal, m_pc3D, &PowerControl3D::switchSlrPower);
|
||||
@ -674,6 +677,14 @@ void HPPA::initTimedDataCollection()
|
||||
connect(m_tmc, &TwoMotorControl::sequenceComplete, m_tdc, &TimedDataCollection::subTaskCompleted);
|
||||
connect(m_tmc, &TwoMotorControl::back2OriginSignal_TimedDataCollection, m_tdc, &TimedDataCollection::onBack2Origin);
|
||||
|
||||
//升降台
|
||||
connect(m_tdc, &TimedDataCollection::LiftingPlatformSignals, this, &HPPA::onLiftingPlatform);
|
||||
connect(m_omc_LiftingPlatform, &OneMotorControl_LiftingPlatform::sequenceComplete, m_tdc, &TimedDataCollection::subTaskCompleted);
|
||||
connect(m_omc_LiftingPlatform, &OneMotorControl_LiftingPlatform::back2OriginSignal_TimedDataCollection, m_tdc, &TimedDataCollection::onBack2Origin);
|
||||
|
||||
//自动调焦
|
||||
connect(m_tdc, &TimedDataCollection::AutoFocusSignals, this, &HPPA::onAutoFocus_TimedDataCollection);
|
||||
|
||||
m_tdc->show();
|
||||
}
|
||||
|
||||
@ -772,6 +783,24 @@ void HPPA::onStartTimedDataCollection(int camType)
|
||||
}
|
||||
}
|
||||
|
||||
void HPPA::onObtainTargetDepthInformation(SubTask subTaskParams)
|
||||
{
|
||||
m_tmc->run4_ObtainTargetDepthInfo(m_depthCameraWindow, subTaskParams.depthAlgorithm, subTaskParams.depthType, subTaskParams.depthInfoX, subTaskParams.depthInfoY,
|
||||
subTaskParams.averageNumberOfTimes, subTaskParams.percentageOfEffectiveArea, subTaskParams.depthRangePercentage);
|
||||
}
|
||||
|
||||
void HPPA::onLiftingPlatform(SubTask subTaskParams)
|
||||
{
|
||||
m_omc_LiftingPlatform->run();
|
||||
}
|
||||
|
||||
void HPPA::onAutoFocus_TimedDataCollection(SubTask subTaskParams)
|
||||
{
|
||||
m_tmc->setImager(m_Imager);
|
||||
//先使用subTaskParams.autoFocusMotorConfigFilePath替换文件oneMotorConfigFile_focus.cfg
|
||||
m_tmc->run5_AutoFocus(subTaskParams.autoFocusX, subTaskParams.autoFocusY);
|
||||
}
|
||||
|
||||
void HPPA::onTimedDataCollection()
|
||||
{
|
||||
QAction* checkedScenario = m_ScenarioActionGroup->checkedAction();
|
||||
@ -1050,6 +1079,11 @@ void HPPA::initControlTabwidget()
|
||||
m_omc->setWindowFlags(Qt::Widget);
|
||||
ui.controlTabWidget->addTab(m_omc, QString::fromLocal8Bit("1轴马达控制"));
|
||||
|
||||
//1轴马达控制,上海3D植物表情,白板/调焦纸升降
|
||||
m_omc_LiftingPlatform = new OneMotorControl_LiftingPlatform();
|
||||
m_omc_LiftingPlatform->setWindowFlags(Qt::Widget);
|
||||
ui.controlTabWidget->addTab(m_omc_LiftingPlatform, QString::fromLocal8Bit("白板/调焦升降台"));
|
||||
|
||||
//2轴马达控制
|
||||
m_tmc = new TwoMotorControl(this);
|
||||
//connect(m_tmc, SIGNAL(startLineNumSignal(int)), this, SLOT(onCreateTab(int)));
|
||||
@ -1088,7 +1122,7 @@ void HPPA::setupGonggashanAutoRecordConnection()
|
||||
connect(m_omc, &OneMotorControl::sequenceComplete, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::onRcordFinished);
|
||||
}
|
||||
|
||||
void HPPA::onGonggashanRecord()
|
||||
void HPPA::onGonggashanRecord(QString posInfo)
|
||||
{
|
||||
//设置文件名
|
||||
//AppSettings::instance().setFrameRate(f);
|
||||
@ -1097,7 +1131,7 @@ void HPPA::onGonggashanRecord()
|
||||
|
||||
QString dateStr = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss");
|
||||
//QString fi = AppSettings::instance().fileName() + "_" + dateStr;
|
||||
AppSettings::instance().setFileName(dateStr);
|
||||
AppSettings::instance().setFileName(dateStr + "_" + posInfo);
|
||||
|
||||
this->frame_number->setText("100000");
|
||||
|
||||
@ -1109,7 +1143,7 @@ void HPPA::onGonggashanRecord()
|
||||
onconnect();
|
||||
}
|
||||
|
||||
m_fodisWindow->openFiberImager();
|
||||
m_fodisWindow->openFiberImager_expose_record(posInfo);
|
||||
}
|
||||
|
||||
void HPPA::recordFromRobotArm(int fileCounter)
|
||||
@ -1672,6 +1706,7 @@ void HPPA::create3DPlantPhenotypeScenario()
|
||||
//m_tabManager->showTab(m_pc);
|
||||
m_tabManager->showTab(m_pc3D);
|
||||
m_tabManager->showTab(m_tmc);
|
||||
m_tabManager->showTab(m_omc_LiftingPlatform);
|
||||
|
||||
m_view3DModelManager->switchScenario(View3DModelManager::ScenarioType::PlantPhenotype);
|
||||
|
||||
@ -2396,7 +2431,7 @@ void HPPA::disconnectImagerAndCleanup()
|
||||
{
|
||||
m_RecordThread->quit();
|
||||
m_RecordThread->wait(3000);
|
||||
delete m_RecordThread;
|
||||
m_RecordThread->deleteLater();
|
||||
m_RecordThread = nullptr;
|
||||
}
|
||||
|
||||
@ -2563,6 +2598,15 @@ void HPPA::onconnect()
|
||||
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
|
||||
QString errorFilePath = QCoreApplication::applicationDirPath() + "/camerror.txt";
|
||||
QFile file(errorFilePath);
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
|
||||
{
|
||||
QTextStream out(&file);
|
||||
out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << " - std::exception: " << e.what() << "\n";
|
||||
file.close();
|
||||
}
|
||||
|
||||
delete m_Imager;
|
||||
m_Imager = nullptr;
|
||||
|
||||
@ -2572,6 +2616,15 @@ void HPPA::onconnect()
|
||||
{
|
||||
ui.action_connect_imager->setIcon(QIcon(":/svg/resources/icons/svg/connect_imager.svg"));
|
||||
|
||||
QString errorFilePath = QCoreApplication::applicationDirPath() + "/camerror.txt";
|
||||
QFile file(errorFilePath);
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
|
||||
{
|
||||
QTextStream out(&file);
|
||||
out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << " - int exception: " << e << "\n";
|
||||
file.close();
|
||||
}
|
||||
|
||||
delete m_Imager;
|
||||
m_Imager = nullptr;
|
||||
|
||||
|
||||
@ -321,6 +321,7 @@ private:
|
||||
PowerControl3D* m_pc3D;
|
||||
RobotArmControl* m_rac;
|
||||
OneMotorControl* m_omc;
|
||||
OneMotorControl_LiftingPlatform* m_omc_LiftingPlatform;
|
||||
TwoMotorControl* m_tmc;
|
||||
FodisWindow* m_fodisWindow;
|
||||
GonggaShanRecordCtl* m_gonggaShanRecordCtl;
|
||||
@ -363,7 +364,7 @@ private:
|
||||
void showFiberImagerSpectral(DeviceAttribute attribute, DataFrame dataFrame);
|
||||
|
||||
void setupGonggashanAutoRecordConnection();
|
||||
void onGonggashanRecord();
|
||||
|
||||
|
||||
public Q_SLOTS:
|
||||
void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber, QString filePath);
|
||||
@ -449,10 +450,15 @@ public Q_SLOTS:
|
||||
void setTimedDataCollectionCamParm(int camType, int captureIntervalSeconds, QString folder);
|
||||
void setTimedDataCollectionMotorParm(QString pathLineFilePath);
|
||||
void onStartTimedDataCollection(int camType);
|
||||
void onObtainTargetDepthInformation(SubTask subTaskParams);
|
||||
void onLiftingPlatform(SubTask subTaskParams);
|
||||
void onAutoFocus_TimedDataCollection(SubTask subTaskParams);
|
||||
|
||||
void onStretchedImageReady(int fileNumber, const QString& filePath, QPixmap& pixmap);
|
||||
void onStretchProcessingError(int fileNumber, const QString& filePath, const QString& error);
|
||||
|
||||
void onGonggashanRecord(QString posInfo);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
|
||||
@ -186,6 +186,7 @@
|
||||
<QtUic Include="gonggashanCtl.ui" />
|
||||
<QtUic Include="HPPA.ui" />
|
||||
<QtMoc Include="HPPA.h" />
|
||||
<ClCompile Include="DepthValueLogger.cpp" />
|
||||
<ClCompile Include="fileOperation.cpp" />
|
||||
<ClCompile Include="focusWindow.cpp" />
|
||||
<ClCompile Include="HPPA.cpp" />
|
||||
@ -212,6 +213,7 @@
|
||||
<QtUic Include="twoMotorControl.ui" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="DepthValueLogger.h" />
|
||||
<QtMoc Include="fileOperation.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -21,6 +21,24 @@
|
||||
<UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
|
||||
<Extensions>ts</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\TimedDataCollection">
|
||||
<UniqueIdentifier>{3777a3c2-8d8a-4414-b6c9-ac20640f7b2e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\TimedDataCollection">
|
||||
<UniqueIdentifier>{ea004f0d-34de-4b29-8ce2-57dd8aa01c03}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\LayerTree">
|
||||
<UniqueIdentifier>{25329ee3-f78c-4dd9-9170-e64ccb4ccd9e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\LayerTree">
|
||||
<UniqueIdentifier>{18072152-2a29-4ad8-be97-d097af97eeec}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\hyperImagerCtl">
|
||||
<UniqueIdentifier>{b3f08410-c140-42db-bcfd-24efba860cfb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\hyperImagerCtl">
|
||||
<UniqueIdentifier>{205ec088-0286-42ca-862c-2870928a46f5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtRcc Include="HPPA.qrc">
|
||||
@ -70,9 +88,6 @@
|
||||
<ClCompile Include="QMotorDoubleSlider.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="resononImager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RgbCameraOperation.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -88,12 +103,6 @@
|
||||
<ClCompile Include="path_tc.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ResononNirImager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ImagerOperationBase.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utility_tc.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -139,21 +148,6 @@
|
||||
<ClCompile Include="View3DModelManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeNode.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeModel.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTree.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeGroupNode.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeLayerNode.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MapLayer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -175,12 +169,6 @@
|
||||
<ClCompile Include="MapLayerStore.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeView.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeViewMenuProvider.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="imageControl.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -226,18 +214,9 @@
|
||||
<ClCompile Include="SingleLensReflexCameraWindow.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeImageNode.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RasterRendererBase.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TimedDataCollection.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TimedDataCollectionDataStructures.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CommunicationViaTCP.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -247,9 +226,6 @@
|
||||
<ClCompile Include="PowerControl3D.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TaskTreeModel.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PathLine.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -265,6 +241,51 @@
|
||||
<ClCompile Include="GonggaShanRecordCtl.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TaskTreeModel.cpp">
|
||||
<Filter>Source Files\TimedDataCollection</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TimedDataCollection.cpp">
|
||||
<Filter>Source Files\TimedDataCollection</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TimedDataCollectionDataStructures.cpp">
|
||||
<Filter>Source Files\TimedDataCollection</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTree.cpp">
|
||||
<Filter>Source Files\LayerTree</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeGroupNode.cpp">
|
||||
<Filter>Source Files\LayerTree</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeImageNode.cpp">
|
||||
<Filter>Source Files\LayerTree</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeLayerNode.cpp">
|
||||
<Filter>Source Files\LayerTree</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeModel.cpp">
|
||||
<Filter>Source Files\LayerTree</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeNode.cpp">
|
||||
<Filter>Source Files\LayerTree</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeView.cpp">
|
||||
<Filter>Source Files\LayerTree</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LayerTreeViewMenuProvider.cpp">
|
||||
<Filter>Source Files\LayerTree</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ImagerOperationBase.cpp">
|
||||
<Filter>Source Files\hyperImagerCtl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="resononImager.cpp">
|
||||
<Filter>Source Files\hyperImagerCtl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ResononNirImager.cpp">
|
||||
<Filter>Source Files\hyperImagerCtl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DepthValueLogger.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="fileOperation.h">
|
||||
@ -291,18 +312,12 @@
|
||||
<QtMoc Include="QMotorDoubleSlider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="resononImager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="RgbCameraOperation.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="aboutWindow.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="ImagerOperationBase.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="adjustTable.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
@ -339,21 +354,6 @@
|
||||
<QtMoc Include="View3DModelManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeModel.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeNode.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTree.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeGroupNode.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeLayerNode.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="MapLayer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
@ -363,9 +363,6 @@
|
||||
<QtMoc Include="MapLayerStore.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeViewMenuProvider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="imageControl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
@ -405,15 +402,6 @@
|
||||
<QtMoc Include="SingleLensReflexCameraWindow.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeImageNode.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="TimedDataCollection.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="TimedDataCollectionDataStructures.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="CommunicationViaTCP.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
@ -423,9 +411,6 @@
|
||||
<QtMoc Include="PowerControl3D.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="TaskTreeModel.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="FodisWindow.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
@ -435,6 +420,45 @@
|
||||
<QtMoc Include="GonggaShanRecordCtl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="TimedDataCollection.h">
|
||||
<Filter>Header Files\TimedDataCollection</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="TaskTreeModel.h">
|
||||
<Filter>Header Files\TimedDataCollection</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="TimedDataCollectionDataStructures.h">
|
||||
<Filter>Header Files\TimedDataCollection</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTree.h">
|
||||
<Filter>Header Files\LayerTree</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeGroupNode.h">
|
||||
<Filter>Header Files\LayerTree</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeImageNode.h">
|
||||
<Filter>Header Files\LayerTree</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeLayerNode.h">
|
||||
<Filter>Header Files\LayerTree</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeModel.h">
|
||||
<Filter>Header Files\LayerTree</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeNode.h">
|
||||
<Filter>Header Files\LayerTree</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="LayerTreeViewMenuProvider.h">
|
||||
<Filter>Header Files\LayerTree</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="ImagerOperationBase.h">
|
||||
<Filter>Header Files\hyperImagerCtl</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="resononImager.h">
|
||||
<Filter>Header Files\hyperImagerCtl</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="DepthValueLogger.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="imageProcessor.h">
|
||||
@ -455,9 +479,6 @@
|
||||
<ClInclude Include="path_tc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ResononNirImager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utility_tc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -482,9 +503,6 @@
|
||||
<ClInclude Include="SinglebandRasterRenderer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LayerTreeView.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AppSettings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -497,6 +515,12 @@
|
||||
<ClInclude Include="FiberSpectrometerOperationBase.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LayerTreeView.h">
|
||||
<Filter>Header Files\LayerTree</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ResononNirImager.h">
|
||||
<Filter>Header Files\hyperImagerCtl</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="FocusDialog.ui">
|
||||
|
||||
@ -221,6 +221,16 @@ void ImagerOperationBase::record_white()
|
||||
|
||||
void ImagerOperationBase::start_record()
|
||||
{
|
||||
QObject* obj = sender();
|
||||
if (obj)
|
||||
{
|
||||
qDebug() << "ImagerOperationBase::start_record, sender name:" << obj->objectName();
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "ImagerOperationBase::start_record, sender is null";
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
//std::cout << "------------------------------------------------------" << std::endl;
|
||||
|
||||
@ -172,7 +172,7 @@ void JinspFiberImager::recordTarget(int recordTimes, QString path)
|
||||
//输出到csv
|
||||
QDateTime curDateTime = QDateTime::currentDateTime();
|
||||
QString currentTime = curDateTime.toString("yyyy_MM_dd_hh_mm_ss");
|
||||
QString fileName = path + "/" + currentTime + "_" + QString::fromStdString(deviceInfo.strSN) + "_integratingSphereSpectral_dn.csv";
|
||||
QString fileName = path + "/" + currentTime + "_" + m_posInfo + "_" + QString::fromStdString(deviceInfo.strSN) + "_integratingSphereSpectral_dn.csv";
|
||||
std::ofstream outfile(fileName.toStdString().c_str());
|
||||
|
||||
for (int i = 0; i < attribute.iPixels; i++)
|
||||
@ -318,8 +318,10 @@ void JinspFiberImager::setCaptureInterval(int captureIntervalSeconds)
|
||||
m_captureIntervalMilliseconds = captureIntervalSeconds * 1000;
|
||||
}
|
||||
|
||||
void JinspFiberImager::OpenFiberImagerAndRecord()
|
||||
void JinspFiberImager::OpenFiberImagerAndRecord(QString posInfo)
|
||||
{
|
||||
m_posInfo = posInfo;
|
||||
|
||||
//连接光谱仪
|
||||
QString SN;
|
||||
QString pixelCount;
|
||||
|
||||
@ -55,6 +55,8 @@ private:
|
||||
|
||||
int m_iExposureTime;
|
||||
|
||||
QString m_posInfo;
|
||||
|
||||
// ZZ_U32 m_MaxValueOfFiberSpectrometer;
|
||||
|
||||
public slots:
|
||||
@ -62,7 +64,7 @@ public slots:
|
||||
void recordTarget(int recordTimes, QString path);
|
||||
void autoExpose();
|
||||
|
||||
void OpenFiberImagerAndRecord();
|
||||
void OpenFiberImagerAndRecord(QString posInfo);
|
||||
|
||||
signals:
|
||||
void sendExposureTimeSignal(int exposureTime);
|
||||
|
||||
@ -223,8 +223,14 @@ void OneMotorControl::record_white()
|
||||
|
||||
void OneMotorControl::run()
|
||||
{
|
||||
if (m_coordinator)//当高光谱相机停止采集后,马达还未回到原点时,上次任务的m_coordinator还没有被销毁
|
||||
{
|
||||
onSequenceComplete(0);
|
||||
}
|
||||
|
||||
qRegisterMetaType<OneMotionCapturePathLine>("OneMotionCapturePathLine");
|
||||
m_coordinator = new OneMotionCaptureCoordinator(m_multiAxisController, m_Imager);
|
||||
m_coordinator->setObjectName("testOneMotionCaptureCoordinator");
|
||||
connect(this, SIGNAL(start(OneMotionCapturePathLine)), m_coordinator, SLOT(startStepMotion(OneMotionCapturePathLine)));
|
||||
connect(this, SIGNAL(stopStepMotionSignal()), m_coordinator, SLOT(stopStepMotion()));
|
||||
|
||||
@ -261,3 +267,278 @@ bool OneMotorControl::getMotorsConnectionStatus()
|
||||
{
|
||||
return m_xMotorConnectionStatus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
OneMotorControl_LiftingPlatform::OneMotorControl_LiftingPlatform(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
connect(this->ui.connect_btn, SIGNAL(pressed()), this, SLOT(onConnectMotor()));
|
||||
|
||||
connect(this->ui.right_btn, SIGNAL(pressed()), this, SLOT(onxMotorRight()));
|
||||
connect(this->ui.right_btn, SIGNAL(released()), this, SLOT(onxMotorStop()));
|
||||
connect(this->ui.left_btn, SIGNAL(pressed()), this, SLOT(onxMotorLeft()));
|
||||
connect(this->ui.left_btn, SIGNAL(released()), this, SLOT(onxMotorStop()));
|
||||
|
||||
connect(this->ui.move2loc_pushButton, SIGNAL(pressed()), this, SLOT(onxMove2Loc()));
|
||||
|
||||
connect(this->ui.zero_start_btn, SIGNAL(released()), this, SLOT(zeroStart()));
|
||||
|
||||
connect(this->ui.rangeMeasurement_btn, SIGNAL(pressed()), this, SLOT(onx_rangeMeasurement()));
|
||||
|
||||
// 从 AppSettings 读取速度参数
|
||||
AppSettings& settings = AppSettings::instance();
|
||||
ui.speed_lineEdit->setText(QString::number(settings.scanSpeed()));
|
||||
ui.return_speed_lineEdit->setText(QString::number(settings.returnSpeed()));
|
||||
|
||||
// 连接信号,当控件数值变化时保存到 AppSettings
|
||||
connect(ui.speed_lineEdit, &QLineEdit::editingFinished, [this]() {
|
||||
AppSettings::instance().setScanSpeed(ui.speed_lineEdit->text().toDouble());
|
||||
});
|
||||
connect(ui.return_speed_lineEdit, &QLineEdit::editingFinished, [this]() {
|
||||
AppSettings::instance().setReturnSpeed(ui.return_speed_lineEdit->text().toDouble());
|
||||
});
|
||||
}
|
||||
|
||||
OneMotorControl_LiftingPlatform::~OneMotorControl_LiftingPlatform()
|
||||
{
|
||||
m_motorThread.quit();
|
||||
m_motorThread.wait();
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::onConnectMotor()
|
||||
{
|
||||
connectMotor(true);
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::connectMotor(bool isNotification)
|
||||
{
|
||||
if (getMotorsConnectionStatus())
|
||||
{
|
||||
if (isNotification)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText(QString::fromLocal8Bit("马达已连接!"));
|
||||
msgBox.exec();
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_multiAxisController != nullptr)
|
||||
{
|
||||
disconnect(m_multiAxisController, SIGNAL(broadcastLocationSignal(std::vector<double>)), this, SLOT(display_x_loc(std::vector<double>)));
|
||||
disconnect(this, SIGNAL(moveSignal(int, bool, double, int)), m_multiAxisController, SLOT(move(int, bool, double, int)));
|
||||
disconnect(this, SIGNAL(move2LocSignal(int, double, double, int)), m_multiAxisController, SLOT(moveTo(int, double, double, int)));
|
||||
disconnect(this, SIGNAL(stopSignal(int)), m_multiAxisController, SLOT(stop(int)));
|
||||
disconnect(this, SIGNAL(zeroStartSignal(int)), m_multiAxisController, SLOT(zeroStart(int)));
|
||||
disconnect(this, SIGNAL(rangeMeasurement(int, double, int)), m_multiAxisController, SLOT(rangeMeasurement(int, double, int)));
|
||||
disconnect(this, SIGNAL(testConnectivitySignal(int, int)), m_multiAxisController, SLOT(testConnectivity(int, int)));
|
||||
disconnect(m_multiAxisController, SIGNAL(broadcastConnectivity(std::vector<int>)), this, SLOT(display_motors_connectivity(std::vector<int>)));
|
||||
|
||||
m_motorThread.quit();
|
||||
m_motorThread.wait();
|
||||
m_multiAxisController = nullptr;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
FileOperation* fileOperation = new FileOperation();
|
||||
string directory = fileOperation->getDirectoryOfExe();
|
||||
QString configFilePath = QString::fromStdString(directory) + "\\oneMotorConfigFile_LiftingPlatform.cfg";
|
||||
|
||||
m_multiAxisController = new IrisMultiMotorController(configFilePath);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText(QString::fromLocal8Bit("请连接马达!"));
|
||||
msgBox.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
m_multiAxisController->moveToThread(&m_motorThread);
|
||||
connect(&m_motorThread, SIGNAL(finished()), m_multiAxisController, SLOT(deleteLater()));
|
||||
|
||||
connect(m_multiAxisController, SIGNAL(broadcastLocationSignal(std::vector<double>)), this, SLOT(display_x_loc(std::vector<double>)));
|
||||
|
||||
connect(this, SIGNAL(moveSignal(int, bool, double, int)), m_multiAxisController, SLOT(move(int, bool, double, int)));
|
||||
connect(this, SIGNAL(move2LocSignal(int, double, double, int)), m_multiAxisController, SLOT(moveTo(int, double, double, int)));
|
||||
connect(this, SIGNAL(stopSignal(int)), m_multiAxisController, SLOT(stop(int)));
|
||||
|
||||
connect(this, SIGNAL(zeroStartSignal(int)), m_multiAxisController, SLOT(zeroStart(int)));
|
||||
|
||||
connect(this, SIGNAL(rangeMeasurement(int, double, int)), m_multiAxisController, SLOT(rangeMeasurement(int, double, int)));
|
||||
|
||||
connect(this, SIGNAL(testConnectivitySignal(int, int)), m_multiAxisController, SLOT(testConnectivity(int, int)));
|
||||
connect(m_multiAxisController, SIGNAL(broadcastConnectivity(std::vector<int>)), this, SLOT(display_motors_connectivity(std::vector<int>)));
|
||||
|
||||
m_motorThread.start();
|
||||
emit testConnectivitySignal(0, 1000);
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::display_x_loc(std::vector<double> loc)
|
||||
{
|
||||
double tmp = round(loc[0] * 100) / 100;
|
||||
this->ui.realTimeLoc_lineEdit->setText(QString::number(tmp));
|
||||
|
||||
emit broadcastLocationSignal(loc);
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::display_motors_connectivity(std::vector<int> connectivity)
|
||||
{
|
||||
//std::cout << "-----------------------------------"<<connectivity.size()<< std::endl;
|
||||
if (connectivity[0])
|
||||
{
|
||||
m_xMotorConnectionStatus = true;
|
||||
|
||||
this->ui.motor_state_label->setStyleSheet(R"(
|
||||
QLabel
|
||||
{
|
||||
background-color: #08FACE;
|
||||
border-radius: 4px;
|
||||
}
|
||||
)");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_xMotorConnectionStatus = false;
|
||||
|
||||
this->ui.motor_state_label->setStyleSheet(R"(
|
||||
QLabel
|
||||
{
|
||||
background-color: red;
|
||||
border-radius: 4px;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
if (getMotorsConnectionStatus())
|
||||
{
|
||||
this->ui.connect_btn->setText(QString::fromLocal8Bit("已连接"));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->ui.connect_btn->setText(QString::fromLocal8Bit("重新连接"));
|
||||
}
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::zeroStart()
|
||||
{
|
||||
zeroStartSignal(0);
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::onx_rangeMeasurement()
|
||||
{
|
||||
double s0 = ui.speed_lineEdit->text().toDouble();
|
||||
emit rangeMeasurement(0, s0, 1000);
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::onxMove2Loc()
|
||||
{
|
||||
double s = ui.speed_lineEdit->text().toDouble();
|
||||
double l = ui.move2loc_lineEdit->text().toDouble();
|
||||
|
||||
emit move2LocSignal(0, l, s, 1000);
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::onxMotorRight()
|
||||
{
|
||||
double s = ui.speed_lineEdit->text().toDouble();
|
||||
|
||||
emit moveSignal(0, false, s, 1000);
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::onxMotorLeft()
|
||||
{
|
||||
double s = ui.speed_lineEdit->text().toDouble();
|
||||
|
||||
emit moveSignal(0, true, s, 1000);
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::onxMotorStop()
|
||||
{
|
||||
emit stopSignal(0);
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::run()
|
||||
{
|
||||
m_coordinator = new OneMotionCoordinator(m_multiAxisController,this);
|
||||
connect(m_coordinator, &OneMotionCoordinator::sequenceComplete, this, &OneMotorControl_LiftingPlatform::sequenceComplete);
|
||||
connect(m_coordinator, &OneMotionCoordinator::ArrivalSignal, this, &OneMotorControl_LiftingPlatform::onBack2Origin);
|
||||
|
||||
double plantDepthValue = DepthValueLogger::instance().readLatestPlantDepthValue();
|
||||
double liftingPlatformDepthValue = DepthValueLogger::instance().readLatestLiftingPlatformDepthValue();
|
||||
double targetDepth = liftingPlatformDepthValue - plantDepthValue;
|
||||
|
||||
if (targetDepth < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_coordinator->moveToTarget(targetDepth, ui.speed_lineEdit->text().toDouble());
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::stop()
|
||||
{
|
||||
emit stopStepMotionSignal();
|
||||
}
|
||||
|
||||
void OneMotorControl_LiftingPlatform::onBack2Origin(double pos)
|
||||
{
|
||||
emit back2OriginSignal_TimedDataCollection();
|
||||
|
||||
m_coordinator->deleteLater();
|
||||
m_coordinator = nullptr;
|
||||
}
|
||||
|
||||
bool OneMotorControl_LiftingPlatform::getMotorsConnectionStatus()
|
||||
{
|
||||
return m_xMotorConnectionStatus;
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <QThread>
|
||||
#include <QMessageBox>
|
||||
#include <QPointer>
|
||||
|
||||
#include "ui_oneMotorControl.h"
|
||||
|
||||
@ -10,6 +11,8 @@
|
||||
#include "MotorWindowBase.h"
|
||||
#include "AppSettings.h"
|
||||
|
||||
#include "DepthValueLogger.h"
|
||||
|
||||
class OneMotorControl : public QDialog, public MotorWindowBase
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -68,7 +71,7 @@ private:
|
||||
QThread m_motorThread;
|
||||
IrisMultiMotorController* m_multiAxisController = nullptr;
|
||||
|
||||
OneMotionCaptureCoordinator* m_coordinator = nullptr;
|
||||
QPointer<OneMotionCaptureCoordinator> m_coordinator;
|
||||
ImagerOperationBase* m_Imager;
|
||||
|
||||
DarkAndWhiteCaptureCoordinator* m_darkCaptureCoordinator = nullptr;
|
||||
@ -76,3 +79,62 @@ private:
|
||||
|
||||
bool m_xMotorConnectionStatus = false;
|
||||
};
|
||||
|
||||
class OneMotorControl_LiftingPlatform : public QDialog, public MotorWindowBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OneMotorControl_LiftingPlatform(QWidget* parent = nullptr);
|
||||
~OneMotorControl_LiftingPlatform();
|
||||
|
||||
void run();
|
||||
void stop();
|
||||
|
||||
bool getMotorsConnectionStatus();
|
||||
|
||||
void connectMotor(bool isNotification);
|
||||
|
||||
public Q_SLOTS:
|
||||
void onConnectMotor();
|
||||
|
||||
void display_x_loc(std::vector<double> loc);
|
||||
void display_motors_connectivity(std::vector<int> connectivity);
|
||||
void onxMove2Loc();
|
||||
void zeroStart();
|
||||
void onx_rangeMeasurement();
|
||||
|
||||
void onxMotorRight();
|
||||
void onxMotorLeft();
|
||||
void onxMotorStop();
|
||||
|
||||
void onBack2Origin(double pos);
|
||||
|
||||
signals:
|
||||
void moveSignal(int, bool, double, int);
|
||||
void move2LocSignal(int, double, double, int);
|
||||
void move2LocSignal(const std::vector<double>, const std::vector<double>, int);
|
||||
void stopSignal(int);
|
||||
|
||||
void rangeMeasurement(int, double, int);
|
||||
void zeroStartSignal(int);
|
||||
void testConnectivitySignal(int, int);
|
||||
|
||||
void start(OneMotionCapturePathLine);
|
||||
void stopStepMotionSignal();
|
||||
|
||||
void sequenceComplete(int status);
|
||||
void back2OriginSignal_TimedDataCollection();
|
||||
|
||||
void broadcastLocationSignal(std::vector<double>);
|
||||
|
||||
private:
|
||||
Ui::OneMotorControl_UI ui;
|
||||
|
||||
QThread m_motorThread;
|
||||
IrisMultiMotorController* m_multiAxisController = nullptr;
|
||||
|
||||
QPointer<OneMotionCoordinator> m_coordinator;
|
||||
|
||||
bool m_xMotorConnectionStatus = false;
|
||||
};
|
||||
|
||||
@ -587,13 +587,17 @@ QString TaskTreeModel::statusToString(TaskStatus status) const
|
||||
|
||||
QString TaskTreeModel::subTaskTypeToString(SubTaskType type) const
|
||||
{
|
||||
switch (type) {
|
||||
switch (type)
|
||||
{
|
||||
case SubTaskType::HyperSpectual400_1000nm: return QString::fromLocal8Bit("高光谱 400-1000nm");
|
||||
case SubTaskType::HyperSpectual1000_1700nm: return QString::fromLocal8Bit("高光谱 1000-1700nm");
|
||||
case SubTaskType::SingleLensReflex: return QString::fromLocal8Bit("单反相机");
|
||||
case SubTaskType::DepthCamera: return QString::fromLocal8Bit("深度相机");
|
||||
case SubTaskType::ObtainingDepthInformation: return QString::fromLocal8Bit("探测深度信息");
|
||||
case SubTaskType::AutoFocus: return QString::fromLocal8Bit("自动调焦");
|
||||
case SubTaskType::LiftingPlatform: return QString::fromLocal8Bit("升降平台");
|
||||
}
|
||||
return "未知类型";
|
||||
return QString::fromLocal8Bit("未知类型");
|
||||
}
|
||||
|
||||
QString TaskTreeModel::formatDuration(double minutes) const
|
||||
|
||||
@ -112,6 +112,10 @@ void TimedDataCollection::setupConnections()
|
||||
connect(m_scheduler, &TaskScheduler::startRecordSignal,
|
||||
this, &TimedDataCollection::startRecordSignal);
|
||||
|
||||
connect(m_scheduler, &TaskScheduler::ObtainingDepthInformationSignals, this, &TimedDataCollection::ObtainingDepthInformationSignals);
|
||||
connect(m_scheduler, &TaskScheduler::LiftingPlatformSignals, this, &TimedDataCollection::LiftingPlatformSignals);
|
||||
connect(m_scheduler, &TaskScheduler::AutoFocusSignals, this, &TimedDataCollection::AutoFocusSignals);
|
||||
|
||||
connect(m_scheduler, &TaskScheduler::switchHalogenLampSignal,
|
||||
this, &TimedDataCollection::switchHalogenLampSignal);
|
||||
connect(m_scheduler, &TaskScheduler::switchD65LampSignal,
|
||||
@ -416,6 +420,7 @@ void TimedDataCollection::readTimedTaskFromFile(const QString& filePath)
|
||||
double totalEstimatedMinutes = 0.0;
|
||||
for (int j = 0; j < loadedTasks[i].subTasks.size(); ++j)
|
||||
{
|
||||
loadedTasks[i].subTasks[j].durationMinutes = 0.0; // 初始化实际耗时为0
|
||||
QString pathLineFilePath = loadedTasks[i].subTasks[j].pathLineFilePath;
|
||||
if (!pathLineFilePath.isEmpty())
|
||||
{
|
||||
@ -426,6 +431,7 @@ void TimedDataCollection::readTimedTaskFromFile(const QString& filePath)
|
||||
}
|
||||
double slrTimeMinute = 135 / 60;
|
||||
loadedTasks[i].estimatedDurationMinutes = totalEstimatedMinutes + loadedTasks[i].HalogenLampPreheatingTime_Minute + slrTimeMinute;
|
||||
loadedTasks[i].durationMinutes = 0.0; // 初始化实际耗时为0
|
||||
}
|
||||
|
||||
m_taskModel->setTasks(loadedTasks);
|
||||
|
||||
@ -52,6 +52,10 @@ Q_SIGNALS:
|
||||
void motorParm(QString pathLineFilePath);
|
||||
void startRecordSignal(int camType);
|
||||
|
||||
void ObtainingDepthInformationSignals(SubTask info);
|
||||
void LiftingPlatformSignals(SubTask info);
|
||||
void AutoFocusSignals(SubTask info);
|
||||
|
||||
void switchHalogenLampSignal(int state);
|
||||
void switchD65LampSignal(int state);
|
||||
void switchSlrSignal(int state);
|
||||
|
||||
@ -113,9 +113,31 @@ SubTaskType TimedDataCollectionDataStructuresReaderWriter::stringToSubTaskType(c
|
||||
if (str == "HyperSpectual1000_1700nm") return SubTaskType::HyperSpectual1000_1700nm;
|
||||
if (str == "SingleLensReflex") return SubTaskType::SingleLensReflex;
|
||||
if (str == "DepthCamera") return SubTaskType::DepthCamera;
|
||||
|
||||
if (str == "ObtainingDepthInformation") return SubTaskType::ObtainingDepthInformation;
|
||||
if (str == "AutoFocus") return SubTaskType::AutoFocus;
|
||||
if (str == "LiftingPlatform") return SubTaskType::LiftingPlatform;
|
||||
|
||||
return SubTaskType::SingleLensReflex;
|
||||
}
|
||||
|
||||
QString TimedDataCollectionDataStructuresReaderWriter::hyperImagerTypeToString(HyperImagerType type)
|
||||
{
|
||||
switch (type) {
|
||||
case HyperImagerType::Pika_L: return "Pika_L";
|
||||
case HyperImagerType::Pika_NIR: return "Pika_NIR";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
HyperImagerType TimedDataCollectionDataStructuresReaderWriter::stringToHyperImagerType(const QString& str)
|
||||
{
|
||||
if (str == "Pika_L") return HyperImagerType::Pika_L;
|
||||
if (str == "Pika_NIR") return HyperImagerType::Pika_NIR;
|
||||
|
||||
return HyperImagerType::Pika_L;
|
||||
}
|
||||
|
||||
// ==================== SubTask序列化 ====================
|
||||
|
||||
QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const SubTask& subTask)
|
||||
@ -132,6 +154,19 @@ QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const S
|
||||
obj["exposureTime"] = subTask.exposureTime;
|
||||
obj["defaultRenderBand"] = subTask.defaultRenderBand;
|
||||
obj["captureIntervalSeconds"] = subTask.captureIntervalSeconds;
|
||||
|
||||
obj["autoFocusHyperImagerType"] = hyperImagerTypeToString(subTask.autoFocusHyperImagerType);
|
||||
obj["autoFocusMotorConfigFilePath"] = subTask.autoFocusMotorConfigFilePath;
|
||||
obj["autoFocusX"] = subTask.autoFocusX;
|
||||
obj["autoFocusY"] = subTask.autoFocusY;
|
||||
|
||||
obj["depthAlgorithm"] = subTask.depthAlgorithm;
|
||||
obj["depthInfoX"] = subTask.depthInfoX;
|
||||
obj["depthInfoY"] = subTask.depthInfoY;
|
||||
obj["averageNumberOfTimes"] = subTask.averageNumberOfTimes;
|
||||
obj["percentageOfEffectiveArea"] = subTask.percentageOfEffectiveArea;
|
||||
obj["depthType"] = subTask.depthType;
|
||||
obj["depthRangePercentage"] = subTask.depthRangePercentage;
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -148,6 +183,19 @@ bool TimedDataCollectionDataStructuresReaderWriter::jsonToSubTask(const QJsonObj
|
||||
subTask.exposureTime = json["exposureTime"].toDouble();
|
||||
subTask.defaultRenderBand = json["defaultRenderBand"].toInt();
|
||||
subTask.captureIntervalSeconds = json["captureIntervalSeconds"].toDouble();
|
||||
|
||||
subTask.autoFocusHyperImagerType = stringToHyperImagerType(json["autoFocusHyperImagerType"].toString());
|
||||
subTask.autoFocusMotorConfigFilePath = json["autoFocusMotorConfigFilePath"].toString();
|
||||
subTask.autoFocusX = json["autoFocusX"].toDouble();
|
||||
subTask.autoFocusY = json["autoFocusY"].toDouble();
|
||||
|
||||
subTask.depthAlgorithm = json["depthAlgorithm"].toInt();
|
||||
subTask.depthInfoX = json["depthInfoX"].toDouble();
|
||||
subTask.depthInfoY = json["depthInfoY"].toDouble();
|
||||
subTask.averageNumberOfTimes = json["averageNumberOfTimes"].toInt();
|
||||
subTask.percentageOfEffectiveArea = json["percentageOfEffectiveArea"].toDouble();
|
||||
subTask.depthType = json["depthType"].toInt();
|
||||
subTask.depthRangePercentage = json["depthRangePercentage"].toDouble();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -235,15 +283,10 @@ void TaskExecutor::execute(const TimedTask& task)
|
||||
|
||||
qDebug() << "TaskExecutor: Starting task" << task.id;
|
||||
|
||||
// 打开卤素灯预热
|
||||
emit switchHalogenLampSignal(1);
|
||||
printMsgAndTime("open HalogenLamp");
|
||||
|
||||
makeFolder(m_task.savePath);
|
||||
|
||||
// 开始执行第一个子任务
|
||||
double sleepTimeSecond = m_task.HalogenLampPreheatingTime_Minute * 60;
|
||||
QTimer::singleShot(sleepTimeSecond *1000, this, &TaskExecutor::executeNextSubTask);
|
||||
double sleepTimeSecond = 1;
|
||||
QTimer::singleShot(sleepTimeSecond * 1000, this, &TaskExecutor::executeNextSubTask);
|
||||
}
|
||||
|
||||
void TaskExecutor::printMsgAndTime(QString msg)
|
||||
@ -269,10 +312,12 @@ void TaskExecutor::makeFolder(QString savePath)
|
||||
if (!dir.exists()) {
|
||||
if (dir.mkpath(".")) {
|
||||
qDebug() << "TaskExecutor: Created data folder:" << savePath;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
qWarning() << "TaskExecutor: Failed to create data folder:" << savePath;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
qDebug() << "TaskExecutor: Data folder already exists:" << savePath;
|
||||
}
|
||||
}
|
||||
@ -299,7 +344,7 @@ void TaskExecutor::onSequenceComplete(int status)
|
||||
|
||||
subTask.endTime = QDateTime::currentDateTime();
|
||||
subTask.durationMinutes = (double)subTask.startTime.secsTo(subTask.endTime) / 60;
|
||||
qDebug() << "TaskExecutor: subtask "<< m_currentSubTaskIndex<< " time consuming(Minutes): "<< subTask.durationMinutes;
|
||||
qDebug() << "TaskExecutor: subtask " << m_currentSubTaskIndex << " time consuming(Minutes): " << subTask.durationMinutes;
|
||||
|
||||
// 拷贝subTask.pathLineFilePath到m_currentFolder
|
||||
if (!subTask.pathLineFilePath.isEmpty() && QFile::exists(subTask.pathLineFilePath)) {
|
||||
@ -307,7 +352,8 @@ void TaskExecutor::onSequenceComplete(int status)
|
||||
QString destPath = m_currentFolder + QDir::separator() + fileInfo.fileName();
|
||||
if (QFile::copy(subTask.pathLineFilePath, destPath)) {
|
||||
qDebug() << "TaskExecutor: Copied path line file to" << destPath;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
qDebug() << "TaskExecutor: Failed to copy path line file from" << subTask.pathLineFilePath << "to" << destPath;
|
||||
}
|
||||
}
|
||||
@ -315,23 +361,38 @@ void TaskExecutor::onSequenceComplete(int status)
|
||||
emit subTaskFinished(m_currentSubTaskIndex, subTask.type, (status == 0));
|
||||
emit taskUpdated(m_task);
|
||||
}
|
||||
//当前任务已经完成,正确关闭灯光或者电源
|
||||
ensurePostTaskLighting();
|
||||
|
||||
//
|
||||
switch (m_task.subTasks[m_currentSubTaskIndex].type)
|
||||
emit taskUpdated(m_task);
|
||||
}
|
||||
|
||||
void TaskExecutor::ensurePreTaskLighting()
|
||||
{
|
||||
SubTaskType currentTaskType = m_task.subTasks[m_currentSubTaskIndex].type;
|
||||
if (currentTaskType != SubTaskType::HyperSpectual400_1000nm &&
|
||||
currentTaskType != SubTaskType::HyperSpectual1000_1700nm)
|
||||
{
|
||||
case SubTaskType::SingleLensReflex:
|
||||
emit switchHalogenLampSignal(0);
|
||||
}
|
||||
if (currentTaskType != SubTaskType::SingleLensReflex &&
|
||||
currentTaskType != SubTaskType::DepthCamera &&
|
||||
currentTaskType != SubTaskType::ObtainingDepthInformation)
|
||||
{
|
||||
emit switchD65LampSignal(0);
|
||||
break;
|
||||
}
|
||||
case SubTaskType::DepthCamera:
|
||||
}
|
||||
|
||||
void TaskExecutor::ensurePostTaskLighting()
|
||||
{
|
||||
SubTaskType currentTaskType = m_task.subTasks[m_currentSubTaskIndex].type;
|
||||
if (currentTaskType == SubTaskType::SingleLensReflex ||
|
||||
currentTaskType == SubTaskType::DepthCamera ||
|
||||
currentTaskType == SubTaskType::ObtainingDepthInformation)
|
||||
{
|
||||
emit switchD65LampSignal(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 判断下一次的任务是否为高光谱任务,如果不是关闭卤素灯
|
||||
int nestSubTaskIndex = m_currentSubTaskIndex + 1;
|
||||
if (nestSubTaskIndex >= m_task.subTasks.size())
|
||||
{
|
||||
@ -340,21 +401,13 @@ void TaskExecutor::onSequenceComplete(int status)
|
||||
emit switchHalogenLampSignal(0);
|
||||
return;
|
||||
}
|
||||
switch (m_task.subTasks[nestSubTaskIndex].type)
|
||||
{
|
||||
case SubTaskType::SingleLensReflex:
|
||||
// 判断下一次的任务是否为高光谱任务,如果不是就关闭卤素灯
|
||||
SubTaskType nestTaskType = m_task.subTasks[nestSubTaskIndex].type;
|
||||
if (nestTaskType != SubTaskType::HyperSpectual400_1000nm &&
|
||||
nestTaskType != SubTaskType::HyperSpectual1000_1700nm)
|
||||
{
|
||||
emit switchHalogenLampSignal(0);
|
||||
break;
|
||||
}
|
||||
case SubTaskType::DepthCamera:
|
||||
{
|
||||
emit switchHalogenLampSignal(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit taskUpdated(m_task);
|
||||
}
|
||||
|
||||
void TaskExecutor::onBack2Origin()
|
||||
@ -373,12 +426,12 @@ void TaskExecutor::onBack2Origin()
|
||||
int nestSubTaskIndex = m_currentSubTaskIndex + 1;
|
||||
if (nestSubTaskIndex < m_task.subTasks.size()) {
|
||||
// 执行下一个子任务
|
||||
if(m_task.subTasks[nestSubTaskIndex].type== SubTaskType::SingleLensReflex)
|
||||
if (m_task.subTasks[nestSubTaskIndex].type == SubTaskType::SingleLensReflex)
|
||||
{
|
||||
printMsgAndTime("Slr task,for weak up,please wait 135 seconds!");
|
||||
emit switchSlrSignal(0);
|
||||
|
||||
QTimer::singleShot(135*1000, this, &TaskExecutor::executeNextSubTask);
|
||||
QTimer::singleShot(135 * 1000, this, &TaskExecutor::executeNextSubTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -434,53 +487,117 @@ void TaskExecutor::executeNextSubTask()
|
||||
|
||||
emit subTaskStarted(m_currentSubTaskIndex, subTask.type);
|
||||
|
||||
emit motorParm(subTask.pathLineFilePath);
|
||||
|
||||
int camType;
|
||||
switch (subTask.type)
|
||||
{
|
||||
case SubTaskType::ObtainingDepthInformation:
|
||||
{
|
||||
//(1)移动到指定位置并通过深度相机获取深度信息(2)调整升降板高度(白板+调焦板)(3)回到零位(0,0)
|
||||
emit switchD65LampSignal(1);
|
||||
emit ObtainingDepthInformationSignals(subTask);
|
||||
break;
|
||||
}
|
||||
case SubTaskType::AutoFocus:
|
||||
{
|
||||
switch (subTask.autoFocusHyperImagerType)
|
||||
{
|
||||
case HyperImagerType::Pika_L:
|
||||
m_camType = 0;
|
||||
m_currentFolder = makeSubTaskDataFolder("L");
|
||||
emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "L");
|
||||
|
||||
break;
|
||||
case HyperImagerType::Pika_NIR:
|
||||
m_camType = 1;
|
||||
m_currentFolder = makeSubTaskDataFolder("NIR");
|
||||
emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "NIR");
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
emit switchHalogenLampSignal(1);
|
||||
|
||||
//执行自动调焦任务
|
||||
QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitAutoFocusSignal);
|
||||
break;
|
||||
}
|
||||
case SubTaskType::LiftingPlatform:
|
||||
{
|
||||
//执行升降平台任务
|
||||
emit LiftingPlatformSignals(subTask);
|
||||
break;
|
||||
}
|
||||
case SubTaskType::HyperSpectual400_1000nm:
|
||||
{
|
||||
camType = 0;
|
||||
m_camType = 0;
|
||||
m_currentFolder = makeSubTaskDataFolder("L");
|
||||
emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "L");
|
||||
emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "L");
|
||||
|
||||
emit motorParm(subTask.pathLineFilePath);
|
||||
|
||||
// 打开卤素灯预热
|
||||
emit switchHalogenLampSignal(1);
|
||||
printMsgAndTime("open HalogenLamp");
|
||||
double sleepTimeSecond = m_task.HalogenLampPreheatingTime_Minute * 60;
|
||||
QTimer::singleShot(sleepTimeSecond * 1000, this, &TaskExecutor::emitRecordSignal);
|
||||
|
||||
break;
|
||||
}
|
||||
case SubTaskType::HyperSpectual1000_1700nm:
|
||||
{
|
||||
camType = 1;
|
||||
m_camType = 1;
|
||||
m_currentFolder = makeSubTaskDataFolder("NIR");
|
||||
emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "NIR");
|
||||
emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "NIR");
|
||||
|
||||
emit motorParm(subTask.pathLineFilePath);
|
||||
|
||||
QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal);
|
||||
|
||||
break;
|
||||
}
|
||||
case SubTaskType::SingleLensReflex:
|
||||
{
|
||||
camType = 2;
|
||||
m_camType = 2;
|
||||
m_currentFolder = makeSubTaskDataFolder("SLR");
|
||||
emit camParm(camType, 3, m_currentFolder);
|
||||
emit camParm(m_camType, 3, m_currentFolder);
|
||||
|
||||
emit motorParm(subTask.pathLineFilePath);
|
||||
|
||||
emit switchD65LampSignal(1);
|
||||
|
||||
|
||||
emit switchSlrSignal(1);
|
||||
|
||||
QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal);
|
||||
|
||||
break;
|
||||
}
|
||||
case SubTaskType::DepthCamera:
|
||||
{
|
||||
camType = 3;
|
||||
m_camType = 3;
|
||||
m_currentFolder = makeSubTaskDataFolder("DepthCamera");
|
||||
emit camParm(camType, 3, m_currentFolder);
|
||||
emit camParm(m_camType, 3, m_currentFolder);
|
||||
|
||||
emit motorParm(subTask.pathLineFilePath);
|
||||
|
||||
emit switchD65LampSignal(1);
|
||||
|
||||
QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
ensurePreTaskLighting();
|
||||
}
|
||||
|
||||
emit startRecordSignal(camType);
|
||||
void TaskExecutor::emitRecordSignal()
|
||||
{
|
||||
emit startRecordSignal(m_camType);
|
||||
}
|
||||
|
||||
void TaskExecutor::emitAutoFocusSignal()
|
||||
{
|
||||
SubTask& subTask = m_task.subTasks[m_currentSubTaskIndex];
|
||||
emit AutoFocusSignals(subTask);
|
||||
}
|
||||
|
||||
// ==================== TaskScheduler 实现 ====================
|
||||
@ -581,7 +698,7 @@ void TaskScheduler::checkTasks()
|
||||
if (task.scheduledTime > now) continue;
|
||||
|
||||
qint64 fireThreSecs = 5;
|
||||
if (task.scheduledTime.addSecs(-1*fireThreSecs) < now && task.scheduledTime.addSecs(fireThreSecs) > now)// 到达计划时间,启动任务
|
||||
if (task.scheduledTime.addSecs(-1 * fireThreSecs) < now && task.scheduledTime.addSecs(fireThreSecs) > now)// 到达计划时间,启动任务
|
||||
{
|
||||
std::cerr << "TaskScheduler::checkTasks,到达计划时间,启动任务" << std::endl;
|
||||
executeTask(task);
|
||||
@ -657,6 +774,10 @@ void TaskScheduler::executeTask(TimedTask& task)
|
||||
connect(m_currentExecutor, &TaskExecutor::startRecordSignal,
|
||||
this, &TaskScheduler::startRecordSignal);
|
||||
|
||||
connect(m_currentExecutor, &TaskExecutor::ObtainingDepthInformationSignals, this, &TaskScheduler::ObtainingDepthInformationSignals);
|
||||
connect(m_currentExecutor, &TaskExecutor::LiftingPlatformSignals, this, &TaskScheduler::LiftingPlatformSignals);
|
||||
connect(m_currentExecutor, &TaskExecutor::AutoFocusSignals, this, &TaskScheduler::AutoFocusSignals);
|
||||
|
||||
connect(m_currentExecutor, &TaskExecutor::switchHalogenLampSignal, this, &TaskScheduler::switchHalogenLampSignal);
|
||||
connect(m_currentExecutor, &TaskExecutor::switchD65LampSignal, this, &TaskScheduler::switchD65LampSignal);
|
||||
connect(m_currentExecutor, &TaskExecutor::switchSlrSignal, this, &TaskScheduler::switchSlrSignal);
|
||||
@ -687,7 +808,8 @@ void TaskScheduler::updateTaskStatus(int taskId, TaskStatus status)
|
||||
task.status = status;
|
||||
if (status == TaskStatus::Running) {
|
||||
task.startTime = QDateTime::currentDateTime();
|
||||
} else if (status == TaskStatus::Finished) {
|
||||
}
|
||||
else if (status == TaskStatus::Finished) {
|
||||
task.endTime = QDateTime::currentDateTime();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -25,7 +25,14 @@ enum class SubTaskType {
|
||||
HyperSpectual400_1000nm, // 400nm-1000nm高光谱相机
|
||||
HyperSpectual1000_1700nm, // 1000nm-1700nm高光谱相机
|
||||
SingleLensReflex, // 单反相机
|
||||
DepthCamera // 深度相机
|
||||
DepthCamera, // 深度相机采集任务
|
||||
ObtainingDepthInformation, //通过深度相机获取被测物体的深度信息
|
||||
AutoFocus, // 自动对焦
|
||||
LiftingPlatform // 升降平台
|
||||
};
|
||||
enum class HyperImagerType {
|
||||
Pika_L,
|
||||
Pika_NIR
|
||||
};
|
||||
|
||||
// ==================== 统一子任务封装 ====================
|
||||
@ -46,6 +53,21 @@ struct SubTask {
|
||||
double exposureTime = 0.0; // 高光谱相机用
|
||||
int defaultRenderBand = 550; // 1000-1700nm高光谱用
|
||||
int captureIntervalSeconds = 5; // 单反/深度相机用
|
||||
|
||||
//任务ObtainingDepthInformation所需的x和y坐标
|
||||
int depthAlgorithm = 0;//0:深度图像的范围(percentageOfEffectiveArea)平均,1:深度范围(depthRangePercentage)的百分比,2:通过彩色图像分割植被区域的深度图像,然后平均
|
||||
int depthType = 0;//0表示植被深度,1表示白板/调焦版深度
|
||||
double depthInfoX = 0.0;
|
||||
double depthInfoY = 0.0;
|
||||
int averageNumberOfTimes = 1; //任务ObtainingDepthInformation所需的平均次数
|
||||
double percentageOfEffectiveArea = 50.0; //深度图像的有效范围百分比
|
||||
double depthRangePercentage = 80.0; //深度范围的百分比
|
||||
|
||||
//高光谱自动调焦
|
||||
HyperImagerType autoFocusHyperImagerType;//取值范围:L、NIR
|
||||
QString autoFocusMotorConfigFilePath;//马达配置文件
|
||||
double autoFocusX = 0.0;
|
||||
double autoFocusY = 0.0;
|
||||
};
|
||||
|
||||
// ==================== 定时任务 ====================
|
||||
@ -109,6 +131,9 @@ private:
|
||||
|
||||
static QString subTaskTypeToString(SubTaskType type);
|
||||
static SubTaskType stringToSubTaskType(const QString& str);
|
||||
|
||||
static QString hyperImagerTypeToString(HyperImagerType type);
|
||||
static HyperImagerType stringToHyperImagerType(const QString& str);
|
||||
};
|
||||
|
||||
// ==================== 任务执行器 ====================
|
||||
@ -151,6 +176,10 @@ signals:
|
||||
void motorParm(QString pathLineFilePath);
|
||||
void startRecordSignal(int camType);
|
||||
|
||||
void ObtainingDepthInformationSignals(SubTask info);
|
||||
void LiftingPlatformSignals(SubTask info);
|
||||
void AutoFocusSignals(SubTask info);
|
||||
|
||||
void switchHalogenLampSignal(int state);
|
||||
void switchD65LampSignal(int state);
|
||||
void switchSlrSignal(int state);
|
||||
@ -160,15 +189,22 @@ public slots:
|
||||
void onBack2Origin();
|
||||
void onError(const QString& error);
|
||||
|
||||
void emitRecordSignal();
|
||||
void emitAutoFocusSignal();
|
||||
|
||||
private:
|
||||
QString m_currentFolder;
|
||||
void executeNextSubTask();
|
||||
void ensurePreTaskLighting();
|
||||
void ensurePostTaskLighting();
|
||||
|
||||
void printMsgAndTime(QString msg);
|
||||
|
||||
TimedTask m_task;
|
||||
int m_currentSubTaskIndex;
|
||||
bool m_isRunning;
|
||||
|
||||
int m_camType;
|
||||
};
|
||||
|
||||
// ==================== 任务调度器 ====================
|
||||
@ -214,6 +250,10 @@ signals:
|
||||
void motorParm(QString pathLineFilePath);
|
||||
void startRecordSignal(int camType);
|
||||
|
||||
void ObtainingDepthInformationSignals(SubTask info);
|
||||
void LiftingPlatformSignals(SubTask info);
|
||||
void AutoFocusSignals(SubTask info);
|
||||
|
||||
void switchHalogenLampSignal(int state);
|
||||
void switchD65LampSignal(int state);
|
||||
void switchSlrSignal(int state);
|
||||
|
||||
@ -210,6 +210,78 @@ void TwoMotorControl::onBack2Origin2()
|
||||
emit back2OriginSignal_TimedDataCollection();
|
||||
}
|
||||
|
||||
void TwoMotorControl::run4_ObtainTargetDepthInfo(DepthCameraWindow* window, double depthAlgorithm,int depthType, double depthInfoX, double depthInfoY, int averageNumberOfTimes, double percentageOfEffectiveArea, double depthRangePercentage)
|
||||
{
|
||||
m_depthType = depthType;
|
||||
|
||||
window->m_DepthCameraOperation->setDepthAlgorithm(depthAlgorithm);
|
||||
window->m_DepthCameraOperation->setAverageNumberOfTimes(averageNumberOfTimes);
|
||||
window->m_DepthCameraOperation->setPercentageOfEffectiveArea(percentageOfEffectiveArea);
|
||||
window->m_DepthCameraOperation->setDepthRangePercentage(depthRangePercentage);
|
||||
|
||||
m_ObtainTargetDepthInfoCoordinator = new TwoMotor1PosCoordinator(m_multiAxisController);
|
||||
connect(m_ObtainTargetDepthInfoCoordinator, &TwoMotor1PosCoordinator::ArrivalSignal, window, &DepthCameraWindow::OpenDepthCamera_getDepthValue);
|
||||
|
||||
connect(window->m_DepthCameraOperation, &DepthCameraOperation::DepthValueSignal, m_ObtainTargetDepthInfoCoordinator, &TwoMotor1PosCoordinator::back2origin);
|
||||
connect(window->m_DepthCameraOperation, &DepthCameraOperation::DepthValueSignal, this, &TwoMotorControl::sequenceComplete, Qt::UniqueConnection);//关灯
|
||||
connect(window->m_DepthCameraOperation, &DepthCameraOperation::DepthValueSignal, this, &TwoMotorControl::saveDepthValue, Qt::UniqueConnection);
|
||||
|
||||
connect(m_ObtainTargetDepthInfoCoordinator, &TwoMotor1PosCoordinator::back2OriginSignal, this, &TwoMotorControl::onBack2Origin3);
|
||||
|
||||
double xmotor_move_speed = ui.xmotor_move_speed_lineEdit->text().toDouble();
|
||||
double ymotor_move_speed = ui.ymotor_move_speed_lineEdit->text().toDouble();
|
||||
|
||||
m_ObtainTargetDepthInfoCoordinator->moveToTarget(depthInfoX, depthInfoY, xmotor_move_speed, ymotor_move_speed);
|
||||
}
|
||||
|
||||
void TwoMotorControl::run5_AutoFocus(double autoFocusX, double autoFocusY)
|
||||
{
|
||||
m_focusWindow = new focusWindow(this, m_Imager);
|
||||
m_focusWindow->onConnectMotor();
|
||||
m_focusWindow->show();
|
||||
|
||||
//自动调焦的协调器添加功能:先归零
|
||||
m_autoFocusCoordinator = new TwoMotor1PosCoordinator(m_multiAxisController);
|
||||
connect(m_autoFocusCoordinator, &TwoMotor1PosCoordinator::ArrivalSignal, m_focusWindow, &focusWindow::onAutoFocus);
|
||||
connect(m_focusWindow, &focusWindow::AutoFocusFinishedSignal, m_autoFocusCoordinator, &TwoMotor1PosCoordinator::back2origin);
|
||||
connect(m_focusWindow, &focusWindow::AutoFocusFinishedSignal, this, &TwoMotorControl::sequenceComplete, Qt::UniqueConnection);
|
||||
connect(m_autoFocusCoordinator, &TwoMotor1PosCoordinator::back2OriginSignal, this, &TwoMotorControl::onBack2Origin4);
|
||||
|
||||
|
||||
double xmotor_move_speed = ui.xmotor_move_speed_lineEdit->text().toDouble();
|
||||
double ymotor_move_speed = ui.ymotor_move_speed_lineEdit->text().toDouble();
|
||||
m_autoFocusCoordinator->moveToTarget(autoFocusX, autoFocusY, xmotor_move_speed, ymotor_move_speed);
|
||||
}
|
||||
|
||||
void TwoMotorControl::saveDepthValue(double depthValue)
|
||||
{
|
||||
if (m_depthType == 0)//0表示植被深度,1表示白板/调焦版深度
|
||||
{
|
||||
DepthValueLogger::instance().appendPlantDepthValue(depthValue);
|
||||
}
|
||||
else if (m_depthType == 1)
|
||||
{
|
||||
DepthValueLogger::instance().appendLiftingPlatformDepthValue(depthValue);
|
||||
}
|
||||
}
|
||||
|
||||
void TwoMotorControl::onBack2Origin3()
|
||||
{
|
||||
m_ObtainTargetDepthInfoCoordinator->deleteLater();
|
||||
m_ObtainTargetDepthInfoCoordinator = nullptr;
|
||||
emit back2OriginSignal_TimedDataCollection();
|
||||
}
|
||||
|
||||
void TwoMotorControl::onBack2Origin4()
|
||||
{
|
||||
m_focusWindow->deleteLater();
|
||||
m_focusWindow = nullptr;
|
||||
|
||||
m_autoFocusCoordinator->deleteLater();
|
||||
m_autoFocusCoordinator = nullptr;
|
||||
emit back2OriginSignal_TimedDataCollection();
|
||||
}
|
||||
|
||||
void TwoMotorControl::run()
|
||||
{
|
||||
if (getState())
|
||||
|
||||
@ -15,6 +15,10 @@
|
||||
|
||||
#include "PathLine.h"
|
||||
|
||||
#include "DepthValueLogger.h"
|
||||
|
||||
#include "focusWindow.h"
|
||||
|
||||
#define PI 3.1415926
|
||||
|
||||
class TwoMotorControl : public QDialog, public MotorWindowBase
|
||||
@ -82,7 +86,12 @@ public Q_SLOTS:
|
||||
|
||||
void run2(SingleLensReflexCameraWindow* w);
|
||||
void run3(DepthCameraWindow* window);
|
||||
void run4_ObtainTargetDepthInfo(DepthCameraWindow* window, double depthAlgorithm, int depthType, double depthInfoX, double depthInfoY, int averageNumberOfTimes, double percentageOfEffectiveArea, double depthRangePercentage);
|
||||
void run5_AutoFocus(double autoFocusX, double autoFocusY);
|
||||
void onBack2Origin2();
|
||||
void saveDepthValue(double depthValue);
|
||||
void onBack2Origin3();
|
||||
void onBack2Origin4();
|
||||
|
||||
void stop_record();
|
||||
|
||||
@ -111,10 +120,16 @@ private:
|
||||
QThread m_coordinatorThread;
|
||||
TwoMotionCaptureCoordinator* m_coordinator = nullptr;
|
||||
TwoMotionCaptureCoordinator* m_coordinator_TimedDataCollection = nullptr;
|
||||
TwoMotor1PosCoordinator* m_ObtainTargetDepthInfoCoordinator = nullptr;
|
||||
TwoMotor1PosCoordinator* m_autoFocusCoordinator = nullptr;
|
||||
|
||||
DarkAndWhiteCaptureCoordinator* m_darkCaptureCoordinator = nullptr;
|
||||
DarkAndWhiteCaptureCoordinator* m_whiteCaptureCoordinator = nullptr;
|
||||
|
||||
QThread m_motorThread;
|
||||
IrisMultiMotorController* m_multiAxisController = nullptr;
|
||||
|
||||
int m_depthType;
|
||||
|
||||
focusWindow* m_focusWindow = nullptr;
|
||||
};
|
||||
|
||||
@ -288,7 +288,7 @@ QPushButton:pressed
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>版本:3.1.1</string>
|
||||
<string>版本:3.1.3</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@ -78,6 +78,40 @@ focusWindow::focusWindow(QWidget *parent, ImagerOperationBase* imager)
|
||||
m_dSpeed = 1.0;
|
||||
}
|
||||
|
||||
void focusWindow::showMessageBox(QString msg, QString title)
|
||||
{
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle(title);
|
||||
msgBox.setText(msg);
|
||||
msgBox.setStyleSheet(R"(
|
||||
QMessageBox {
|
||||
background-color: #0D1233;
|
||||
}
|
||||
QMessageBox QLabel {
|
||||
color: #ACCDFF;
|
||||
font-size: 14px;
|
||||
}
|
||||
QPushButton {
|
||||
background-color: #142D7F;
|
||||
color: #e6eeff;
|
||||
border: 1px solid #2f6bff;
|
||||
border-radius: 6px;
|
||||
padding: 6px 20px;
|
||||
min-width: 60px;
|
||||
font-size: 13px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
border: 1px solid #4d8dff;
|
||||
background-color: red;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #23345c;
|
||||
}
|
||||
)");
|
||||
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
focusWindow::~focusWindow()
|
||||
{
|
||||
printf("destroy focusWindow-------------------------\n");
|
||||
@ -163,33 +197,7 @@ void focusWindow::onConnectMotor()
|
||||
{
|
||||
if (ui.is_new_version_radioButton->isChecked())
|
||||
{
|
||||
FileOperation* fileOperation = new FileOperation();
|
||||
string directory = fileOperation->getDirectoryOfExe();
|
||||
QString configFilePath = QString::fromStdString(directory) + "\\oneMotorConfigFile_focus.cfg";
|
||||
|
||||
m_multiAxisController = new IrisMultiMotorController(configFilePath);
|
||||
m_multiAxisController->moveToThread(&m_motorThread);
|
||||
connect(&m_motorThread, SIGNAL(finished()), m_multiAxisController, SLOT(deleteLater()));
|
||||
connect(this, SIGNAL(rmoveSignal(int, double, double, int)), m_multiAxisController, SLOT(rmove(int, double, double, int)));
|
||||
connect(this, SIGNAL(move2LocSignal(int, double, double, int)), m_multiAxisController, SLOT(moveTo(int, double, double, int)));
|
||||
connect(this, SIGNAL(rangeMeasurementSignal(int, double, int)), m_multiAxisController, SLOT(rangeMeasurement(int, double, int)));
|
||||
connect(this, SIGNAL(zeroStartSignal(int)), m_multiAxisController, SLOT(zeroStart(int)));
|
||||
connect(this, SIGNAL(move2MaxLocSignal(int, double, int)), m_multiAxisController, SLOT(moveToMax(int, double, int)));
|
||||
connect(m_multiAxisController, SIGNAL(broadcastLocationSignal(std::vector<double>)), this, SLOT(display_x_loc(std::vector<double>)));
|
||||
connect(m_multiAxisController, SIGNAL(motorStopSignal(int, double)), this, SLOT(moveAfterAutoFocus(int, double)));
|
||||
m_motorThread.start();
|
||||
|
||||
//归零
|
||||
//emit zeroStartSignal(0);
|
||||
|
||||
//自动调焦逻辑
|
||||
m_coordinator = new MotionCaptureCoordinator(m_multiAxisController, m_Imager);
|
||||
m_coordinator->moveToThread(&m_MotionCaptureCoordinatorThread);
|
||||
connect(&m_MotionCaptureCoordinatorThread, SIGNAL(finished()), m_coordinator, SLOT(deleteLater()));
|
||||
connect(this, SIGNAL(startStepMotion(double, int, double, double)), m_coordinator, SLOT(startStepMotion(double, int, double, double)));
|
||||
connect(m_coordinator, SIGNAL(progressChanged(int)), this, SLOT(onAutoFocusProgress(int)));
|
||||
connect(m_coordinator, SIGNAL(sequenceComplete()), this, SLOT(onAutoFocusFinished()));
|
||||
m_MotionCaptureCoordinatorThread.start();
|
||||
connectMotor(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -260,6 +268,131 @@ void focusWindow::onConnectMotor()
|
||||
disableBeforeConnect(false);
|
||||
}
|
||||
|
||||
void focusWindow::connectMotor(bool isNotification)//需要修改这个函数
|
||||
{
|
||||
if (getMotorsConnectionStatus())
|
||||
{
|
||||
if (isNotification)
|
||||
{
|
||||
showMessageBox(QString::fromLocal8Bit("马达已连接!"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_multiAxisController)
|
||||
{
|
||||
disconnect(&m_motorThread, SIGNAL(finished()), m_multiAxisController, SLOT(deleteLater()));
|
||||
disconnect(this, SIGNAL(rmoveSignal(int, double, double, int)), m_multiAxisController, SLOT(rmove(int, double, double, int)));
|
||||
disconnect(this, SIGNAL(move2LocSignal(int, double, double, int)), m_multiAxisController, SLOT(moveTo(int, double, double, int)));
|
||||
disconnect(this, SIGNAL(rangeMeasurementSignal(int, double, int)), m_multiAxisController, SLOT(rangeMeasurement(int, double, int)));
|
||||
disconnect(this, SIGNAL(zeroStartSignal(int)), m_multiAxisController, SLOT(zeroStart(int)));
|
||||
disconnect(this, SIGNAL(move2MaxLocSignal(int, double, int)), m_multiAxisController, SLOT(moveToMax(int, double, int)));
|
||||
disconnect(m_multiAxisController, SIGNAL(broadcastLocationSignal(std::vector<double>)), this, SLOT(display_x_loc(std::vector<double>)));
|
||||
disconnect(m_multiAxisController, SIGNAL(motorStopSignal(int, double)), this, SLOT(moveAfterAutoFocus(int, double)));
|
||||
disconnect(m_multiAxisController, SIGNAL(broadcastConnectivity(std::vector<int>)), this, SLOT(display_motors_connectivity(std::vector<int>)));
|
||||
|
||||
m_motorThread.quit();
|
||||
m_motorThread.wait();
|
||||
m_multiAxisController->deleteLater();
|
||||
}
|
||||
|
||||
if (m_coordinator)
|
||||
{
|
||||
disconnect(&m_MotionCaptureCoordinatorThread, SIGNAL(finished()), m_coordinator, SLOT(deleteLater()));
|
||||
disconnect(this, SIGNAL(startStepMotionSignal(double, int, double, double)), m_coordinator, SLOT(startStepMotion(double, int, double, double)));
|
||||
disconnect(m_coordinator, SIGNAL(progressChanged(int)), this, SLOT(onAutoFocusProgress(int)));
|
||||
disconnect(m_coordinator, SIGNAL(sequenceComplete()), this, SLOT(onAutoFocusFinished()));
|
||||
|
||||
m_MotionCaptureCoordinatorThread.quit();
|
||||
m_MotionCaptureCoordinatorThread.wait();
|
||||
m_coordinator->deleteLater();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
FileOperation* fileOperation = new FileOperation();
|
||||
string directory = fileOperation->getDirectoryOfExe();
|
||||
QString configFilePath = QString::fromStdString(directory) + "\\oneMotorConfigFile_focus.cfg";
|
||||
|
||||
m_multiAxisController = new IrisMultiMotorController(configFilePath);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
showMessageBox(QString::fromLocal8Bit("请连接马达!"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_multiAxisController->moveToThread(&m_motorThread);
|
||||
connect(&m_motorThread, SIGNAL(finished()), m_multiAxisController, SLOT(deleteLater()));
|
||||
connect(this, SIGNAL(rmoveSignal(int, double, double, int)), m_multiAxisController, SLOT(rmove(int, double, double, int)));
|
||||
connect(this, SIGNAL(move2LocSignal(int, double, double, int)), m_multiAxisController, SLOT(moveTo(int, double, double, int)));
|
||||
connect(this, SIGNAL(rangeMeasurementSignal(int, double, int)), m_multiAxisController, SLOT(rangeMeasurement(int, double, int)));
|
||||
connect(this, SIGNAL(zeroStartSignal(int)), m_multiAxisController, SLOT(zeroStart(int)));
|
||||
connect(this, SIGNAL(move2MaxLocSignal(int, double, int)), m_multiAxisController, SLOT(moveToMax(int, double, int)));
|
||||
connect(m_multiAxisController, SIGNAL(broadcastLocationSignal(std::vector<double>)), this, SLOT(display_x_loc(std::vector<double>)));
|
||||
connect(m_multiAxisController, SIGNAL(motorStopSignal(int, double)), this, SLOT(moveAfterAutoFocus(int, double)));
|
||||
connect(this, SIGNAL(testConnectivitySignal(int, int)), m_multiAxisController, SLOT(testConnectivity(int, int)));
|
||||
connect(m_multiAxisController, SIGNAL(broadcastConnectivity(std::vector<int>)), this, SLOT(display_motors_connectivity(std::vector<int>)));
|
||||
m_motorThread.start();
|
||||
emit testConnectivitySignal(0, 1000);
|
||||
|
||||
//归零
|
||||
//emit zeroStartSignal(0);
|
||||
|
||||
//自动调焦逻辑
|
||||
m_coordinator = new MotionCaptureCoordinator(m_multiAxisController, m_Imager);
|
||||
m_coordinator->moveToThread(&m_MotionCaptureCoordinatorThread);
|
||||
connect(&m_MotionCaptureCoordinatorThread, SIGNAL(finished()), m_coordinator, SLOT(deleteLater()));
|
||||
connect(this, SIGNAL(startStepMotionSignal(double, int, double, double)), m_coordinator, SLOT(startStepMotion(double, int, double, double)));
|
||||
connect(m_coordinator, SIGNAL(progressChanged(int)), this, SLOT(onAutoFocusProgress(int)));
|
||||
connect(m_coordinator, SIGNAL(sequenceComplete()), this, SLOT(onAutoFocusFinished()));
|
||||
m_MotionCaptureCoordinatorThread.start();
|
||||
|
||||
}
|
||||
|
||||
void focusWindow::display_motors_connectivity(std::vector<int> connectivity)
|
||||
{
|
||||
//std::cout << "-----------------------------------"<<connectivity.size()<< std::endl;
|
||||
if (connectivity[0])
|
||||
{
|
||||
m_xMotorConnectionStatus = true;
|
||||
|
||||
this->ui.motor_state_label->setStyleSheet(R"(
|
||||
QLabel
|
||||
{
|
||||
background-color: #08FACE;
|
||||
border-radius: 4px;
|
||||
}
|
||||
)");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_xMotorConnectionStatus = false;
|
||||
|
||||
this->ui.motor_state_label->setStyleSheet(R"(
|
||||
QLabel
|
||||
{
|
||||
background-color: red;
|
||||
border-radius: 4px;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
if (getMotorsConnectionStatus())
|
||||
{
|
||||
this->ui.connectMotor_btn->setText(QString::fromLocal8Bit("已连接"));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->ui.connectMotor_btn->setText(QString::fromLocal8Bit("重新连接"));
|
||||
}
|
||||
}
|
||||
|
||||
bool focusWindow::getMotorsConnectionStatus()
|
||||
{
|
||||
return m_xMotorConnectionStatus;
|
||||
}
|
||||
|
||||
void focusWindow::display_x_loc(std::vector<double> loc)
|
||||
{
|
||||
double tmp = round(loc[0] * 100) / 100;
|
||||
@ -342,7 +475,7 @@ void focusWindow::onAutoFocus()
|
||||
//获取马达最大位置
|
||||
std::vector<double> maxRangeLocations = m_multiAxisController->getMaxPos();
|
||||
double maxPos = maxRangeLocations[0];
|
||||
emit startStepMotion(m_dSpeed, m_iStepSize, 0, maxPos);
|
||||
emit startStepMotionSignal(m_dSpeed, m_iStepSize, 0, maxPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -516,30 +649,48 @@ void focusWindow::moveAfterAutoFocus(int motorID, double location)
|
||||
|
||||
std::cout << "\n已经到达位置:" << location << std::endl;
|
||||
|
||||
double tmp = abs(location - m_goodPos) / m_goodPos * 100;
|
||||
if (tmp < 5)
|
||||
double errorRate = getErrorRate(m_goodPos, location);
|
||||
if (errorRate < 5|| m_moveRetryCount > MAX_MOVE_RETRY)
|
||||
{
|
||||
m_isMoveAfterAutoFocus = false;
|
||||
m_moveRetryCount = 0;
|
||||
if (!m_isAutoFocusSuccess)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText(QString::fromLocal8Bit("纹理较弱,自动调焦效果不佳!请使用调焦纸进行自动调焦!"));
|
||||
msgBox.exec();
|
||||
qDebug() << "纹理较弱,自动调焦效果不佳!请使用调焦纸进行自动调焦!";
|
||||
//showMessageBox(QString::fromLocal8Bit("纹理较弱,自动调焦效果不佳!请使用调焦纸进行自动调焦!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText(QString::fromLocal8Bit("自动调焦成功!"));
|
||||
msgBox.exec();
|
||||
qDebug() << "自动调焦成功!";
|
||||
//showMessageBox(QString::fromLocal8Bit("自动调焦成功!"));
|
||||
}
|
||||
emit AutoFocusFinishedSignal(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveRetryCount++;
|
||||
qDebug() << "自动调焦后目标马达位置,重试次数:" << m_moveRetryCount;
|
||||
//移动马达到最佳位置
|
||||
emit move2LocSignal(0, (double)m_goodPos, m_dSpeed, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
double focusWindow::getErrorRate(double targetLoc, double actualLoc)
|
||||
{
|
||||
double targetLocTmp;
|
||||
if (targetLoc == 0)
|
||||
{
|
||||
targetLocTmp = 0.001;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetLocTmp = targetLoc;
|
||||
}
|
||||
double errorRate = abs(targetLoc - actualLoc) / targetLocTmp * 100;
|
||||
|
||||
return errorRate;
|
||||
}
|
||||
|
||||
void focusWindow::getGaussianInitParam(const std::vector<double>& pos, const std::vector<double>& index, double& a_init, double& mu_init, double& sigma_init, double& c_init)
|
||||
{
|
||||
auto minmax_element = std::minmax_element(index.begin(), index.end());
|
||||
@ -690,11 +841,15 @@ MotionCaptureCoordinator::MotionCaptureCoordinator(
|
||||
, m_currentPos(0)
|
||||
, m_endPos(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, &MotionCaptureCoordinator::zeroStart,
|
||||
m_motorCtrl, &IrisMultiMotorController::zeroStart);
|
||||
|
||||
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal,
|
||||
this, &MotionCaptureCoordinator::handlePositionReached);
|
||||
//connect(m_motorCtrl, &IrisMultiMotorController::moveFailed,
|
||||
@ -731,15 +886,37 @@ void MotionCaptureCoordinator::startStepMotion(double speed, int stepInterval, d
|
||||
m_speed = speed;
|
||||
m_iStepInterval = stepInterval;
|
||||
m_iStepIntervalRealTime = 1;
|
||||
m_currentPos = startPos;
|
||||
m_startPos = startPos;
|
||||
m_endPos = endPos;
|
||||
m_posInternal = (endPos - startPos) / stepInterval;
|
||||
|
||||
m_isRunning = true;
|
||||
m_isZeroing = true;
|
||||
|
||||
// 先执行归零操作
|
||||
emit zeroStart(0);
|
||||
qDebug() << "MotionCaptureCoordinator::startStepMotion: Zeroing started.";
|
||||
}
|
||||
|
||||
void MotionCaptureCoordinator::startMotionSequence()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
m_currentPos = m_startPos;
|
||||
m_isZeroing = false;
|
||||
qDebug() << "MotionCaptureCoordinator::startMotionSequence: Zeroing complete. Starting motion sequence.";
|
||||
|
||||
processNextPosition();
|
||||
}
|
||||
|
||||
void MotionCaptureCoordinator::handleZeroComplete(int motorID, double pos)
|
||||
{
|
||||
if (!m_isRunning || !m_isZeroing) return;
|
||||
|
||||
// 归零完成,开始分步运动
|
||||
startMotionSequence();
|
||||
}
|
||||
|
||||
void MotionCaptureCoordinator::stopStepMotion()
|
||||
{
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
@ -782,6 +959,13 @@ void MotionCaptureCoordinator::handlePositionReached(int motorID, double pos)
|
||||
{
|
||||
if (!m_isRunning) return;
|
||||
|
||||
// 如果正在等待归零完成,调用归零完成处理
|
||||
if (m_isZeroing)
|
||||
{
|
||||
handleZeroComplete(motorID, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
QMutexLocker locker(&m_dataMutex);
|
||||
|
||||
//验证马达运动位置是否到达指定位置
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include <QtSerialPort/QSerialPortInfo>
|
||||
#include <QDateTime>
|
||||
#include <QMutex>
|
||||
#include <QPointer>
|
||||
|
||||
#include "ui_FocusDialog.h"
|
||||
#include "AbstractPortMiscDefines.h"
|
||||
@ -69,14 +70,17 @@ signals:
|
||||
void errorOccurred(const QString& error);
|
||||
void moveTo(int, double, double, int);
|
||||
void getFocusIndexSobel();
|
||||
void zeroStart(int motorID);
|
||||
|
||||
private slots:
|
||||
void handlePositionReached(int motorID, double pos);
|
||||
void handleCaptureComplete(double index);
|
||||
void handleError(const QString& error);
|
||||
void handleZeroComplete(int motorID, double pos);
|
||||
|
||||
private:
|
||||
void processNextPosition();
|
||||
void startMotionSequence();
|
||||
|
||||
IrisMultiMotorController* m_motorCtrl;
|
||||
ImagerOperationBase* m_cameraCtrl;
|
||||
@ -85,6 +89,7 @@ private:
|
||||
|
||||
double m_posInternal;
|
||||
double m_currentPos;
|
||||
double m_startPos;
|
||||
double m_endPos;
|
||||
bool m_isRunning;
|
||||
double m_speed;
|
||||
@ -92,6 +97,7 @@ private:
|
||||
int m_iStepInterval;
|
||||
int m_iStepIntervalRealTime;
|
||||
int m_counter;
|
||||
bool m_isZeroing;
|
||||
};
|
||||
|
||||
class focusWindow:public QDialog
|
||||
@ -123,19 +129,28 @@ private:
|
||||
void disableBeforeConnect(bool disable);
|
||||
|
||||
QThread m_motorThread;
|
||||
IrisMultiMotorController* m_multiAxisController;
|
||||
QPointer<IrisMultiMotorController> m_multiAxisController;
|
||||
double m_dSpeed;
|
||||
|
||||
QThread m_MotionCaptureCoordinatorThread;
|
||||
MotionCaptureCoordinator* m_coordinator;
|
||||
QPointer<MotionCaptureCoordinator> m_coordinator;
|
||||
|
||||
int m_iStepSize;
|
||||
double m_goodPos;
|
||||
bool m_isAutoFocusSuccess;
|
||||
bool m_isMoveAfterAutoFocus = false;
|
||||
int m_moveRetryCount = 0;
|
||||
static constexpr int MAX_MOVE_RETRY = 3;
|
||||
void getGaussianInitParam(const std::vector<double>& pos, const std::vector<double>& index, double& a_init, double& mu_init, double& sigma_init, double& c_init);
|
||||
void gaussian_fit(const std::vector<double>& x_data, const std::vector<double>& y_data, double& a, double& mu, double& sigma, double& c);
|
||||
|
||||
bool m_xMotorConnectionStatus = false;
|
||||
bool getMotorsConnectionStatus();
|
||||
void connectMotor(bool isNotification);
|
||||
|
||||
void showMessageBox(QString msg, QString title = QString::fromLocal8Bit("提示"));
|
||||
|
||||
double getErrorRate(double targetLoc, double actualLoc);
|
||||
|
||||
public Q_SLOTS:
|
||||
void onConnectMotor();
|
||||
@ -158,6 +173,8 @@ public Q_SLOTS:
|
||||
|
||||
void onExit();
|
||||
|
||||
void display_motors_connectivity(std::vector<int> connectivity);
|
||||
|
||||
signals:
|
||||
void StartManualFocusSignal(int);//1:开始调焦;0:停止调焦;
|
||||
|
||||
@ -166,9 +183,12 @@ signals:
|
||||
void rmoveSignal(int, double, double, int);
|
||||
void rangeMeasurementSignal(int, double, int);
|
||||
void zeroStartSignal(int);
|
||||
void testConnectivitySignal(int, int);
|
||||
|
||||
void startStepMotion(double speed, int stepInterval = 100, double startPos = 0, double endPos = -1);
|
||||
void startStepMotionSignal(double speed, int stepInterval = 100, double startPos = 0, double endPos = -1);
|
||||
void closeSignal();
|
||||
|
||||
void AutoFocusFinishedSignal(int status);
|
||||
};
|
||||
|
||||
class WorkerThread2 : public QThread
|
||||
|
||||
@ -32,14 +32,6 @@ QSpinBox
|
||||
border: none;
|
||||
}
|
||||
|
||||
QTextEdit
|
||||
{
|
||||
font: 10pt "新宋体";
|
||||
background-color: #142D7F;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
QPushButton
|
||||
{
|
||||
/*width: 172px;
|
||||
@ -82,56 +74,7 @@ QPushButton:pressed
|
||||
QLabel {
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
QSlider::groove:horizontal {
|
||||
height: 10px;
|
||||
background: #1e2a44;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* 已滑过:渐变蓝 */
|
||||
QSlider::sub-page:horizontal {
|
||||
background: qlineargradient(
|
||||
x1:0, y1:0, x2:1, y2:0,
|
||||
stop:0 #1f4fff,
|
||||
stop:0.5 #2f6bff,
|
||||
stop:1 #5fa0ff
|
||||
);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* 未滑过 */
|
||||
QSlider::add-page:horizontal {
|
||||
height: 10px;
|
||||
background: #2a3550;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* ===== 滑块按钮 ===== */
|
||||
QSlider::handle:horizontal {
|
||||
width: 15px;
|
||||
height: 10px;
|
||||
|
||||
/* 蓝色实心 */
|
||||
background: #2f6bff;
|
||||
|
||||
/* 白色外圈 */
|
||||
border: 2px solid #ffffff;
|
||||
border-radius: 5px;
|
||||
|
||||
/* 垂直居中 */
|
||||
margin: -5px 0;
|
||||
}
|
||||
|
||||
/* 悬停 */
|
||||
QSlider::handle:horizontal:hover {
|
||||
background: #4d8dff;
|
||||
}
|
||||
|
||||
/* 按下 */
|
||||
QSlider::handle:horizontal:pressed {
|
||||
background: #1f4fff;
|
||||
}</string>
|
||||
</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,1,3">
|
||||
<item>
|
||||
@ -257,7 +200,57 @@ QSlider::handle:horizontal:pressed {
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTextEdit" name="status_textEdit"/>
|
||||
<widget class="QTextEdit" name="status_textEdit">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTextEdit
|
||||
{
|
||||
font: 10pt "新宋体";
|
||||
background-color: #142D7F;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
QScrollBar:vertical {
|
||||
background: #0E1C4C;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical {
|
||||
background: #4B60A6;
|
||||
border-radius: 6px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
QScrollBar:horizontal {
|
||||
background: #0E1C4C;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal {
|
||||
background: #4B60A6;
|
||||
border-radius: 6px;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
|
||||
width: 0px;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'新宋体'; font-size:10pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
Reference in New Issue
Block a user