Browse Source

清晰化

ManualUV
hesuicong 3 weeks ago
parent
commit
af1c3c0510
  1. 210
      libs/MVS/SceneTexture.cpp

210
libs/MVS/SceneTexture.cpp

@ -14606,10 +14606,8 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap, @@ -14606,10 +14606,8 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
m_virtualFaceGeometries.Resize(virtualFaceMap.size());
}
for (auto& viewList : faceViews)
viewList.clear();
for (auto& weightList : faceViewWeights)
weightList.clear();
for (auto& viewList : faceViews) viewList.clear();
for (auto& weightList : faceViewWeights) weightList.clear();
// ===== Debug 统计 =====
size_t emptyCandidateViews = 0;
@ -14617,128 +14615,142 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap, @@ -14617,128 +14615,142 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
size_t fallbackByCenterFace = 0;
size_t successVF = 0;
// ✅ 面片 → 视图 映射表
std::vector<IIndex> faceToView(scene.mesh.faces.size(), NO_ID);
// ----------------------------------------------------------------
// 1. 初始视图分配
// ----------------------------------------------------------------
for (size_t i = 0; i < virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i];
FIndex faceID2 = vf.faces[0];
if (faceID2 >= faceNeighbors.size()) {
DEBUG_EXTRA("FATAL: faceID %u out of range!", faceID2);
continue;
}
if (vf.faces.empty()) continue;
if (faceNeighbors[faceID2].empty()) {
// DEBUG_EXTRA("FATAL: faceNeighbors[%u] is empty! FaceViewSelection mode error.", faceID2);
}
FIndex faceID2 = vf.faces[0];
if (faceID2 >= faceNeighbors.size()) {
DEBUG_EXTRA("FATAL: faceID %u out of range!", faceID2);
continue;
}
//------------------------------------------------------------------
// 1. 收集每个面片的候选视图
//------------------------------------------------------------------
// 收集候选视图
std::unordered_set<IIndex> candidateViews;
std::vector<std::vector<IIndex>> faceViewCandidates(vf.faces.size());
for (size_t j = 0; j < vf.faces.size(); ++j) {
FIndex faceID = vf.faces[j];
if (faceID >= faceNeighbors.size())
continue;
for (FIndex faceID : vf.faces) {
if (faceID >= faceNeighbors.size()) continue;
for (IIndex viewID : faceNeighbors[faceID]) {
if (views.empty() || views.FindFirst(viewID) != NO_ID) {
candidateViews.insert(viewID);
faceViewCandidates[j].push_back(viewID);
}
}
}
//------------------------------------------------------------------
// 2. 【终极兜底】候选视图为空 → 强制分配一个视图
// 物理遮挡不重要,逻辑可见性最重要
//------------------------------------------------------------------
if (candidateViews.empty()) {
++emptyCandidateViews;
// ------------------------------------------------------------
// 2. 兜底:候选视图为空
// ------------------------------------------------------------
if (candidateViews.empty()) {
++emptyCandidateViews;
// 找一个可用的相机ID
// 优先级:views参数指定的 > 所有images中的第一个
IIndex forcedView = NO_ID;
IIndex forcedView = NO_ID;
if (!views.empty()) {
forcedView = views[0];
} else if (!images.empty()) {
forcedView = 0;
}
if (!views.empty()) {
forcedView = views[0];
} else if (!images.empty()) {
forcedView = 0;
}
if (forcedView != NO_ID) {
faceViews[i].push_back(forcedView);
faceViewWeights[i].push_back(1.0f);
if (forcedView != NO_ID) {
faceViews[i].push_back(forcedView);
faceViewWeights[i].push_back(1.0f);
++fallbackByCenterFace;
for (FIndex fid : vf.faces) {
if (fid < faceToView.size())
faceToView[fid] = forcedView;
}
// 降低日志级别,避免刷屏,用 DEBUG 而非 EXTRA
// DEBUG("VF[%zu] EMPTY -> FORCED view %d (ignoring physical occlusion)",
// i, forcedView);
continue;
}
++fallbackByCenterFace;
continue;
}
// 实在没救(连images都没有),这才跳过
DEBUG_EXTRA("VF[%zu] truly hopeless: no images available", i);
continue;
}
DEBUG_EXTRA("VF[%zu] truly hopeless: no images available", i);
continue;
}
//------------------------------------------------------------------
// 3. 【关键放松】不再强求“所有面片共视”
// 只要视图能看到任意一个面片即可
//------------------------------------------------------------------
std::vector<IIndex> usableViews(
candidateViews.begin(), candidateViews.end()
);
// ------------------------------------------------------------
// 3. 选择最佳视图(简单策略:第一个候选)
// ------------------------------------------------------------
IIndex bestView = *candidateViews.begin();
// (可选)按质量排序,取前 N 个
// std::sort(usableViews.begin(), usableViews.end(),
// [&](IIndex a, IIndex b) { return Quality(a) > Quality(b); });
faceViews[i].push_back(bestView);
faceViewWeights[i].push_back(1.0f);
if (usableViews.size() < minCommonCameras) {
faceViews[i] = usableViews;
} else {
// 仍尊重 minCommonCameras,但不强求共视
faceViews[i].assign(
usableViews.begin(),
usableViews.begin() + minCommonCameras
);
}
//------------------------------------------------------------------
// 4. 【二次兜底】usableViews 为空(理论上不会发生)
//------------------------------------------------------------------
if (faceViews[i].empty()) {
++emptyCommonViews;
if (!vf.faces.empty()) {
FIndex centerFace = vf.faces[0];
if (centerFace < faceNeighbors.size() &&
!faceNeighbors[centerFace].empty()) {
IIndex bestView = faceNeighbors[centerFace][0];
faceViews[i].push_back(bestView);
faceViewWeights[i].push_back(1.0f);
DEBUG_EXTRA("VF[%zu] empty usableViews -> force view %d",
i, bestView);
continue;
for (FIndex fid : vf.faces) {
if (fid < faceToView.size())
faceToView[fid] = bestView;
}
++successVF;
}
// ----------------------------------------------------------------
// 4. 【轻量 Patch 一致性传播】
// ----------------------------------------------------------------
if (scene.mesh.faceFaces.empty()) {
scene.mesh.ListIncidenteFaceFaces();
}
const int PROPAGATION_ITER = 2;
for (int iter = 0; iter < PROPAGATION_ITER; ++iter) {
std::vector<IIndex> newFaceToView = faceToView;
for (FIndex fid = 0; fid < (FIndex)faceToView.size(); ++fid) {
if (faceToView[fid] == NO_ID) continue;
if (fid >= (FIndex)scene.mesh.faceFaces.size()) continue;
const Mesh::Face& neighbors = scene.mesh.faceFaces[fid];
std::unordered_map<IIndex, int> vote;
vote[faceToView[fid]] = 1;
for (int k = 0; k < 3; ++k) {
FIndex nb = neighbors[k];
if (nb == NO_ID) continue;
if (nb < (FIndex)faceToView.size() && faceToView[nb] != NO_ID) {
vote[faceToView[nb]]++;
}
}
continue;
IIndex majorityView = faceToView[fid];
int maxVote = 0;
for (const auto& v : vote) {
if (v.second > maxVote) {
maxVote = v.second;
majorityView = v.first;
}
}
if (maxVote >= 3 && majorityView != faceToView[fid]) {
newFaceToView[fid] = majorityView;
}
}
//------------------------------------------------------------------
// 5. 权重分配(均等,最稳定)
//------------------------------------------------------------------
float weight = 1.0f / static_cast<float>(faceViews[i].size());
faceViewWeights[i].resize(faceViews[i].size(), weight);
faceToView.swap(newFaceToView);
}
++successVF;
// ----------------------------------------------------------------
// 5. 根据传播后的结果,更新 virtual face 的视图
// ----------------------------------------------------------------
for (size_t i = 0; i < virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i];
if (vf.faces.empty() || faceViews[i].empty()) continue;
FIndex firstFace = vf.faces[0];
if (firstFace < faceToView.size() && faceToView[firstFace] != NO_ID) {
IIndex consistentView = faceToView[firstFace];
faceViews[i] = {consistentView};
faceViewWeights[i] = {1.0f};
}
}
//--------------------------------------------------------------------------
// 6. Debug 汇总(非常重要)
//--------------------------------------------------------------------------
// ----------------------------------------------------------------
// 6. Debug 汇总
// ----------------------------------------------------------------
DEBUG_EXTRA("====== Virtual Face View Selection Summary ======");
DEBUG_EXTRA("Total virtual faces : %zu", virtualFaceMap.size());
DEBUG_EXTRA("Successfully assigned : %zu", successVF);

Loading…
Cancel
Save