2 Commits

Author SHA1 Message Date
392bc98ebf add,计划采集21,上海农科院3D植物表型:
1、实现3种深度计算算法;
2026-08-19 17:37:08 +08:00
0866b9cd56 add,计划采集20,上海农科院3D植物表型:
1、新增任务类型AutoFocus:执行自动调焦过程;
2026-08-18 14:36:41 +08:00
14 changed files with 512 additions and 153 deletions

View File

@ -305,10 +305,14 @@ void DepthCameraOperation::OpenDepthCamera_getDepthValue()
auto vid = devInfo->getVid(); auto vid = devInfo->getVid();
config->enableVideoStream(OB_STREAM_DEPTH, 640, 480, 15, OB_FORMAT_Y16); 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); config->setFrameAggregateOutputMode(OB_FRAME_AGGREGATE_OUTPUT_ALL_TYPE_FRAME_REQUIRE);
m_pipe->enableFrameSync(); m_pipe->enableFrameSync();
// Create a format converter filter.
auto formatConverter = std::make_shared<ob::FormatConvertFilter>();
m_pipe->start(config); m_pipe->start(config);
// Drop several frames // Drop several frames
@ -322,7 +326,10 @@ void DepthCameraOperation::OpenDepthCamera_getDepthValue()
record = true; record = true;
QString fileNamePrefix = AppSettings::instance().depthCameraDataFolder() + QDir::separator() + "Gemini336L"; QString fileNamePrefix = AppSettings::instance().depthCameraDataFolder() + QDir::separator() + "Gemini336L";
double depthValue_all = 0.0; // 增量平均所需的变量
cv::Mat avgRgbMat, avgDepthMat;
int avgFrameCount = 0;
for (size_t i = 0; i < m_averageNumberOfTimes; i++) for (size_t i = 0; i < m_averageNumberOfTimes; i++)
{ {
if(frameIndex==0) if(frameIndex==0)
@ -342,25 +349,56 @@ void DepthCameraOperation::OpenDepthCamera_getDepthValue()
// 彩色和深度图像 // 彩色和深度图像
auto depthFrame = frameSet->getFrame(OB_FRAME_DEPTH)->as<ob::DepthFrame>(); 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()); //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()); cv::Mat depthMat(depthFrame->height(), depthFrame->width(), CV_16UC1, depthFrame->data());
//裁剪边缘区域 // 增量平均计算
int cropRows = static_cast<int>(depthMat.rows * (1 - m_percentageOfEffectiveArea) / 2); if (avgFrameCount == 0)
int cropCols = static_cast<int>(depthMat.cols * (1 - m_percentageOfEffectiveArea) / 2); {
cv::Rect roi(cropCols, cropRows, avgRgbMat = cv::Mat::zeros(rgbMat.size(), CV_32FC3);
depthMat.cols - 2 * cropCols, avgDepthMat = cv::Mat::zeros(depthMat.size(), CV_32F);
depthMat.rows - 2 * cropRows); }
cv::Mat depthRoi = depthMat(roi); 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::Scalar meanDepth = cv::mean(depthRoi);
double depthValue = meanDepth[0] / 1000.0; // 转换为米
depthValue_all += depthValue;
std::cout << "Depth value: " << depthValue << " m, accumulated: " << depthValue_all << std::endl;
cv::Mat depthMat8U; cv::Mat depthMat8U;
depthMat.convertTo(depthMat8U, CV_8UC1, 255.0 / 4096.0); depthMat.convertTo(depthMat8U, CV_8UC1, 255.0 / 4096.0);
@ -375,13 +413,51 @@ void DepthCameraOperation::OpenDepthCamera_getDepthValue()
frameIndex++; 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);
}
}
//计算平均深度值 //计算平均深度值
double depthValue_avg = depthValue_all / m_averageNumberOfTimes; std::cout << "Depth value: " << depthValue << " m" << std::endl;
std::cout << "Average depth value: " << depthValue_avg << " m" << std::endl; emit DepthValueSignal(depthValue);
emit DepthValueSignal(depthValue_avg);
m_pipe->stop();
delete m_pipe; delete m_pipe;
m_pipe = nullptr; m_pipe = nullptr;
@ -389,6 +465,97 @@ void DepthCameraOperation::OpenDepthCamera_getDepthValue()
record = false; 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_) void DepthCameraOperation::saveDepthFrame(const std::shared_ptr<ob::DepthFrame> depthFrame, const uint32_t frameIndex, std::string fileNamePrefix_)
{ {
std::vector<int> params; std::vector<int> params;

View File

@ -5,8 +5,10 @@
#include <QNetworkReply> #include <QNetworkReply>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QImage> #include <QImage>
#include <Qthread> #include <QThread>
#include <QDir> #include <QDir>
#include <QCoreApplication>
#include <QDateTime>
//#include <QLabel> //#include <QLabel>
#include <QFileDialog> #include <QFileDialog>
@ -35,8 +37,10 @@ public:
void setCaptureInterval(int captureIntervalSeconds); void setCaptureInterval(int captureIntervalSeconds);
void setDepthAlgorithm(int depthAlgorithm) { m_depthAlgorithm = depthAlgorithm; }
void setAverageNumberOfTimes(double averageNumberOfTimes) { m_averageNumberOfTimes = averageNumberOfTimes; } void setAverageNumberOfTimes(double averageNumberOfTimes) { m_averageNumberOfTimes = averageNumberOfTimes; }
void setPercentageOfEffectiveArea(double percentageOfEffectiveArea) { m_percentageOfEffectiveArea = percentageOfEffectiveArea; } void setPercentageOfEffectiveArea(double percentageOfEffectiveArea) { m_percentageOfEffectiveArea = percentageOfEffectiveArea; }
void setDepthRangePercentage(double depthRangePercentage) { m_depthRangePercentage = depthRangePercentage; }
private: private:
ob::Pipeline* m_pipe; ob::Pipeline* m_pipe;
@ -53,8 +57,16 @@ private:
int m_captureIntervalMilliseconds; int m_captureIntervalMilliseconds;
int m_depthAlgorithm;
double m_averageNumberOfTimes; double m_averageNumberOfTimes;
double m_percentageOfEffectiveArea; 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: public slots:
void OpenDepthCamera(); void OpenDepthCamera();
@ -101,5 +113,4 @@ signals:
private: private:
Ui::DepthCameraClass ui; Ui::DepthCameraClass ui;
QThread* m_DepthCameraThread; QThread* m_DepthCameraThread;
}; };

View File

@ -682,6 +682,9 @@ void HPPA::initTimedDataCollection()
connect(m_omc_LiftingPlatform, &OneMotorControl_LiftingPlatform::sequenceComplete, m_tdc, &TimedDataCollection::subTaskCompleted); 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_omc_LiftingPlatform, &OneMotorControl_LiftingPlatform::back2OriginSignal_TimedDataCollection, m_tdc, &TimedDataCollection::onBack2Origin);
//自动调焦
connect(m_tdc, &TimedDataCollection::AutoFocusSignals, this, &HPPA::onAutoFocus_TimedDataCollection);
m_tdc->show(); m_tdc->show();
} }
@ -782,7 +785,8 @@ void HPPA::onStartTimedDataCollection(int camType)
void HPPA::onObtainTargetDepthInformation(SubTask subTaskParams) void HPPA::onObtainTargetDepthInformation(SubTask subTaskParams)
{ {
m_tmc->run4_ObtainTargetDepthInfo(m_depthCameraWindow, subTaskParams.depthType, subTaskParams.depthInfoX, subTaskParams.depthInfoY, subTaskParams.averageNumberOfTimes, subTaskParams.percentageOfEffectiveArea); 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) void HPPA::onLiftingPlatform(SubTask subTaskParams)
@ -790,6 +794,13 @@ void HPPA::onLiftingPlatform(SubTask subTaskParams)
m_omc_LiftingPlatform->run(); 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() void HPPA::onTimedDataCollection()
{ {
QAction* checkedScenario = m_ScenarioActionGroup->checkedAction(); QAction* checkedScenario = m_ScenarioActionGroup->checkedAction();

View File

@ -452,6 +452,7 @@ public Q_SLOTS:
void onStartTimedDataCollection(int camType); void onStartTimedDataCollection(int camType);
void onObtainTargetDepthInformation(SubTask subTaskParams); void onObtainTargetDepthInformation(SubTask subTaskParams);
void onLiftingPlatform(SubTask subTaskParams); void onLiftingPlatform(SubTask subTaskParams);
void onAutoFocus_TimedDataCollection(SubTask subTaskParams);
void onStretchedImageReady(int fileNumber, const QString& filePath, QPixmap& pixmap); void onStretchedImageReady(int fileNumber, const QString& filePath, QPixmap& pixmap);
void onStretchProcessingError(int fileNumber, const QString& filePath, const QString& error); void onStretchProcessingError(int fileNumber, const QString& filePath, const QString& error);

View File

@ -114,6 +114,7 @@ void TimedDataCollection::setupConnections()
connect(m_scheduler, &TaskScheduler::ObtainingDepthInformationSignals, this, &TimedDataCollection::ObtainingDepthInformationSignals); connect(m_scheduler, &TaskScheduler::ObtainingDepthInformationSignals, this, &TimedDataCollection::ObtainingDepthInformationSignals);
connect(m_scheduler, &TaskScheduler::LiftingPlatformSignals, this, &TimedDataCollection::LiftingPlatformSignals); connect(m_scheduler, &TaskScheduler::LiftingPlatformSignals, this, &TimedDataCollection::LiftingPlatformSignals);
connect(m_scheduler, &TaskScheduler::AutoFocusSignals, this, &TimedDataCollection::AutoFocusSignals);
connect(m_scheduler, &TaskScheduler::switchHalogenLampSignal, connect(m_scheduler, &TaskScheduler::switchHalogenLampSignal,
this, &TimedDataCollection::switchHalogenLampSignal); this, &TimedDataCollection::switchHalogenLampSignal);
@ -419,6 +420,7 @@ void TimedDataCollection::readTimedTaskFromFile(const QString& filePath)
double totalEstimatedMinutes = 0.0; double totalEstimatedMinutes = 0.0;
for (int j = 0; j < loadedTasks[i].subTasks.size(); ++j) 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; QString pathLineFilePath = loadedTasks[i].subTasks[j].pathLineFilePath;
if (!pathLineFilePath.isEmpty()) if (!pathLineFilePath.isEmpty())
{ {
@ -429,6 +431,7 @@ void TimedDataCollection::readTimedTaskFromFile(const QString& filePath)
} }
double slrTimeMinute = 135 / 60; double slrTimeMinute = 135 / 60;
loadedTasks[i].estimatedDurationMinutes = totalEstimatedMinutes + loadedTasks[i].HalogenLampPreheatingTime_Minute + slrTimeMinute; loadedTasks[i].estimatedDurationMinutes = totalEstimatedMinutes + loadedTasks[i].HalogenLampPreheatingTime_Minute + slrTimeMinute;
loadedTasks[i].durationMinutes = 0.0; // 初始化实际耗时为0
} }
m_taskModel->setTasks(loadedTasks); m_taskModel->setTasks(loadedTasks);

View File

@ -54,6 +54,7 @@ Q_SIGNALS:
void ObtainingDepthInformationSignals(SubTask info); void ObtainingDepthInformationSignals(SubTask info);
void LiftingPlatformSignals(SubTask info); void LiftingPlatformSignals(SubTask info);
void AutoFocusSignals(SubTask info);
void switchHalogenLampSignal(int state); void switchHalogenLampSignal(int state);
void switchD65LampSignal(int state); void switchD65LampSignal(int state);

View File

@ -121,6 +121,23 @@ SubTaskType TimedDataCollectionDataStructuresReaderWriter::stringToSubTaskType(c
return SubTaskType::SingleLensReflex; 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序列化 ==================== // ==================== SubTask序列化 ====================
QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const SubTask& subTask) QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const SubTask& subTask)
@ -138,15 +155,18 @@ QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const S
obj["defaultRenderBand"] = subTask.defaultRenderBand; obj["defaultRenderBand"] = subTask.defaultRenderBand;
obj["captureIntervalSeconds"] = subTask.captureIntervalSeconds; obj["captureIntervalSeconds"] = subTask.captureIntervalSeconds;
obj["autoFocusHyperImagerType"] = hyperImagerTypeToString(subTask.autoFocusHyperImagerType);
obj["autoFocusMotorConfigFilePath"] = subTask.autoFocusMotorConfigFilePath; obj["autoFocusMotorConfigFilePath"] = subTask.autoFocusMotorConfigFilePath;
obj["autoFocusX"] = subTask.autoFocusX; obj["autoFocusX"] = subTask.autoFocusX;
obj["autoFocusY"] = subTask.autoFocusY; obj["autoFocusY"] = subTask.autoFocusY;
obj["depthAlgorithm"] = subTask.depthAlgorithm;
obj["depthInfoX"] = subTask.depthInfoX; obj["depthInfoX"] = subTask.depthInfoX;
obj["depthInfoY"] = subTask.depthInfoY; obj["depthInfoY"] = subTask.depthInfoY;
obj["averageNumberOfTimes"] = subTask.averageNumberOfTimes; obj["averageNumberOfTimes"] = subTask.averageNumberOfTimes;
obj["percentageOfEffectiveArea"] = subTask.percentageOfEffectiveArea; obj["percentageOfEffectiveArea"] = subTask.percentageOfEffectiveArea;
obj["depthType"] = subTask.depthType; obj["depthType"] = subTask.depthType;
obj["depthRangePercentage"] = subTask.depthRangePercentage;
return obj; return obj;
} }
@ -164,15 +184,18 @@ bool TimedDataCollectionDataStructuresReaderWriter::jsonToSubTask(const QJsonObj
subTask.defaultRenderBand = json["defaultRenderBand"].toInt(); subTask.defaultRenderBand = json["defaultRenderBand"].toInt();
subTask.captureIntervalSeconds = json["captureIntervalSeconds"].toDouble(); subTask.captureIntervalSeconds = json["captureIntervalSeconds"].toDouble();
subTask.autoFocusHyperImagerType = stringToHyperImagerType(json["autoFocusHyperImagerType"].toString());
subTask.autoFocusMotorConfigFilePath = json["autoFocusMotorConfigFilePath"].toString(); subTask.autoFocusMotorConfigFilePath = json["autoFocusMotorConfigFilePath"].toString();
subTask.autoFocusX = json["autoFocusX"].toDouble(); subTask.autoFocusX = json["autoFocusX"].toDouble();
subTask.autoFocusY = json["autoFocusY"].toDouble(); subTask.autoFocusY = json["autoFocusY"].toDouble();
subTask.depthAlgorithm = json["depthAlgorithm"].toInt();
subTask.depthInfoX = json["depthInfoX"].toDouble(); subTask.depthInfoX = json["depthInfoX"].toDouble();
subTask.depthInfoY = json["depthInfoY"].toDouble(); subTask.depthInfoY = json["depthInfoY"].toDouble();
subTask.averageNumberOfTimes = json["averageNumberOfTimes"].toInt(); subTask.averageNumberOfTimes = json["averageNumberOfTimes"].toInt();
subTask.percentageOfEffectiveArea = json["percentageOfEffectiveArea"].toDouble(); subTask.percentageOfEffectiveArea = json["percentageOfEffectiveArea"].toDouble();
subTask.depthType = json["depthType"].toInt(); subTask.depthType = json["depthType"].toInt();
subTask.depthRangePercentage = json["depthRangePercentage"].toDouble();
return true; return true;
} }
@ -475,9 +498,27 @@ void TaskExecutor::executeNextSubTask()
} }
case SubTaskType::AutoFocus: case SubTaskType::AutoFocus:
{ {
//先判断高光谱相机类型,然后发送相机参数hyperCamParm连接相机 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; break;
} }
case SubTaskType::LiftingPlatform: case SubTaskType::LiftingPlatform:
@ -553,6 +594,12 @@ void TaskExecutor::emitRecordSignal()
emit startRecordSignal(m_camType); emit startRecordSignal(m_camType);
} }
void TaskExecutor::emitAutoFocusSignal()
{
SubTask& subTask = m_task.subTasks[m_currentSubTaskIndex];
emit AutoFocusSignals(subTask);
}
// ==================== TaskScheduler 实现 ==================== // ==================== TaskScheduler 实现 ====================
TaskScheduler::TaskScheduler(QObject* parent) TaskScheduler::TaskScheduler(QObject* parent)
@ -729,6 +776,7 @@ void TaskScheduler::executeTask(TimedTask& task)
connect(m_currentExecutor, &TaskExecutor::ObtainingDepthInformationSignals, this, &TaskScheduler::ObtainingDepthInformationSignals); connect(m_currentExecutor, &TaskExecutor::ObtainingDepthInformationSignals, this, &TaskScheduler::ObtainingDepthInformationSignals);
connect(m_currentExecutor, &TaskExecutor::LiftingPlatformSignals, this, &TaskScheduler::LiftingPlatformSignals); 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::switchHalogenLampSignal, this, &TaskScheduler::switchHalogenLampSignal);
connect(m_currentExecutor, &TaskExecutor::switchD65LampSignal, this, &TaskScheduler::switchD65LampSignal); connect(m_currentExecutor, &TaskExecutor::switchD65LampSignal, this, &TaskScheduler::switchD65LampSignal);

View File

@ -30,6 +30,10 @@ enum class SubTaskType {
AutoFocus, // 自动对焦 AutoFocus, // 自动对焦
LiftingPlatform // 升降平台 LiftingPlatform // 升降平台
}; };
enum class HyperImagerType {
Pika_L,
Pika_NIR
};
// ==================== 统一子任务封装 ==================== // ==================== 统一子任务封装 ====================
@ -51,13 +55,16 @@ struct SubTask {
int captureIntervalSeconds = 5; // 单反/深度相机用 int captureIntervalSeconds = 5; // 单反/深度相机用
//任务ObtainingDepthInformation所需的x和y坐标 //任务ObtainingDepthInformation所需的x和y坐标
int depthAlgorithm = 0;//0:深度图像的范围(percentageOfEffectiveArea)平均,1:深度范围(depthRangePercentage)的百分比,2:通过彩色图像分割植被区域的深度图像,然后平均
int depthType = 0;//0表示植被深度,1表示白板/调焦版深度 int depthType = 0;//0表示植被深度,1表示白板/调焦版深度
double depthInfoX = 0.0; double depthInfoX = 0.0;
double depthInfoY = 0.0; double depthInfoY = 0.0;
int averageNumberOfTimes = 1; //任务ObtainingDepthInformation所需的平均次数 int averageNumberOfTimes = 1; //任务ObtainingDepthInformation所需的平均次数
double percentageOfEffectiveArea = 50.0; //深度图像的有效范围百分比 double percentageOfEffectiveArea = 50.0; //深度图像的有效范围百分比
double depthRangePercentage = 80.0; //深度范围的百分比
//高光谱自动调焦 //高光谱自动调焦
HyperImagerType autoFocusHyperImagerType;//取值范围:L、NIR
QString autoFocusMotorConfigFilePath;//马达配置文件 QString autoFocusMotorConfigFilePath;//马达配置文件
double autoFocusX = 0.0; double autoFocusX = 0.0;
double autoFocusY = 0.0; double autoFocusY = 0.0;
@ -124,6 +131,9 @@ private:
static QString subTaskTypeToString(SubTaskType type); static QString subTaskTypeToString(SubTaskType type);
static SubTaskType stringToSubTaskType(const QString& str); static SubTaskType stringToSubTaskType(const QString& str);
static QString hyperImagerTypeToString(HyperImagerType type);
static HyperImagerType stringToHyperImagerType(const QString& str);
}; };
// ==================== 任务执行器 ==================== // ==================== 任务执行器 ====================
@ -168,6 +178,7 @@ signals:
void ObtainingDepthInformationSignals(SubTask info); void ObtainingDepthInformationSignals(SubTask info);
void LiftingPlatformSignals(SubTask info); void LiftingPlatformSignals(SubTask info);
void AutoFocusSignals(SubTask info);
void switchHalogenLampSignal(int state); void switchHalogenLampSignal(int state);
void switchD65LampSignal(int state); void switchD65LampSignal(int state);
@ -179,6 +190,7 @@ public slots:
void onError(const QString& error); void onError(const QString& error);
void emitRecordSignal(); void emitRecordSignal();
void emitAutoFocusSignal();
private: private:
QString m_currentFolder; QString m_currentFolder;
@ -240,6 +252,7 @@ signals:
void ObtainingDepthInformationSignals(SubTask info); void ObtainingDepthInformationSignals(SubTask info);
void LiftingPlatformSignals(SubTask info); void LiftingPlatformSignals(SubTask info);
void AutoFocusSignals(SubTask info);
void switchHalogenLampSignal(int state); void switchHalogenLampSignal(int state);
void switchD65LampSignal(int state); void switchD65LampSignal(int state);

View File

@ -210,12 +210,14 @@ void TwoMotorControl::onBack2Origin2()
emit back2OriginSignal_TimedDataCollection(); emit back2OriginSignal_TimedDataCollection();
} }
void TwoMotorControl::run4_ObtainTargetDepthInfo(DepthCameraWindow* window, int depthType, double depthInfoX, double depthInfoY, int averageNumberOfTimes, double percentageOfEffectiveArea) void TwoMotorControl::run4_ObtainTargetDepthInfo(DepthCameraWindow* window, double depthAlgorithm,int depthType, double depthInfoX, double depthInfoY, int averageNumberOfTimes, double percentageOfEffectiveArea, double depthRangePercentage)
{ {
m_depthType = depthType; m_depthType = depthType;
window->m_DepthCameraOperation->setDepthAlgorithm(depthAlgorithm);
window->m_DepthCameraOperation->setAverageNumberOfTimes(averageNumberOfTimes); window->m_DepthCameraOperation->setAverageNumberOfTimes(averageNumberOfTimes);
window->m_DepthCameraOperation->setPercentageOfEffectiveArea(percentageOfEffectiveArea); window->m_DepthCameraOperation->setPercentageOfEffectiveArea(percentageOfEffectiveArea);
window->m_DepthCameraOperation->setDepthRangePercentage(depthRangePercentage);
m_ObtainTargetDepthInfoCoordinator = new TwoMotor1PosCoordinator(m_multiAxisController); m_ObtainTargetDepthInfoCoordinator = new TwoMotor1PosCoordinator(m_multiAxisController);
connect(m_ObtainTargetDepthInfoCoordinator, &TwoMotor1PosCoordinator::ArrivalSignal, window, &DepthCameraWindow::OpenDepthCamera_getDepthValue); connect(m_ObtainTargetDepthInfoCoordinator, &TwoMotor1PosCoordinator::ArrivalSignal, window, &DepthCameraWindow::OpenDepthCamera_getDepthValue);
@ -232,6 +234,25 @@ void TwoMotorControl::run4_ObtainTargetDepthInfo(DepthCameraWindow* window, int
m_ObtainTargetDepthInfoCoordinator->moveToTarget(depthInfoX, depthInfoY, xmotor_move_speed, ymotor_move_speed); 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) void TwoMotorControl::saveDepthValue(double depthValue)
{ {
if (m_depthType == 0)//0表示植被深度,1表示白板/调焦版深度 if (m_depthType == 0)//0表示植被深度,1表示白板/调焦版深度
@ -251,6 +272,16 @@ void TwoMotorControl::onBack2Origin3()
emit back2OriginSignal_TimedDataCollection(); emit back2OriginSignal_TimedDataCollection();
} }
void TwoMotorControl::onBack2Origin4()
{
m_focusWindow->deleteLater();
m_focusWindow = nullptr;
m_autoFocusCoordinator->deleteLater();
m_autoFocusCoordinator = nullptr;
emit back2OriginSignal_TimedDataCollection();
}
void TwoMotorControl::run() void TwoMotorControl::run()
{ {
if (getState()) if (getState())

View File

@ -17,6 +17,8 @@
#include "DepthValueLogger.h" #include "DepthValueLogger.h"
#include "focusWindow.h"
#define PI 3.1415926 #define PI 3.1415926
class TwoMotorControl : public QDialog, public MotorWindowBase class TwoMotorControl : public QDialog, public MotorWindowBase
@ -84,10 +86,12 @@ public Q_SLOTS:
void run2(SingleLensReflexCameraWindow* w); void run2(SingleLensReflexCameraWindow* w);
void run3(DepthCameraWindow* window); void run3(DepthCameraWindow* window);
void run4_ObtainTargetDepthInfo(DepthCameraWindow* window, int depthType, double depthInfoX, double depthInfoY, int averageNumberOfTimes, double percentageOfEffectiveArea); 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 onBack2Origin2();
void saveDepthValue(double depthValue); void saveDepthValue(double depthValue);
void onBack2Origin3(); void onBack2Origin3();
void onBack2Origin4();
void stop_record(); void stop_record();
@ -117,6 +121,7 @@ private:
TwoMotionCaptureCoordinator* m_coordinator = nullptr; TwoMotionCaptureCoordinator* m_coordinator = nullptr;
TwoMotionCaptureCoordinator* m_coordinator_TimedDataCollection = nullptr; TwoMotionCaptureCoordinator* m_coordinator_TimedDataCollection = nullptr;
TwoMotor1PosCoordinator* m_ObtainTargetDepthInfoCoordinator = nullptr; TwoMotor1PosCoordinator* m_ObtainTargetDepthInfoCoordinator = nullptr;
TwoMotor1PosCoordinator* m_autoFocusCoordinator = nullptr;
DarkAndWhiteCaptureCoordinator* m_darkCaptureCoordinator = nullptr; DarkAndWhiteCaptureCoordinator* m_darkCaptureCoordinator = nullptr;
DarkAndWhiteCaptureCoordinator* m_whiteCaptureCoordinator = nullptr; DarkAndWhiteCaptureCoordinator* m_whiteCaptureCoordinator = nullptr;
@ -125,4 +130,6 @@ private:
IrisMultiMotorController* m_multiAxisController = nullptr; IrisMultiMotorController* m_multiAxisController = nullptr;
int m_depthType; int m_depthType;
focusWindow* m_focusWindow = nullptr;
}; };

View File

@ -288,7 +288,7 @@ QPushButton:pressed
}</string> }</string>
</property> </property>
<property name="text"> <property name="text">
<string>版本:3.1.2</string> <string>版本:3.1.3</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -299,7 +299,7 @@ void focusWindow::connectMotor(bool isNotification)//需要修改这个函数
if (m_coordinator) if (m_coordinator)
{ {
disconnect(&m_MotionCaptureCoordinatorThread, SIGNAL(finished()), m_coordinator, SLOT(deleteLater())); disconnect(&m_MotionCaptureCoordinatorThread, SIGNAL(finished()), m_coordinator, SLOT(deleteLater()));
disconnect(this, SIGNAL(startStepMotion(double, int, double, double)), m_coordinator, SLOT(startStepMotion(double, int, double, double))); 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(progressChanged(int)), this, SLOT(onAutoFocusProgress(int)));
disconnect(m_coordinator, SIGNAL(sequenceComplete()), this, SLOT(onAutoFocusFinished())); disconnect(m_coordinator, SIGNAL(sequenceComplete()), this, SLOT(onAutoFocusFinished()));
@ -343,7 +343,7 @@ void focusWindow::connectMotor(bool isNotification)//需要修改这个函数
m_coordinator = new MotionCaptureCoordinator(m_multiAxisController, m_Imager); m_coordinator = new MotionCaptureCoordinator(m_multiAxisController, m_Imager);
m_coordinator->moveToThread(&m_MotionCaptureCoordinatorThread); m_coordinator->moveToThread(&m_MotionCaptureCoordinatorThread);
connect(&m_MotionCaptureCoordinatorThread, SIGNAL(finished()), m_coordinator, SLOT(deleteLater())); 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(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(progressChanged(int)), this, SLOT(onAutoFocusProgress(int)));
connect(m_coordinator, SIGNAL(sequenceComplete()), this, SLOT(onAutoFocusFinished())); connect(m_coordinator, SIGNAL(sequenceComplete()), this, SLOT(onAutoFocusFinished()));
m_MotionCaptureCoordinatorThread.start(); m_MotionCaptureCoordinatorThread.start();
@ -475,7 +475,7 @@ void focusWindow::onAutoFocus()
//获取马达最大位置 //获取马达最大位置
std::vector<double> maxRangeLocations = m_multiAxisController->getMaxPos(); std::vector<double> maxRangeLocations = m_multiAxisController->getMaxPos();
double maxPos = maxRangeLocations[0]; double maxPos = maxRangeLocations[0];
emit startStepMotion(m_dSpeed, m_iStepSize, 0, maxPos); emit startStepMotionSignal(m_dSpeed, m_iStepSize, 0, maxPos);
} }
else else
{ {
@ -649,26 +649,48 @@ void focusWindow::moveAfterAutoFocus(int motorID, double location)
std::cout << "\n已经到达位置:" << location << std::endl; std::cout << "\n已经到达位置:" << location << std::endl;
double tmp = abs(location - m_goodPos) / m_goodPos * 100; double errorRate = getErrorRate(m_goodPos, location);
if (tmp < 5 || m_goodPos == 0) if (errorRate < 5|| m_moveRetryCount > MAX_MOVE_RETRY)
{ {
m_isMoveAfterAutoFocus = false; m_isMoveAfterAutoFocus = false;
m_moveRetryCount = 0;
if (!m_isAutoFocusSuccess) if (!m_isAutoFocusSuccess)
{ {
showMessageBox(QString::fromLocal8Bit("纹理较弱,自动调焦效果不佳!请使用调焦纸进行自动调焦!")); qDebug() << "纹理较弱,自动调焦效果不佳!请使用调焦纸进行自动调焦!";
//showMessageBox(QString::fromLocal8Bit("纹理较弱,自动调焦效果不佳!请使用调焦纸进行自动调焦!"));
} }
else else
{ {
showMessageBox(QString::fromLocal8Bit("自动调焦成功!")); qDebug() << "自动调焦成功!";
//showMessageBox(QString::fromLocal8Bit("自动调焦成功!"));
} }
emit AutoFocusFinishedSignal(0);
} }
else else
{ {
m_moveRetryCount++;
qDebug() << "自动调焦后目标马达位置,重试次数:" << m_moveRetryCount;
//移动马达到最佳位置 //移动马达到最佳位置
emit move2LocSignal(0, (double)m_goodPos, m_dSpeed, 1000); 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) 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()); auto minmax_element = std::minmax_element(index.begin(), index.end());
@ -819,11 +841,15 @@ MotionCaptureCoordinator::MotionCaptureCoordinator(
, m_currentPos(0) , m_currentPos(0)
, m_endPos(0) , m_endPos(0)
, m_isRunning(false) , m_isRunning(false)
, m_isZeroing(false)
{ {
//这些信号槽是按照逻辑顺序的 //这些信号槽是按照逻辑顺序的
connect(this, SIGNAL(moveTo(int, double, double, int)), connect(this, SIGNAL(moveTo(int, double, double, int)),
m_motorCtrl, SLOT(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, connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal,
this, &MotionCaptureCoordinator::handlePositionReached); this, &MotionCaptureCoordinator::handlePositionReached);
//connect(m_motorCtrl, &IrisMultiMotorController::moveFailed, //connect(m_motorCtrl, &IrisMultiMotorController::moveFailed,
@ -860,15 +886,37 @@ void MotionCaptureCoordinator::startStepMotion(double speed, int stepInterval, d
m_speed = speed; m_speed = speed;
m_iStepInterval = stepInterval; m_iStepInterval = stepInterval;
m_iStepIntervalRealTime = 1; m_iStepIntervalRealTime = 1;
m_currentPos = startPos; m_startPos = startPos;
m_endPos = endPos; m_endPos = endPos;
m_posInternal = (endPos - startPos) / stepInterval; m_posInternal = (endPos - startPos) / stepInterval;
m_isRunning = true; 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(); processNextPosition();
} }
void MotionCaptureCoordinator::handleZeroComplete(int motorID, double pos)
{
if (!m_isRunning || !m_isZeroing) return;
// 归零完成,开始分步运动
startMotionSequence();
}
void MotionCaptureCoordinator::stopStepMotion() void MotionCaptureCoordinator::stopStepMotion()
{ {
QMutexLocker locker(&m_dataMutex); QMutexLocker locker(&m_dataMutex);
@ -911,6 +959,13 @@ void MotionCaptureCoordinator::handlePositionReached(int motorID, double pos)
{ {
if (!m_isRunning) return; if (!m_isRunning) return;
// 如果正在等待归零完成,调用归零完成处理
if (m_isZeroing)
{
handleZeroComplete(motorID, pos);
return;
}
QMutexLocker locker(&m_dataMutex); QMutexLocker locker(&m_dataMutex);
//验证马达运动位置是否到达指定位置 //验证马达运动位置是否到达指定位置

View File

@ -70,14 +70,17 @@ signals:
void errorOccurred(const QString& error); void errorOccurred(const QString& error);
void moveTo(int, double, double, int); void moveTo(int, double, double, int);
void getFocusIndexSobel(); void getFocusIndexSobel();
void zeroStart(int motorID);
private slots: private slots:
void handlePositionReached(int motorID, double pos); void handlePositionReached(int motorID, double pos);
void handleCaptureComplete(double index); void handleCaptureComplete(double index);
void handleError(const QString& error); void handleError(const QString& error);
void handleZeroComplete(int motorID, double pos);
private: private:
void processNextPosition(); void processNextPosition();
void startMotionSequence();
IrisMultiMotorController* m_motorCtrl; IrisMultiMotorController* m_motorCtrl;
ImagerOperationBase* m_cameraCtrl; ImagerOperationBase* m_cameraCtrl;
@ -86,6 +89,7 @@ private:
double m_posInternal; double m_posInternal;
double m_currentPos; double m_currentPos;
double m_startPos;
double m_endPos; double m_endPos;
bool m_isRunning; bool m_isRunning;
double m_speed; double m_speed;
@ -93,6 +97,7 @@ private:
int m_iStepInterval; int m_iStepInterval;
int m_iStepIntervalRealTime; int m_iStepIntervalRealTime;
int m_counter; int m_counter;
bool m_isZeroing;
}; };
class focusWindow:public QDialog class focusWindow:public QDialog
@ -134,6 +139,8 @@ private:
double m_goodPos; double m_goodPos;
bool m_isAutoFocusSuccess; bool m_isAutoFocusSuccess;
bool m_isMoveAfterAutoFocus = false; 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 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); void gaussian_fit(const std::vector<double>& x_data, const std::vector<double>& y_data, double& a, double& mu, double& sigma, double& c);
@ -143,6 +150,8 @@ private:
void showMessageBox(QString msg, QString title = QString::fromLocal8Bit("提示")); void showMessageBox(QString msg, QString title = QString::fromLocal8Bit("提示"));
double getErrorRate(double targetLoc, double actualLoc);
public Q_SLOTS: public Q_SLOTS:
void onConnectMotor(); void onConnectMotor();
void onMove2MotorLogicZero(); void onMove2MotorLogicZero();
@ -176,8 +185,10 @@ signals:
void zeroStartSignal(int); void zeroStartSignal(int);
void testConnectivitySignal(int, 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 closeSignal();
void AutoFocusFinishedSignal(int status);
}; };
class WorkerThread2 : public QThread class WorkerThread2 : public QThread