756 lines
31 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "DetectPresenter.h"
#include <algorithm>
#include <cmath>
#include <utility>
#include <vector>
#include "AapgsModelClassifier.h"
#include "PersionModelDetector.h"
#include "SG_errCode.h"
#include "planeLocalization_Export.h"
namespace
{
struct PlaneLocalizationResult
{
SSX_planeInfo info{};
int errorCode = 0;
QString errorMessage;
};
bool IsFinitePoint(const SVzNL3DPoint& point)
{
return std::isfinite(point.x) &&
std::isfinite(point.y) &&
std::isfinite(point.z);
}
bool IsPersonDetection(const PersionModelDetector::Detection& detection)
{
const QString label = detection.label.trimmed();
return label.compare(QStringLiteral("person"), Qt::CaseInsensitive) == 0 ||
(label.isEmpty() && detection.classId == 0);
}
bool ConvertCloudToScanLines(
const RsCloudData& cloud,
std::vector<std::vector<SVzNL3DPosition>>& scanLines,
QString& errorMessage)
{
scanLines.clear();
errorMessage.clear();
scanLines.reserve(cloud.size());
size_t validPointCount = 0;
for (const auto& item : cloud) {
const EVzResultDataType dataType = item.first;
const SVzLaserLineData& sourceLine = item.second;
if (sourceLine.nPointCount < 0 ||
(sourceLine.nPointCount > 0 && !sourceLine.p3DPoint)) {
errorMessage = QStringLiteral("点云包含无效扫描线");
return false;
}
if (dataType != keResultDataType_PointXYZI &&
dataType != keResultDataType_Position) {
errorMessage = QStringLiteral("停机算法不支持点云类型:%1")
.arg(static_cast<int>(dataType));
return false;
}
std::vector<SVzNL3DPosition> targetLine;
targetLine.resize(static_cast<size_t>(sourceLine.nPointCount));
if (dataType == keResultDataType_PointXYZI) {
const auto* points =
static_cast<const SVzNLPointXYZI*>(sourceLine.p3DPoint);
for (int pointIndex = 0;
pointIndex < sourceLine.nPointCount;
++pointIndex) {
SVzNL3DPosition& target =
targetLine[static_cast<size_t>(pointIndex)];
target.nPointIdx = pointIndex;
target.pt3D.x = static_cast<double>(points[pointIndex].x);
target.pt3D.y = static_cast<double>(points[pointIndex].y);
target.pt3D.z = static_cast<double>(points[pointIndex].z);
if (!IsFinitePoint(target.pt3D)) {
target.pt3D = { 0.0, 0.0, 0.0 };
} else if (std::fabs(target.pt3D.x) > 1e-6 ||
std::fabs(target.pt3D.y) > 1e-6 ||
std::fabs(target.pt3D.z) > 1e-6) {
++validPointCount;
}
}
} else {
const auto* points =
static_cast<const SVzNL3DPosition*>(sourceLine.p3DPoint);
for (int pointIndex = 0;
pointIndex < sourceLine.nPointCount;
++pointIndex) {
targetLine[static_cast<size_t>(pointIndex)] = points[pointIndex];
SVzNL3DPoint& point =
targetLine[static_cast<size_t>(pointIndex)].pt3D;
if (!IsFinitePoint(point)) {
point = { 0.0, 0.0, 0.0 };
} else if (std::fabs(point.x) > 1e-6 ||
std::fabs(point.y) > 1e-6 ||
std::fabs(point.z) > 1e-6) {
++validPointCount;
}
}
}
scanLines.push_back(std::move(targetLine));
}
if (scanLines.empty() || validPointCount == 0) {
errorMessage = QStringLiteral("点云不包含有效三维点");
return false;
}
return true;
}
SSX_planeParkingParam BuildParkingParam(const VrPlaneParkingParam& source)
{
SSX_planeParkingParam target{};
target.parkingPoint = { source.parkingPointX,
source.parkingPointY,
source.parkingPointZ };
target.guideLinePoint = { source.guideLinePointX,
source.guideLinePointY,
source.guideLinePointZ };
target.guidingRange = source.guidingRange;
target.parkingRange = source.parkingRange;
target.distFromNoseToWheel = source.distFromNoseToWheel;
return target;
}
SSG_planeCalibPara BuildGroundCalibrationParam(
const VrPlaneGroundCalibrationParam& source)
{
SSG_planeCalibPara target{};
for (int i = 0; i < 9; ++i) {
target.planeCalib[i] = source.planeCalib[i];
target.invRMatrix[i] = source.invRMatrix[i];
}
target.planeHeight = source.planeHeight;
return target;
}
SSG_treeGrowParam BuildTreeGrowParam(const VrPlaneTreeGrowParam& source)
{
SSG_treeGrowParam target{};
target.yDeviation_max = source.yDeviationMax;
target.zDeviation_max = source.zDeviationMax;
target.maxLineSkipNum = source.maxLineSkipNum;
target.maxSkipDistance = source.maxSkipDistance;
target.minLTypeTreeLen = source.minLTypeTreeLen;
target.minVTypeTreeLen = source.minVTypeTreeLen;
return target;
}
PlaneLocalizationResult LocalizePlane(const RsCloudData& cloud,
const VrAlgorithmParams& algorithmParams)
{
PlaneLocalizationResult result;
std::vector<std::vector<SVzNL3DPosition>> scanLines;
if (!ConvertCloudToScanLines(cloud, scanLines, result.errorMessage)) {
result.errorCode = cloud.empty() ? SG_ERR_3D_DATA_NULL
: SG_ERR_3D_DATA_INVLD;
return result;
}
std::vector<std::vector<SVzNL3DPosition>> debugData;
int algorithmError = 0;
result.info = wd_planeLocalization(
scanLines,
BuildGroundCalibrationParam(algorithmParams.groundCalibrationParam),
BuildParkingParam(algorithmParams.planeParkingParam),
BuildTreeGrowParam(algorithmParams.treeGrowParam),
debugData,
&algorithmError);
result.errorCode = algorithmError;
if (algorithmError == SX_ERR_NO_PLANE_FOUND) {
result.errorMessage = QStringLiteral("未找到有效飞机目标");
} else if (algorithmError == SX_ERR_NOSEPOINT_FAIL) {
result.errorMessage = QStringLiteral("飞机机鼻定位失败");
} else if (algorithmError == SX_ERR_ENDINE_FAIL) {
result.errorMessage = QStringLiteral("飞机主体特征提取失败");
} else if (algorithmError != 0) {
result.errorMessage = QStringLiteral("飞机定位算法错误:%1")
.arg(algorithmError);
} else if (!std::isfinite(result.info.distance) ||
!std::isfinite(result.info.deviation) ||
!std::isfinite(result.info.dirAngle_deg) ||
!IsFinitePoint(result.info.nosePoint) ||
!IsFinitePoint(result.info.axis)) {
result.errorCode = SG_ERR_3D_DATA_INVLD;
result.errorMessage = QStringLiteral("飞机定位算法返回非有限数值");
}
return result;
}
bool IsPlaneLostError(int errorCode)
{
return errorCode == SX_ERR_NO_PLANE_FOUND ||
errorCode == SX_ERR_NOSEPOINT_FAIL ||
errorCode == SX_ERR_ENDINE_FAIL ||
errorCode == SG_ERR_3D_DATA_NULL;
}
QString GuideText(ParkingGuideState state)
{
switch (state) {
case ParkingGuideState::DockingStarted: return QStringLiteral("START");
case ParkingGuideState::Capturing: return QStringLiteral("CAPTURE");
case ParkingGuideState::Tracking: return QStringLiteral("TRACKING");
case ParkingGuideState::ApproachRate: return QStringLiteral("APPROACH");
case ParkingGuideState::CenterLineAligned: return QStringLiteral("CENTER");
case ParkingGuideState::Slow: return QStringLiteral("SLOW");
case ParkingGuideState::AzimuthGuidance: return QStringLiteral("AZIMUTH");
case ParkingGuideState::StopPositionReached: return QStringLiteral("STOP");
case ParkingGuideState::DockingCompleted: return QStringLiteral("OK");
case ParkingGuideState::Overshot: return QStringLiteral("TOOFAR");
case ParkingGuideState::StoppedShort: return QStringLiteral("STOP SHORT");
case ParkingGuideState::SlowAircraftLost: return QStringLiteral("SLOW+LOST");
case ParkingGuideState::AircraftVerificationFailed:
return QStringLiteral("STOP+IDFAIL");
case ParkingGuideState::TooFast: return QStringLiteral("STOPTOOFAST");
case ParkingGuideState::EmergencyStop: return QStringLiteral("STOP");
case ParkingGuideState::ChocksOn: return QStringLiteral("CHOCK ON");
case ParkingGuideState::SystemError: return QStringLiteral("ERROR");
default: return QStringLiteral("WAIT");
}
}
void SetGuideState(ParkingSpaceGuideInfo& info, ParkingGuideState state)
{
info.guideStateCode = static_cast<int>(state);
info.guideText = GuideText(state);
}
ParkingSpaceGuideInfo MakeLastKnownInfo(
const ParkingGuideAlgorithmState& state)
{
ParkingSpaceGuideInfo info;
const QString selectedModelType = state.selectedModelType.trimmed();
const QString recognizedModelType = state.recognizedModelType.trimmed();
info.expectedModelType = selectedModelType;
info.modelType = recognizedModelType.isEmpty()
? QStringLiteral("未知")
: recognizedModelType;
info.modelMatched = state.modelVerified;
info.modelVerificationSupported = state.modelVerificationSupported;
info.personInChockRegion = state.personInChockRegion;
info.chocksConfirmed = state.chocksConfirmed;
info.personCount = state.personCount;
info.personConfidence = state.personConfidence;
info.distance = state.lastDistance;
info.lateralOffset = state.lastDeviation;
info.angle = state.lastAngle;
info.aircraftSpeed = state.filteredApproachSpeed / 1000.0;
info.confidence = std::isfinite(state.modelConfidence)
? state.modelConfidence
: 0.0;
return info;
}
}
DetectPresenter::DetectPresenter()
: m_modelClassifier(std::make_unique<AapgsModelClassifier>())
, m_personDetector(std::make_unique<PersionModelDetector>())
{
}
DetectPresenter::~DetectPresenter() = default;
bool ModelRecognitionResult::IsVerified(double minimumConfidence) const
{
if (!std::isfinite(minimumConfidence)) {
return false;
}
const QString normalizedModel = modelType.trimmed();
const bool isUnknown = normalizedModel == QStringLiteral("未知") ||
normalizedModel.compare(QStringLiteral("unknown"), Qt::CaseInsensitive) == 0;
const double threshold = (std::max)(0.0, minimumConfidence);
return verified &&
!normalizedModel.isEmpty() &&
!isUnknown &&
std::isfinite(confidence) &&
confidence >= threshold;
}
QString DetectPresenter::GetAlgoVersion()
{
const char* planeVersion = wd_PlaneLocalizationVersion();
return QStringLiteral(
"planeLocalization %1 / AAPGS_model 1.0.0 / Persion_model 1.0.0")
.arg(planeVersion ? QString::fromLocal8Bit(planeVersion)
: QStringLiteral("未知"));
}
int DetectPresenter::DetectAirplanePresence(const RsCloudData& cloud,
const VrAlgorithmParams& algorithmParams,
AirplanePresenceResult& result)
{
result = AirplanePresenceResult();
const PlaneLocalizationResult localization =
LocalizePlane(cloud, algorithmParams);
if (localization.errorCode == 0) {
result.state = AirplanePresenceState::Detected;
result.message = QStringLiteral("检测到飞机,距离停机点 %1 mm")
.arg(localization.info.distance, 0, 'f', 1);
return 0;
}
if (IsPlaneLostError(localization.errorCode)) {
result.state = AirplanePresenceState::NotDetected;
result.message = localization.errorMessage.trimmed().isEmpty()
? QStringLiteral("未检测到飞机")
: localization.errorMessage;
return 0;
}
result.state = AirplanePresenceState::ViewBlocked;
result.message = localization.errorMessage.trimmed().isEmpty()
? QStringLiteral("飞机检测视野或点云异常")
: localization.errorMessage;
return 0;
}
int DetectPresenter::DetectParkingSpaceGuide(const RsCloudData& cloud,
const VrAlgorithmParams& algorithmParams,
qint64 frameTimestampMs,
const ParkingGuideAlgorithmState& previousState,
DetectionResult& result,
ParkingGuideAlgorithmControl& control)
{
result = DetectionResult();
control = ParkingGuideAlgorithmControl();
control.nextState = previousState;
result.cameraIndex = 1;
result.errorCode = 0;
const VrGuideDecisionParam& guideParam = algorithmParams.guideDecisionParam;
const VrParkingProcessParam& processParam = algorithmParams.processParam;
const VrModelRecognitionParam& modelParam =
algorithmParams.modelRecognitionParam;
const PlaneLocalizationResult localization =
LocalizePlane(cloud, algorithmParams);
control.planeLocalizationErrorCode = localization.errorCode;
control.planeLocalizationMessage = localization.errorMessage;
if (localization.errorCode != 0) {
ParkingGuideAlgorithmState& next = control.nextState;
next.errorFrameCount =
(std::max)(0, previousState.errorFrameCount) + 1;
const bool planeLost = IsPlaneLostError(localization.errorCode);
next.lostFrameCount = planeLost
? (std::max)(0, previousState.lostFrameCount) + 1
: 0;
ParkingSpaceGuideInfo errorInfo = MakeLastKnownInfo(previousState);
const int errorThreshold =
(std::max)(1, processParam.errorFrameThreshold);
if (next.errorFrameCount < errorThreshold) {
const ParkingGuideState retainedState = previousState.hasMeasurement
? ParkingGuideStateFromCode(previousState.lastGuideStateCode)
: ParkingGuideState::Waiting;
SetGuideState(errorInfo,
retainedState == ParkingGuideState::Unknown
? ParkingGuideState::Waiting
: retainedState);
result.message = previousState.hasMeasurement
? QStringLiteral(
"距离 %1 mm横向偏差 %2 mm航向角 %3°接近速度 %4 m/s")
.arg(errorInfo.distance, 0, 'f', 1)
.arg(errorInfo.lateralOffset, 0, 'f', 1)
.arg(errorInfo.angle, 0, 'f', 2)
.arg(errorInfo.aircraftSpeed, 0, 'f', 1)
: QStringLiteral("等待飞机定位");
} else {
SetGuideState(errorInfo,
planeLost
? ParkingGuideState::SlowAircraftLost
: ParkingGuideState::SystemError);
errorInfo.hasException = true;
result.errorCode = localization.errorCode;
next.stoppedFrameCount = 0;
next.stoppedShortFrameCount = 0;
next.stopPositionReached = false;
next.dockingCompleted = false;
next.completedHoldFrameCount = 0;
result.message = localization.errorMessage.trimmed().isEmpty()
? QStringLiteral("停机引导定位失败")
: localization.errorMessage;
}
result.parkingSpaceInfoList.push_back(errorInfo);
return 0;
}
if (previousState.hasMeasurement) {
const double distanceChange = std::fabs(
localization.info.distance - previousState.lastDistance);
const double lateralOffsetChange = std::fabs(
localization.info.deviation - previousState.lastDeviation);
const double distanceThreshold = (std::max)(
0.0, processParam.distanceChangeThreshold);
const double lateralOffsetThreshold = (std::max)(
0.0, processParam.lateralOffsetChangeThreshold);
if (distanceChange > distanceThreshold ||
lateralOffsetChange > lateralOffsetThreshold) {
ParkingSpaceGuideInfo retainedInfo =
MakeLastKnownInfo(previousState);
const ParkingGuideState retainedState =
ParkingGuideStateFromCode(previousState.lastGuideStateCode);
SetGuideState(retainedInfo,
retainedState == ParkingGuideState::Unknown
? ParkingGuideState::Waiting
: retainedState);
result.parkingSpaceInfoList.push_back(retainedInfo);
result.message = QStringLiteral(
"检测数据突变已忽略:距离变化 %1 mm阈值 %2 mm%3横向偏移变化 %4 mm阈值 %5 mm%6")
.arg(distanceChange, 0, 'f', 1)
.arg(distanceThreshold, 0, 'f', 1)
.arg(distanceChange > distanceThreshold
? QStringLiteral("超阈值")
: QStringLiteral("未超阈值"))
.arg(lateralOffsetChange, 0, 'f', 1)
.arg(lateralOffsetThreshold, 0, 'f', 1)
.arg(lateralOffsetChange > lateralOffsetThreshold
? QStringLiteral("超阈值")
: QStringLiteral("未超阈值"));
return 0;
}
}
ParkingGuideAlgorithmState& next = control.nextState;
next.errorFrameCount = 0;
next.lostFrameCount = 0;
next.successfulFrameCount =
(std::max)(0, previousState.successfulFrameCount) + 1;
double approachSpeed = previousState.filteredApproachSpeed;
if (previousState.hasMeasurement &&
previousState.errorFrameCount == 0 &&
frameTimestampMs > previousState.lastTimestampMs) {
const double elapsedSeconds =
static_cast<double>(frameTimestampMs - previousState.lastTimestampMs) /
1000.0;
const double rawApproachSpeed =
(previousState.lastDistance - localization.info.distance) /
elapsedSeconds;
const double alpha = std::clamp(processParam.speedFilterAlpha,
0.0,
1.0);
approachSpeed = alpha * rawApproachSpeed +
(1.0 - alpha) * previousState.filteredApproachSpeed;
} else if (!previousState.hasMeasurement ||
previousState.errorFrameCount > 0) {
approachSpeed = 0.0;
}
if (!std::isfinite(approachSpeed)) {
approachSpeed = 0.0;
}
next.hasMeasurement = true;
next.lastTimestampMs = frameTimestampMs;
next.lastDistance = localization.info.distance;
next.lastDeviation = localization.info.deviation;
next.lastAngle = localization.info.dirAngle_deg;
next.lastNoseX = localization.info.nosePoint.x;
next.lastNoseY = localization.info.nosePoint.y;
next.lastNoseZ = localization.info.nosePoint.z;
next.filteredApproachSpeed = approachSpeed;
ParkingSpaceGuidePosition position;
position.x = localization.info.nosePoint.x;
position.y = localization.info.nosePoint.y;
position.z = localization.info.nosePoint.z;
position.roll = 0.0;
position.pitch = 0.0;
position.yaw = localization.info.dirAngle_deg;
result.positions.push_back(position);
ParkingSpaceGuideInfo info = MakeLastKnownInfo(next);
info.hasException = false;
const double stopTolerance =
(std::max)(0.0, processParam.stopDistanceTolerance);
const double overshootDistance =
(std::max)(stopTolerance, processParam.overshootDistance);
const double slowDistance =
(std::max)(stopTolerance, processParam.slowDistance);
const double approachStartDistance =
(std::max)(slowDistance, processParam.approachStartDistance);
const double captureStartDistance =
(std::max)(approachStartDistance,
processParam.captureStartDistance);
const double dockingStartDistance =
(std::max)(captureStartDistance,
processParam.dockingStartDistance);
const double stoppedSpeed =
(std::max)(0.0, processParam.stoppedSpeedThreshold);
const double maxApproachSpeed =
(std::max)(0.0, processParam.maxApproachSpeed);
const bool hasSpeedBaseline = previousState.hasMeasurement &&
previousState.errorFrameCount == 0;
const bool isStopped = hasSpeedBaseline &&
std::fabs(approachSpeed) <= stoppedSpeed;
const bool isAtStopPosition =
std::fabs(localization.info.distance) <= stopTolerance;
ParkingGuideState guideState = ParkingGuideState::Tracking;
// Overshoot must win over a previously reached stop position. The
// completion latch is only valid while the aircraft remains in the stop
// tolerance; otherwise the process must resume guidance.
if (localization.info.distance <= -overshootDistance) {
next.stopPositionReached = false;
next.dockingCompleted = false;
next.stoppedFrameCount = 0;
next.stoppedShortFrameCount = 0;
next.completedHoldFrameCount = 0;
next.centerLineAligned = false;
guideState = ParkingGuideState::Overshot;
} else if (previousState.dockingCompleted &&
isAtStopPosition &&
isStopped) {
next.dockingCompleted = true;
guideState = ParkingGuideState::DockingCompleted;
} else if (isAtStopPosition) {
next.dockingCompleted = false;
next.stoppedShortFrameCount = 0;
if (!previousState.stopPositionReached) {
next.stopPositionReached = true;
next.completedHoldFrameCount = 0;
}
if (isStopped) {
next.stoppedFrameCount =
(std::max)(0, previousState.stoppedFrameCount) + 1;
} else {
next.stoppedFrameCount = 0;
}
next.completedHoldFrameCount =
(std::max)(0, previousState.completedHoldFrameCount) + 1;
const int stableFrames = (std::max)(1, processParam.stopStableFrames);
const int completedFrames =
(std::max)(1, processParam.completedHoldFrames);
if (next.stoppedFrameCount >= stableFrames &&
next.completedHoldFrameCount >= completedFrames) {
next.dockingCompleted = true;
guideState = ParkingGuideState::DockingCompleted;
} else {
guideState = ParkingGuideState::StopPositionReached;
}
} else {
next.stopPositionReached = false;
next.dockingCompleted = false;
next.stoppedFrameCount = 0;
next.stoppedShortFrameCount = 0;
next.centerLineAligned = false;
next.completedHoldFrameCount = 0;
const double stoppedShortDistance =
(std::max)(stopTolerance, processParam.stoppedShortMinDistance);
if (previousState.hasMeasurement &&
next.successfulFrameCount > 4 &&
isStopped &&
localization.info.distance >= stoppedShortDistance) {
next.stoppedShortFrameCount =
(std::max)(0, previousState.stoppedShortFrameCount) + 1;
} else {
next.stoppedShortFrameCount = 0;
}
if (next.stoppedShortFrameCount >=
(std::max)(1, processParam.stoppedShortStableFrames)) {
guideState = ParkingGuideState::StoppedShort;
} else if (localization.info.distance >= 0.0 &&
localization.info.distance <= slowDistance &&
hasSpeedBaseline &&
maxApproachSpeed > 0.0 &&
approachSpeed >= maxApproachSpeed) {
guideState = ParkingGuideState::Slow;
} else if (localization.info.distance > slowDistance &&
hasSpeedBaseline &&
maxApproachSpeed > 0.0 &&
approachSpeed >= maxApproachSpeed) {
guideState = ParkingGuideState::TooFast;
} else if (localization.info.distance >= 0.0 &&
localization.info.distance <= approachStartDistance &&
(std::fabs(localization.info.deviation) >
(std::max)(0.0, guideParam.lateralTolerance) ||
std::fabs(localization.info.dirAngle_deg) >
(std::max)(0.0, guideParam.angleTolerance))) {
next.centerLineAligned = false;
guideState = ParkingGuideState::AzimuthGuidance;
} else if (localization.info.distance >= 0.0 &&
localization.info.distance <= approachStartDistance) {
next.centerLineAligned = true;
guideState = ParkingGuideState::CenterLineAligned;
} else if (localization.info.distance <= captureStartDistance &&
localization.info.distance > approachStartDistance) {
next.centerLineAligned = false;
guideState = ParkingGuideState::Capturing;
} else if (localization.info.distance <= dockingStartDistance &&
localization.info.distance > captureStartDistance) {
next.centerLineAligned = false;
guideState = ParkingGuideState::DockingStarted;
} else if (localization.info.distance > dockingStartDistance) {
next.centerLineAligned = false;
guideState = ParkingGuideState::Waiting;
} else {
next.centerLineAligned = false;
guideState = ParkingGuideState::Tracking;
}
}
SetGuideState(info, guideState);
next.lastGuideStateCode = info.guideStateCode;
result.parkingSpaceInfoList.push_back(info);
result.message = QStringLiteral(
"距离 %1 mm横向偏差 %2 mm航向角 %3°接近速度 %4 m/s")
.arg(info.distance, 0, 'f', 1)
.arg(info.lateralOffset, 0, 'f', 1)
.arg(info.angle, 0, 'f', 2)
.arg(info.aircraftSpeed, 0, 'f', 1);
const double modelVerifyDistance = modelParam.modelVerifyDistance;
const int maxRecognitionAttempts =
(std::max)(1, modelParam.maxRecognitionAttempts);
const bool isInModelVerifyRange = modelVerifyDistance >= 0.0 &&
info.distance >= 0.0 &&
info.distance <= modelVerifyDistance;
const ParkingGuideState measuredState =
ParkingGuideStateFromCode(info.guideStateCode);
const bool mustPreserveMeasuredState =
measuredState == ParkingGuideState::Overshot;
const bool hasSelectedModel =
!previousState.selectedModelType.trimmed().isEmpty();
const bool canAttemptRecognition =
!hasSelectedModel ||
previousState.modelRecognitionAttempts < maxRecognitionAttempts;
if (isInModelVerifyRange &&
!previousState.modelRecognitionComplete &&
!previousState.modelRecognitionInProgress &&
canAttemptRecognition) {
control.needModelRecognition = true;
control.recognitionContext =
previousState.selectedModelType.trimmed().toUtf8();
} else if (isInModelVerifyRange &&
!previousState.modelRecognitionComplete &&
!previousState.modelRecognitionInProgress &&
hasSelectedModel &&
!mustPreserveMeasuredState) {
ParkingSpaceGuideInfo& failedInfo = result.parkingSpaceInfoList.back();
failedInfo.hasException = true;
failedInfo.guideStateCode =
static_cast<int>(ParkingGuideState::AircraftVerificationFailed);
failedInfo.guideText =
GuideText(ParkingGuideState::AircraftVerificationFailed);
control.nextState.lastGuideStateCode = failedInfo.guideStateCode;
result.message = QStringLiteral("机型二次验证失败");
}
return 0;
}
int DetectPresenter::RecognizeModel2D(const QImage& frame,
const QByteArray& recognitionContext,
ModelRecognitionResult& result)
{
result = ModelRecognitionResult();
if (!m_modelClassifier) {
result.message = QStringLiteral("AAPGS机型识别器未初始化");
return -1;
}
AapgsModelClassifier::Classification classification;
QString errorMessage;
if (!m_modelClassifier->Classify(frame, classification, errorMessage)) {
result.message = errorMessage.trimmed().isEmpty()
? QStringLiteral("AAPGS机型识别失败")
: errorMessage.trimmed();
return -1;
}
result.recognitionComplete = true;
result.verificationSupported = true;
result.modelType = classification.modelType;
result.confidence = classification.confidence;
const QString expectedModelType =
QString::fromUtf8(recognitionContext).trimmed();
const QString recognizedModelType = result.modelType.trimmed();
if (expectedModelType.isEmpty()) {
result.message = QStringLiteral("自动识别机型:%1")
.arg(recognizedModelType);
return 0;
}
if (recognizedModelType.compare(expectedModelType,
Qt::CaseInsensitive) != 0) {
result.message = QStringLiteral("机型验证不一致:选择%1识别%2")
.arg(expectedModelType,
recognizedModelType.isEmpty()
? QStringLiteral("未知")
: recognizedModelType);
return 0;
}
result.verified = true;
return 0;
}
int DetectPresenter::DetectPersonInRegion2D(
const QImage& frame,
const VrPersonDetectionParam& personParam,
PersonDetectionResult& result)
{
result = PersonDetectionResult();
if (!m_personDetector || frame.isNull()) {
result.message = QStringLiteral("人员检测图像或检测器不可用");
return -1;
}
const double imageWidth = static_cast<double>(frame.width());
const double imageHeight = static_cast<double>(frame.height());
// The caller has already cropped the configured chock ROI. Detection and
// result coordinates therefore use the cropped image as their full area.
result.roi = QRectF(0.0, 0.0, imageWidth, imageHeight);
PersionModelDetector::Analysis analysis;
QString errorMessage;
if (!m_personDetector->Analyze(frame, analysis, errorMessage)) {
result.message = errorMessage.trimmed().isEmpty()
? QStringLiteral("Persion人员检测失败")
: errorMessage.trimmed();
return -1;
}
const double threshold = std::clamp(personParam.confidenceThreshold,
0.0,
1.0);
for (const PersionModelDetector::Detection& detection : analysis.detections) {
if (!IsPersonDetection(detection) ||
detection.confidence < threshold) {
continue;
}
const QRectF box = detection.boundingBox.intersected(
QRectF(0.0, 0.0, imageWidth, imageHeight));
if (box.isEmpty()) {
continue;
}
result.personBoxes.push_back(box);
++result.personCount;
result.confidence = (std::max)(result.confidence,
detection.confidence);
}
result.personInRegion = result.personCount > 0;
result.message = result.personInRegion
? QStringLiteral("轮挡区域检测到人员")
: QStringLiteral("等待人员进入轮挡区域");
return 0;
}