轮眉检测多相机并行扫描

This commit is contained in:
杰仔 2026-05-17 19:00:47 +08:00
parent 3eea68772b
commit 23269cda03
6 changed files with 101 additions and 15 deletions

View File

@ -180,6 +180,9 @@ private:
// TCP检测触发回调 // TCP检测触发回调
bool onTCPDetectionTriggered(int param); bool onTCPDetectionTriggered(int param);
// 启动下一个待扫描相机TCP顺序循环
void startNextTCPCamera();
// 发送TCP测量结果 // 发送TCP测量结果
void sendTCPMeasureResults(); void sendTCPMeasureResults();
@ -187,12 +190,13 @@ private:
IVrWheelMeasureConfig* m_config = nullptr; IVrWheelMeasureConfig* m_config = nullptr;
WheelMeasureConfigResult m_configResult; WheelMeasureConfigResult m_configResult;
IWheelMeasureStatus* m_statusUpdate = nullptr; IWheelMeasureStatus* m_statusUpdate = nullptr;
int m_currentCameraIndex = 1; // 默认相机索引1-based
// TCP协议 // TCP协议
WheelMeasureTCPProtocol m_tcpProtocol; // TCP服务器协议 WheelMeasureTCPProtocol m_tcpProtocol; // TCP服务器协议
bool m_tcpDetectionMode = false; // 是否为TCP触发的检测 bool m_tcpDetectionMode = false; // 是否为TCP触发的检测
QMap<int, WheelMeasureTCPProtocol::CameraMeasureResult> m_tcpResults; // TCP检测结果缓存 QMap<int, WheelMeasureTCPProtocol::CameraMeasureResult> m_tcpResults; // TCP检测结果缓存
std::vector<int> m_tcpScanList; // TCP模式下待扫描的相机列表(1-based)
size_t m_tcpScanIndex = 0; // TCP模式下当前扫描索引
}; };
#endif // WHEELMEASUREPRESENTER_H #endif // WHEELMEASUREPRESENTER_H

View File

@ -54,6 +54,9 @@ int WheelMeasurePresenter::InitApp()
SetWorkStatus(WorkStatus::InitIng); SetWorkStatus(WorkStatus::InitIng);
// 默认相机索引初始化为11-based
m_currentCameraIndex = 1;
// 加载配置 // 加载配置
QString configPath = PathManager::GetInstance().GetConfigFilePath(); QString configPath = PathManager::GetInstance().GetConfigFilePath();
if (!initializeConfig(configPath)) { if (!initializeConfig(configPath)) {
@ -171,9 +174,22 @@ void WheelMeasurePresenter::OnWorkStatusChanged(WorkStatus status)
} }
}, Qt::QueuedConnection); }, Qt::QueuedConnection);
// TCP模式下检测完成,发送所有结果 // TCP模式下检测完成:顺序模式推进下一个相机批处理模式直接发送结果
if (status == WorkStatus::Completed && m_tcpDetectionMode) { if (status == WorkStatus::Completed && m_tcpDetectionMode) {
LOG_INFO("TCP模式所有相机检测完成准备发送结果\n"); if (!m_tcpScanList.empty()) {
// 顺序模式:推进到下一个相机
m_tcpScanIndex++;
if (m_tcpScanIndex < m_tcpScanList.size()) {
LOG_INFO("TCP模式当前相机扫描完成启动下一个相机 (%zu/%zu)\n",
m_tcpScanIndex + 1, m_tcpScanList.size());
QMetaObject::invokeMethod(this, [this]() {
startNextTCPCamera();
}, Qt::QueuedConnection);
return;
}
}
// 顺序模式末尾 或 批处理模式所有批次完成
LOG_INFO("TCP模式所有相机扫描完成准备发送结果\n");
QMetaObject::invokeMethod(this, [this]() { QMetaObject::invokeMethod(this, [this]() {
sendTCPMeasureResults(); sendTCPMeasureResults();
}, Qt::QueuedConnection); }, Qt::QueuedConnection);
@ -923,15 +939,75 @@ bool WheelMeasurePresenter::onTCPDetectionTriggered(int param)
// 清空之前的TCP结果缓存 // 清空之前的TCP结果缓存
m_tcpResults.clear(); m_tcpResults.clear();
m_tcpDetectionMode = true; m_tcpDetectionMode = true;
m_tcpScanList.clear();
m_tcpScanIndex = 0;
// 启动所有相机的顺序检测 // 统计启用的相机数量
int enabledCount = 0;
for (const auto& cameraConfig : m_configResult.cameras) {
if (cameraConfig.enabled) ++enabledCount;
}
if (enabledCount == 0) {
LOG_WARNING("TCP检测触发无启用的相机无法启动检测\n");
m_tcpDetectionMode = false;
return false;
}
// 清空之前的测量结果显示
QMetaObject::invokeMethod(this, [this]() { QMetaObject::invokeMethod(this, [this]() {
StartAllDetection(); if (m_statusUpdate) {
m_statusUpdate->OnClearMeasureData();
m_statusUpdate->OnStatusUpdate(QString("TCP触发开始检测所有设备"));
}
}, Qt::QueuedConnection); }, Qt::QueuedConnection);
int simCount = m_configResult.scanConfig.simultaneousCount;
if (simCount == 1) {
// 顺序模式:应用层逐个调度相机(每次 StartDetection(具体索引) 走 branch 1
for (int idx = 1; idx <= enabledCount; ++idx) {
m_tcpScanList.push_back(idx);
}
LOG_INFO("TCP检测顺序启动 %d 个相机 (simultaneousCount=1)\n", enabledCount);
QMetaObject::invokeMethod(this, [this]() {
startNextTCPCamera();
}, Qt::QueuedConnection);
} else {
// 批处理模式StartDetection(-1) 委托 BasePresenter 自动分批扫描所有相机
// - simultaneousCount=0: 所有相机同时扫描
// - simultaneousCount>1: 每批 N 个相机同时扫描
LOG_INFO("TCP检测批处理启动 (simultaneousCount=%d, 启用相机=%d)\n", simCount, enabledCount);
QMetaObject::invokeMethod(this, [this]() {
StartDetection(-1);
}, Qt::QueuedConnection);
}
return true; return true;
} }
void WheelMeasurePresenter::startNextTCPCamera()
{
if (m_tcpScanIndex >= m_tcpScanList.size()) {
LOG_WARNING("startNextTCPCamera: 索引越界,直接发送结果\n");
sendTCPMeasureResults();
return;
}
int cameraIdx = m_tcpScanList[m_tcpScanIndex];
LOG_INFO("TCP扫描: 启动相机 %d (%zu/%zu)\n",
cameraIdx, m_tcpScanIndex + 1, m_tcpScanList.size());
if (m_statusUpdate) {
m_statusUpdate->OnStatusUpdate(QString("TCP扫描相机 %1 (%2/%3)")
.arg(cameraIdx)
.arg(m_tcpScanIndex + 1)
.arg(m_tcpScanList.size()));
}
// 调用 BasePresenter::StartDetection 指定相机扫描branch 1: 单相机模式)
StartDetection(cameraIdx);
}
void WheelMeasurePresenter::sendTCPMeasureResults() void WheelMeasurePresenter::sendTCPMeasureResults()
{ {
// 计算期望的相机数量 // 计算期望的相机数量
@ -970,4 +1046,6 @@ void WheelMeasurePresenter::sendTCPMeasureResults()
// 清空缓存和标志 // 清空缓存和标志
m_tcpResults.clear(); m_tcpResults.clear();
m_tcpDetectionMode = false; m_tcpDetectionMode = false;
m_tcpScanList.clear();
m_tcpScanIndex = 0;
} }

View File

@ -3,7 +3,7 @@
#define WHEELMEASURE_APP_NAME "轮眉高度测量" #define WHEELMEASURE_APP_NAME "轮眉高度测量"
#define WHEELMEASURE_VERSION_STRING "1.1.6" #define WHEELMEASURE_VERSION_STRING "1.2.0"
#define WHEELMEASURE_BUILD_STRING "1" #define WHEELMEASURE_BUILD_STRING "1"
#define WHEELMEASURE_FULL_VERSION_STRING "V" WHEELMEASURE_VERSION_STRING "_" WHEELMEASURE_BUILD_STRING #define WHEELMEASURE_FULL_VERSION_STRING "V" WHEELMEASURE_VERSION_STRING "_" WHEELMEASURE_BUILD_STRING

View File

@ -1,3 +1,7 @@
# 1.2.0
## build_1 2026-05-17
1. 多相机并行扫描
# 1.1.6 # 1.1.6
## build_1 2026-04-25 ## build_1 2026-04-25
1. 优化存储数据 1. 优化存储数据

View File

@ -661,7 +661,7 @@ protected:
int m_batchStartIndex = 0; // 当前批次起始位置 int m_batchStartIndex = 0; // 当前批次起始位置
int m_batchSize = 0; // 当前批次相机数 int m_batchSize = 0; // 当前批次相机数
int m_batchFinishedCount = 0; // 当前批次已完成计数 int m_batchFinishedCount = 0; // 当前批次已完成计数
bool m_batchInProgress = false; // 是否正在分批扫描 std::atomic<bool> m_batchInProgress{false}; // 是否正在分批扫描(决定数据/状态回调的分流路径)
std::mutex m_batchStateMutex; // 保护分批调度状态 std::mutex m_batchStateMutex; // 保护分批调度状态
private: private:

View File

@ -196,7 +196,7 @@ int BasePresenter::StartDetection(int cameraIndex, bool isAuto)
LOG_INFO("[BasePresenter] 进入多相机分批扫描模式\n"); LOG_INFO("[BasePresenter] 进入多相机分批扫描模式\n");
// 停止当前正在进行的检测 // 停止当前正在进行的检测
if (m_batchInProgress || m_bAlgoDetectThreadRunning) { if (m_batchInProgress.load() || m_bAlgoDetectThreadRunning) {
StopDetection(); StopDetection();
} }
@ -566,7 +566,7 @@ void BasePresenter::AlgoDetectThreadFunc()
break; break;
} }
if (m_scanConfig.simultaneousCount > 1 || m_scanConfig.simultaneousCount == 0) { if (m_batchInProgress.load()) {
// 多相机分批模式:检查批次是否完成并处理 // 多相机分批模式:检查批次是否完成并处理
ProcessBatchIfReady(); ProcessBatchIfReady();
} else { } else {
@ -657,7 +657,7 @@ int BasePresenter::DetectTask()
// 批量模式下不在这里设置Completed由ProcessBatchIfReady统一设置 // 批量模式下不在这里设置Completed由ProcessBatchIfReady统一设置
{ {
std::lock_guard<std::mutex> lock(m_batchStateMutex); std::lock_guard<std::mutex> lock(m_batchStateMutex);
if (!m_batchInProgress) { if (!m_batchInProgress.load()) {
SetWorkStatus(WorkStatus::Completed); SetWorkStatus(WorkStatus::Completed);
} }
} }
@ -800,8 +800,8 @@ void BasePresenter::_StaticDetectionCallback(EVzResultDataType eDataType, SVzLas
lineData.bEndOnceScan = pLaserLinePoint->bEndOnceScan; lineData.bEndOnceScan = pLaserLinePoint->bEndOnceScan;
// 根据扫描模式分流存储 // 根据扫描模式分流存储
if (pThis->m_scanConfig.simultaneousCount > 1 || pThis->m_scanConfig.simultaneousCount == 0) { if (pThis->m_batchInProgress.load()) {
// 多相机同时扫描模式:存入该相机的独立缓存 // 多相机分批扫描模式:存入该相机的独立缓存
pThis->AddDetectionDataToCameraCache(cameraIndex, eDataType, lineData); pThis->AddDetectionDataToCameraCache(cameraIndex, eDataType, lineData);
} else { } else {
// 单相机模式:存入共享缓存 // 单相机模式:存入共享缓存
@ -846,8 +846,8 @@ void BasePresenter::_StaticCameraStatusCallback(EVzDeviceWorkStatus eStatus, voi
{ {
LOG_INFO("[BasePresenter Camera Status Callback] Camera %d scan finished\n", cameraIndex); LOG_INFO("[BasePresenter Camera Status Callback] Camera %d scan finished\n", cameraIndex);
// 多相机模式下记录批次完成 // 分批模式下记录批次完成
if (pThis->m_scanConfig.simultaneousCount > 1 || pThis->m_scanConfig.simultaneousCount == 0) { if (pThis->m_batchInProgress.load()) {
pThis->OnCameraScanFinished(cameraIndex); pThis->OnCameraScanFinished(cameraIndex);
} }
@ -1131,7 +1131,7 @@ void BasePresenter::ProcessBatchIfReady()
bool batchComplete = false; bool batchComplete = false;
{ {
std::lock_guard<std::mutex> lock(m_batchStateMutex); std::lock_guard<std::mutex> lock(m_batchStateMutex);
if (!m_batchInProgress) return; if (!m_batchInProgress.load()) return;
batchComplete = (m_batchFinishedCount >= m_batchSize); batchComplete = (m_batchFinishedCount >= m_batchSize);
} }