diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index f3edd18..17c88fb 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -16099,7 +16099,7 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches( // ★ 如果求逆策略全部越界,尝试直接用 H(不逆) if (allOutOfRange) { - printf("[DIAG] Invert strategy failed for pi=%d, trying direct H...\n", pi); + // printf("[DIAG] Invert strategy failed for pi=%d, trying direct H...\n", pi); const float* H_direct = geom.homography.ptr(); allOutOfRange = true; @@ -16143,7 +16143,7 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches( // 如果两种策略都失败,跳过这个虚拟面 if (allOutOfRange) { - printf("[WARN] Both mapping strategies failed for pi=%d, vfID=%u\n", pi, vfID); + // printf("[WARN] Both mapping strategies failed for pi=%d, vfID=%u\n", pi, vfID); continue; } @@ -17904,6 +17904,63 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( (int)faceNeighbors.empty()); DEBUG_EXTRA("Selecting best views for %zu virtual faces", virtualFaceMap.size()); + + // ---------- 准备禁用视图列表(禁用最后一个单独数字 = 最大值的【所有】相机) ---------- + std::unordered_set disabledViews; + { + struct ViewDigitPair { + IIndex idx; + int digit; + }; + std::vector viewDigits; + + for (IIndex idx = 0; idx < (IIndex)images.size(); ++idx) { + const Image& img = images[idx]; + if (!img.IsValid()) continue; + + // 提取文件名(不含路径和扩展名) + std::string path = img.name; + size_t lastSlash = path.find_last_of("/\\"); + size_t start = (lastSlash == std::string::npos) ? 0 : lastSlash + 1; + size_t lastDot = path.find_last_of('.'); + if (lastDot == std::string::npos) lastDot = path.size(); + std::string strName = path.substr(start, lastDot - start); + + // 提取最后一个 _ 前面的最后一个数字字符 + int digit = -1; + size_t lastUnderscore = strName.find_last_of('_'); + if (lastUnderscore != std::string::npos && lastUnderscore > 0) { + for (size_t pos = lastUnderscore - 1; ; --pos) { + if (std::isdigit(strName[pos])) { + digit = strName[pos] - '0'; + break; + } + if (pos == 0) break; + } + } + + if (digit >= 0) { + viewDigits.push_back({idx, digit}); + } + } + + // ★ 找到最大的 digit 值 + int maxDigit = -1; + for (const auto& vd : viewDigits) { + if (vd.digit > maxDigit) maxDigit = vd.digit; + } + + // ★ 禁用【所有】digit == maxDigit 的视图(不再只禁前 N 个) + for (const auto& vd : viewDigits) { + if (vd.digit == maxDigit) { + disabledViews.insert(vd.idx); + DEBUG_EXTRA("[DisabledView] idx=%d name=%s digit=%d (maxDigit=%d)", + vd.idx, images[vd.idx].name.c_str(), vd.digit, maxDigit); + } + } + DEBUG_EXTRA("[DisabledView] %zu views disabled (all with digit=%d)", + disabledViews.size(), maxDigit); + } // ---------- 初始化 ---------- faceViews.resize(virtualFaceMap.size()); @@ -17967,15 +18024,32 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( FIndex faceID = vf.faces[0]; if (faceID >= faceNeighbors.size()) continue; - std::unordered_set candidateViews; - for (FIndex fid : vf.faces) { - if (fid >= faceNeighbors.size()) continue; - for (IIndex vid : faceNeighbors[fid]) { - if (views.empty() || views.FindFirst(vid) != NO_ID) { - candidateViews.insert(vid); - } - } - } + std::unordered_set candidateViews; + for (FIndex fid : vf.faces) { + if (fid >= faceNeighbors.size()) continue; + for (IIndex vid : faceNeighbors[fid]) { + if (views.empty() || views.FindFirst(vid) != NO_ID) { + // ★ 排除禁用视图(优先选择小数字的视图) + if (disabledViews.count(vid) == 0) { + candidateViews.insert(vid); + } + } + } + } + + // ★ 如果候选视图为空,放宽限制允许禁用视图参与 + if (candidateViews.empty()) { + for (FIndex fid : vf.faces) { + if (fid >= faceNeighbors.size()) continue; + for (IIndex vid : faceNeighbors[fid]) { + if (views.empty() || views.FindFirst(vid) != NO_ID) { + candidateViews.insert(vid); + } + } + } + // DEBUG_EXTRA("[Fallback] pi=%zu: allowed disabled views, got %zu candidates", + // i, candidateViews.size()); + } if (candidateViews.empty()) { ++emptyCandidateViews;