提交修改

This commit is contained in:
cool609 2026-03-25 04:12:40 +08:00
parent 252a5232da
commit 26f8780eff

View File

@ -142,7 +142,15 @@ void EvaluateLine(
}
// 角度平滑:滑动窗口均值,抑制点级噪声
// Fix3: 先保存原始角度,平滑后对所有"原始角度已超阈"的点强制恢复特征分类,
// 防止平滑窗口把窄孔洞两侧的异号角度互相抵消,导致真实边缘被压回 Flat。
{
// 保存平滑前的原始角度
std::vector<float> rawAngles(count, 0.0f);
for (int i = 0; i < count; i++) {
rawAngles[i] = pts[i].signedAngleDeg;
}
int smoothW = params.residualSmoothWindow;
if (smoothW > 1) {
int halfW = smoothW / 2;
@ -170,6 +178,24 @@ void EvaluateLine(
pts[i].trend = keLineAngleTrend_Flat;
}
}
// Fix3: 若原始角度已超过检测阈值,平滑窗口不应将其压回 Flat。
// 原始角度由 searchDist 参考点计算,本身已具备一定的抗噪能力。
// 平滑窗口在孔洞两侧引入异号角度交叉干扰,会把窄孔洞的边缘信号抹平:
// - 孔洞入射侧的 Desc 角被出射侧的正角平均拉升,可能越过 negThresh
// - 孔洞出射侧的 Asc 角被入射侧的负角平均拉低,可能跌破 posThresh。
// 保护原则raw 超阈 → 强制保留为特征点raw 未超阈 → 允许平滑结果覆盖。
for (int i = 0; i < count; i++) {
if (!pts[i].hasAngle) continue;
float raw = rawAngles[i];
if (raw > posThresh && pts[i].trend != keLineAngleTrend_PositiveJump) {
pts[i].signedAngleDeg = raw;
pts[i].trend = keLineAngleTrend_PositiveJump;
} else if (raw < negThresh && pts[i].trend != keLineAngleTrend_NegativeJump) {
pts[i].signedAngleDeg = raw;
pts[i].trend = keLineAngleTrend_NegativeJump;
}
}
}
// ================================================================
@ -248,12 +274,18 @@ void EvaluateLine(
}
// 短段合并:单点的 Ascending/Descending 段视为噪声,合并回 Flat
// 例外:紧邻 Gap 段的单点 Asc/Desc 是孔洞边缘的真实信号,不应消除
{
for (auto& seg : segs) {
for (size_t k = 0; k < segs.size(); k++) {
auto& seg = segs[k];
if (seg.type != ESegType::Flat && seg.type != ESegType::Gap) {
int segLen = seg.endPos - seg.startPos + 1;
if (segLen < 2) {
seg.type = ESegType::Flat;
bool adjToGap = (k > 0 && segs[k - 1].type == ESegType::Gap)
|| (k + 1 < segs.size() && segs[k + 1].type == ESegType::Gap);
if (!adjToGap) {
seg.type = ESegType::Flat;
}
}
}
}
@ -288,10 +320,13 @@ void EvaluateLine(
bool seenDesc = false, seenAsc = false, seenGap = false;
bool descFirst = false;
bool seenInnerFlat = false; // 已在"坑底"模式下见过内部 Flat
size_t bestExit = si;
for (size_t ei = si + 1; ei < segs.size(); ei++) {
if (segs[ei].type == ESegType::Descending) {
// 若已见过内部 Flat 且尚未找到上升沿,说明这是第二个独立特征的下降,不应桥接
if (seenInnerFlat && !seenAsc) break;
if (!seenAsc) descFirst = true;
seenDesc = true;
continue;
@ -313,8 +348,10 @@ void EvaluateLine(
if (seenDesc && seenAsc && descFirst) break; // 完整凹坑
if (!seenDesc && !seenAsc && seenGap) break; // 纯空洞
if (!seenDesc && seenAsc) break; // 仅上升(凸起),不继续
if (seenDesc && seenAsc && !descFirst) break; // 上升-下降型边缘/凸起,完成配对
// seenDesc && !seenAsc: 可能是内部 Flat坑底继续向前找上升
seenInnerFlat = true;
}
if (bestExit <= si) continue;
@ -327,6 +364,18 @@ void EvaluateLine(
int startPos = segs[si].endPos;
int endPos = segs[bestExit].startPos;
// 对凹坑特征,右边界应落在最后一个上升段的末端,而不是后继 Flat 的起点。
// 否则会把边界推出到已经回到平台面的点上,导致 pair 比真实坑口更宽。
if (isPit) {
for (size_t back = bestExit; back > si; --back) {
const Segment& seg = segs[back - 1];
if (seg.type == ESegType::Ascending) {
endPos = seg.endPos;
break;
}
}
}
// depth: 表面与坑底的 z 极差
float refZ = std::min(pts[startPos].point.z, pts[endPos].point.z);
float minZ = refZ, maxZ = refZ;