Browse Source

从视图选择和光栅化进一步优化

ManualUV
hesuicong 1 week ago
parent
commit
453622d3f2
  1. 396
      libs/MVS/SceneTexture.cpp

396
libs/MVS/SceneTexture.cpp

@ -655,6 +655,7 @@ public:
float fRatioDataSmoothness, int nIgnoreMaskLabel, float fRatioDataSmoothness, int nIgnoreMaskLabel,
const IIndexArr& views); const IIndexArr& views);
// 简单的 view smoothing:如果某个面的 view 和多数邻居不同,且分数差距不大,就改成邻居的 view // 简单的 view smoothing:如果某个面的 view 和多数邻居不同,且分数差距不大,就改成邻居的 view
cv::Vec3f SampleFaceCenterColor(IIndex vid, const Point3f& faceCenter);
float ComputeViewNormalScore(const Mesh::Normal& faceNormal, const Camera& camera, const Point3f& faceCenter); float ComputeViewNormalScore(const Mesh::Normal& faceNormal, const Camera& camera, const Point3f& faceCenter);
float ComputeResolutionScore( float ComputeResolutionScore(
@ -15970,7 +15971,8 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches(
{ {
for (int x = 0; x < patchW; ++x) { for (int x = 0; x < patchW; ++x) {
cv::Vec3b color = remapped.at<cv::Vec3b>(y, x); cv::Vec3b color = remapped.at<cv::Vec3b>(y, x);
if (color[0] < 5 && color[1] < 5 && color[2] < 5) continue; if (color[0] == 0 && color[1] == 0 && color[2] == 0) continue;
int atlasX = x + minX, atlasY = y + minY; int atlasX = x + minX, atlasY = y + minY;
if (atlasX < 0 || atlasX >= textureSize || atlasY < 0 || atlasY >= textureSize) continue; if (atlasX < 0 || atlasX >= textureSize || atlasY < 0 || atlasY >= textureSize) continue;
// atlas(atlasY, atlasX) = Pixel8U{color[2], color[1], color[0]}; // atlas(atlasY, atlasX) = Pixel8U{color[2], color[1], color[0]};
@ -16357,8 +16359,7 @@ bool MeshTexture::RasterizeVirtualFaces(
for (int x = 0; x < patchW; ++x) { for (int x = 0; x < patchW; ++x) {
cv::Vec3b color = patch.at<cv::Vec3b>(y, x); cv::Vec3b color = patch.at<cv::Vec3b>(y, x);
// if (color[0]==0 && color[1]==0 && color[2]==0) continue; if (color[0] == 0 && color[1] == 0 && color[2] == 0) continue;
if (color[0] < 5 && color[1] < 5 && color[2] < 5) continue;
int atlasX = x + minX, atlasY = y + minY; int atlasX = x + minX, atlasY = y + minY;
if (atlasX<0||atlasX>=textureSize||atlasY<0||atlasY>=textureSize) continue; if (atlasX<0||atlasX>=textureSize||atlasY<0||atlasY>=textureSize) continue;
@ -17667,92 +17668,44 @@ int MeshTexture::ComputeOptimalTextureSizeAdaptive(
return textureSize; return textureSize;
} }
// 替换掉 g_avgColors[vid] 的用法
cv::Vec3f MeshTexture::SampleFaceCenterColor(IIndex vid, const Point3f& faceCenter) {
const Image& img = images[vid];
if (img.image.empty()) return cv::Vec3f(-1, -1, -1);
Point2f proj = img.camera.ProjectPoint(Point3d(faceCenter));
int px = (int)(proj.x + 0.5f), py = (int)(proj.y + 0.5f);
if (px < 0 || py < 0 || px >= img.image.cols || py >= img.image.rows)
return cv::Vec3f(-1, -1, -1);
const cv::Vec3b& c = img.image.at<cv::Vec3b>(py, px);
return cv::Vec3f(c[2]/255.0f, c[1]/255.0f, c[0]/255.0f); // BGR→RGB, normalize
}
// ============================================================ // ============================================================
// 5. SelectBestViewsForVirtualFaces(修复版) // 5. SelectBestViewsForVirtualFaces(修复版)
// ============================================================ // ============================================================
// ============================================================
// 5. SelectBestViewsForVirtualFaces(局部采样颜色版)
// ============================================================
// 前置条件:MeshTexture 类中需声明并定义 SampleFaceCenterColor:
// cv::Vec3f SampleFaceCenterColor(IIndex vid, const Point3f& faceCenter) const;
// 实现见下方附录
// ============================================================
bool MeshTexture::SelectBestViewsForVirtualFaces( bool MeshTexture::SelectBestViewsForVirtualFaces(
VirtualFaceMap& virtualFaceMap, VirtualFaceMap& virtualFaceMap,
unsigned minCommonCameras, float fOutlierThreshold, unsigned minCommonCameras, float fOutlierThreshold,
float fRatioDataSmoothness, int nIgnoreMaskLabel, float fRatioDataSmoothness, int nIgnoreMaskLabel,
const IIndexArr& views) const IIndexArr& views)
{ {
VERBOSE("4[EnterSelect] faceFaces.empty=%d faceFaces.size=%d faceNeighbors.empty=%d", VERBOSE("4[EnterSelect] faceFaces.empty=%d faceFaces.size=%d faceNeighbors.empty=%d",
(int)scene.mesh.faceFaces.empty(), (int)scene.mesh.faceFaces.empty(),
(int)scene.mesh.faceFaces.size(), (int)scene.mesh.faceFaces.size(),
(int)faceNeighbors.empty()); (int)faceNeighbors.empty());
DEBUG_EXTRA("Selecting best views for %zu virtual faces", virtualFaceMap.size()); DEBUG_EXTRA("Selecting best views for %zu virtual faces", virtualFaceMap.size());
static std::vector<cv::Vec3f> g_avgColors;
// ===== 从磁盘加载图像,计算全局平均颜色 =====
static bool g_avgColorsComputed = false;
// if (!g_avgColorsComputed) {
// const size_t numViews = images.size(); // ← 你的变量名
// g_avgColors.resize(numViews, cv::Vec3f(-1, -1, -1));
// for (size_t vid = 0; vid < numViews; ++vid) {
// const std::string& imgPath = images[vid].name; // ← 你的字段名
// cv::Mat img = cv::imread(imgPath, cv::IMREAD_COLOR);
// if (img.empty()) {
// VERBOSE("[AvgColor] view %zu: cannot load '%s'", vid, imgPath.c_str());
// continue;
// }
// // 直接转 float 算均值,不 resize
// cv::Mat imgF;
// img.convertTo(imgF, CV_32FC3, 1.0 / 255.0);
// cv::Scalar mean = cv::mean(imgF);
// g_avgColors[vid] = cv::Vec3f(mean[0], mean[1], mean[2]);
// VERBOSE("[AvgColor] view %zu: mean=(%.3f,%.3f,%.3f)",
// vid, mean[0], mean[1], mean[2]);
// }
// g_avgColorsComputed = true;
// VERBOSE("[AvgColor] Done: [0]=(%.3f,%.3f,%.3f)",
// g_avgColors[0][0], g_avgColors[0][1], g_avgColors[0][2]);
// }
g_avgColorsComputed = false;
if (!g_avgColorsComputed) {
g_avgColors.assign(images.size(), cv::Vec3f(-1, -1, -1));
for (size_t vid = 0; vid < images.size(); ++vid) {
const cv::Mat& img = images[vid].image; // ★ 直接用内存图像
if (img.empty()) continue;
cv::Mat imgF;
img.convertTo(imgF, CV_32FC3, 1.0 / 255.0);
cv::Scalar mean = cv::mean(imgF);
g_avgColors[vid] = cv::Vec3f(mean[0], mean[1], mean[2]); // BGR
}
g_avgColorsComputed = true;
VERBOSE("[AvgColor] Done: [0]=(%.3f,%.3f,%.3f), [1]=(%.3f,%.3f,%.3f)",
g_avgColors[0][0], g_avgColors[0][1], g_avgColors[0][2],
g_avgColors[1][0], g_avgColors[1][1], g_avgColors[1][2]);
}
if (g_avgColors.empty()) {
g_avgColors.resize(images.size(), cv::Vec3f(-1, -1, -1));
for (size_t v = 0; v < images.size(); ++v) {
const cv::Mat& m = images[v].image;
if (m.empty()) continue;
cv::Scalar meanColor = cv::mean(m);
g_avgColors[v] = cv::Vec3f(meanColor[0] / 255.0f, meanColor[1] / 255.0f, meanColor[2] / 255.0f);
}
VERBOSE("[AvgColor] Precomputed average colors for %zu images", images.size());
// 调试:打印 g_avgColors 内容
VERBOSE("[AvgColorDebug] g_avgColors.size=%d, [0]=(%.1f,%.1f,%.1f), [1]=(%.1f,%.1f,%.1f), [78]=(%.1f,%.1f,%.1f)",
(int)g_avgColors.size(),
g_avgColors[0][0], g_avgColors[0][1], g_avgColors[0][2],
g_avgColors[1][0], g_avgColors[1][1], g_avgColors[1][2],
g_avgColors[78][0], g_avgColors[78][1], g_avgColors[78][2]);
}
// ---------- 初始化 ----------
faceViews.resize(virtualFaceMap.size()); faceViews.resize(virtualFaceMap.size());
faceViewWeights.resize(virtualFaceMap.size()); faceViewWeights.resize(virtualFaceMap.size());
for (auto& v : faceViews) v.clear(); for (auto& v : faceViews) v.clear();
for (auto& w : faceViewWeights) w.clear(); for (auto& w : faceViewWeights) w.clear();
@ -17766,46 +17719,45 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(
std::vector<IIndex> faceToView(scene.mesh.faces.size(), NO_ID); std::vector<IIndex> faceToView(scene.mesh.faces.size(), NO_ID);
std::vector<float> faceScores(scene.mesh.faces.size(), -FLT_MAX); std::vector<float> faceScores(scene.mesh.faces.size(), -FLT_MAX);
if (scene.mesh.faceFaces.empty()) { if (scene.mesh.faceFaces.empty()) {
scene.mesh.ListIncidenteFaceFaces(); scene.mesh.ListIncidenteFaceFaces();
} }
VERBOSE("5[AfterVis] faceFaces.empty=%d faceFaces.size=%d faceFaces[0]={%u,%u,%u}", VERBOSE("5[AfterVis] faceFaces.empty=%d faceFaces.size=%d faceFaces[0]={%u,%u,%u}",
(int)scene.mesh.faceFaces.empty(), (int)scene.mesh.faceFaces.empty(),
(int)scene.mesh.faceFaces.size(), (int)scene.mesh.faceFaces.size(),
scene.mesh.faceFaces.empty() ? 0xFFFFFFFF : scene.mesh.faceFaces[0][0], scene.mesh.faceFaces.empty() ? 0xFFFFFFFF : scene.mesh.faceFaces[0][0],
scene.mesh.faceFaces.empty() ? 0xFFFFFFFF : scene.mesh.faceFaces[0][1], scene.mesh.faceFaces.empty() ? 0xFFFFFFFF : scene.mesh.faceFaces[0][1],
scene.mesh.faceFaces.empty() ? 0xFFFFFFFF : scene.mesh.faceFaces[0][2]); scene.mesh.faceFaces.empty() ? 0xFFFFFFFF : scene.mesh.faceFaces[0][2]);
// ★★★ 关键修复:从 faceFaces 构建 faceNeighbors(virtual face 邻接)★★★ // ★★★ 从 faceFaces 构建 faceNeighbors(virtual face 邻接)★★★
if (faceNeighbors.empty()) { if (faceNeighbors.empty()) {
faceNeighbors.resize(virtualFaceMap.size()); faceNeighbors.resize(virtualFaceMap.size());
for (size_t fid = 0; fid < virtualFaceMap.size(); ++fid) { for (size_t fid = 0; fid < virtualFaceMap.size(); ++fid) {
if (fid >= scene.mesh.faceFaces.size()) break; if (fid >= scene.mesh.faceFaces.size()) break;
const Mesh::FaceFaces& ff = scene.mesh.faceFaces[fid]; // 原始面邻接 const Mesh::FaceFaces& ff = scene.mesh.faceFaces[fid];
for (int k = 0; k < 3; ++k) { for (int k = 0; k < 3; ++k) {
FIndex nb = ff[k]; FIndex nb = ff[k];
if (nb == NO_ID || nb >= (FIndex)virtualFaceMap.size()) continue; if (nb == NO_ID || nb >= (FIndex)virtualFaceMap.size()) continue;
// 去重插入 bool exists = false;
bool exists = false; for (IIndex existing : faceNeighbors[fid]) {
for (IIndex existing : faceNeighbors[fid]) { if ((FIndex)existing == nb) { exists = true; break; }
if ((FIndex)existing == nb) { exists = true; break; } }
} if (!exists) faceNeighbors[fid].push_back((IIndex)nb);
if (!exists) faceNeighbors[fid].push_back((IIndex)nb); }
} }
} DEBUG_EXTRA("[SelectBest] faceNeighbors built: size=%zu, avg=%f",
DEBUG_EXTRA("[SelectBest] faceNeighbors built: size=%zu, avg=%f", faceNeighbors.size(),
faceNeighbors.size(), faceNeighbors.size() > 0 ?
faceNeighbors.size() > 0 ? (double)std::accumulate(faceNeighbors.begin(), faceNeighbors.end(), 0ull,
(double)std::accumulate(faceNeighbors.begin(), faceNeighbors.end(), 0ull, [](size_t s, const auto& v) { return s + v.size(); }) / faceNeighbors.size() : 0);
[](size_t s, const auto& v) { return s + v.size(); }) / faceNeighbors.size() : 0); }
}
// ---------- 1. 初始视图分配 ---------- // ---------- 1. 初始视图分配 ----------
size_t emptyCandidateViews = 0; size_t emptyCandidateViews = 0;
size_t fallbackByCenterFace = 0; size_t fallbackByCenterFace = 0;
size_t successVF = 0; size_t successVF = 0;
for (size_t i = 0; i < virtualFaceMap.size(); ++i) { for (size_t i = 0; i < virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i]; const VirtualFace& vf = virtualFaceMap[i];
if (vf.faces.empty()) continue; if (vf.faces.empty()) continue;
@ -17881,67 +17833,59 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(
float s_occlusion = ComputeOcclusionPenalty( float s_occlusion = ComputeOcclusionPenalty(
p0, p1, p2, img.image.cols, img.image.rows, 8); p0, p1, p2, img.image.cols, img.image.rows, 8);
float rawScore = 3.0f * s_normal // 正视角优先 float rawScore = 3.0f * s_normal
+ 0.5f * s_resolution + 0.5f * s_resolution
- 0.1f * s_occlusion; - 0.1f * s_occlusion;
float score = rawScore; float score = rawScore;
// ========== 颜色一致性代价 ========== // ========== 颜色一致性代价(局部采样版)==========
{ {
const float lambda = 100.0f; const float lambda = 0.5f; // 从 100 降到 0.5
// ========== 收集邻居颜色(修复版:1-ring + faceToView)==========
std::vector<cv::Vec3f> neighborColors; // 采样当前候选视图下面中心的颜色
if (!scene.mesh.faceFaces.empty() && faceID < scene.mesh.faceFaces.size()) { cv::Vec3f candidateColor = SampleFaceCenterColor(vid, faceCenter);
const Mesh::Face& topoNeighbors = scene.mesh.faceFaces[faceID]; if (candidateColor[0] < 0) {
for (int k = 0; k < 3; ++k) { // 投影失败,跳过颜色代价但不 return
FIndex nb = topoNeighbors[k]; // 保持 score 不变
if (nb == NO_ID || nb >= (FIndex)faceToView.size()) continue; } else {
// 收集邻居颜色:已分配的面,采样邻居面中心在邻居视图下的颜色
IIndex nbView = faceToView[nb]; std::vector<cv::Vec3f> neighborColors;
if (nbView == NO_ID) { if (!scene.mesh.faceFaces.empty() && faceID < scene.mesh.faceFaces.size()) {
// fallback: 邻居还没分配 view,用第一个可见相机 const Mesh::FaceFaces& topoNeighbors = scene.mesh.faceFaces[faceID];
if (nb < (FIndex)faceNeighbors.size() && !faceNeighbors[nb].empty()) { for (int k = 0; k < 3; ++k) {
nbView = faceNeighbors[nb][0]; FIndex nb = topoNeighbors[k];
if (nb == NO_ID || nb >= (FIndex)faceToView.size()) continue;
IIndex nbView = faceToView[nb];
if (nbView == NO_ID) {
if (nb < (FIndex)faceNeighbors.size() && !faceNeighbors[nb].empty()) {
nbView = faceNeighbors[nb][0];
}
} }
} if (nbView == NO_ID || nbView >= (IIndex)images.size()) continue;
if (nbView != NO_ID && nbView < (IIndex)g_avgColors.size()) {
const cv::Vec3f& nc = g_avgColors[nbView]; // 计算邻居面中心
if (nc[0] >= 0) { // 有效颜色才收集 const Mesh::Face& nbFace = scene.mesh.faces[nb];
neighborColors.push_back(nc); Point3f nbCenter = (scene.mesh.vertices[nbFace[0]] +
scene.mesh.vertices[nbFace[1]] +
scene.mesh.vertices[nbFace[2]]) / 3.0f;
cv::Vec3f nbColor = SampleFaceCenterColor(nbView, nbCenter);
if (nbColor[0] >= 0) {
neighborColors.push_back(nbColor);
} }
} }
} }
}
// ========== 修复结束 ========== float colorDiff = 0.0f;
if (!neighborColors.empty()) {
float colorDiff = 0.0f;
if (!neighborColors.empty()) {
cv::Vec3f candidateColor = g_avgColors[vid];
// cv::Vec3f candidateColor = SampleColorAtPoint(images[vid].image, images[vid].camera, faceCenter);
if (faceID == 50000) {
if (candidateColor[0] < 0) {
VERBOSE("[ColorDebug] face=50000 vid=%d -> candidateColor FAILED (val=%.1f,%.1f,%.1f)",
(int)vid, candidateColor[0], candidateColor[1], candidateColor[2]);
}
// 同时打印 g_avgColors[vid] 的原始值
if (vid < g_avgColors.size()) {
VERBOSE("[ColorDebug] g_avgColors[%d] = (%.1f,%.1f,%.1f)",
(int)vid, g_avgColors[vid][0], g_avgColors[vid][1], g_avgColors[vid][2]);
} else {
VERBOSE("[ColorDebug] vid=%d OUT OF BOUNDS! g_avgColors.size=%d",
(int)vid, (int)g_avgColors.size());
}
}
if (candidateColor[0] >= 0) {
for (const auto& nc : neighborColors) { for (const auto& nc : neighborColors) {
cv::Vec3f d = candidateColor - nc; cv::Vec3f d = candidateColor - nc;
colorDiff += std::sqrt(d[0]*d[0] + d[1]*d[1] + d[2]*d[2]); colorDiff += std::sqrt(d[0]*d[0] + d[1]*d[1] + d[2]*d[2]);
} }
// colorDiff = (colorDiff / neighborColors.size()) / 1.732f;
colorDiff = colorDiff / neighborColors.size(); colorDiff = colorDiff / neighborColors.size();
colorDiff = std::min(colorDiff, 1.0f); colorDiff = std::min(colorDiff, 1.0f);
// ✅ 修复:不再乘 score,避免放大效应
score -= lambda * colorDiff; score -= lambda * colorDiff;
} }
} }
@ -17950,10 +17894,8 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(
static int g_dbg = 0; static int g_dbg = 0;
g_dbg++; g_dbg++;
if (g_dbg <= 20 || faceID % 50000 == 0) { if (g_dbg <= 20 || faceID % 50000 == 0) {
VERBOSE("[Score] face=%d view=%d rawScore=%.3f nbrColors=%d " VERBOSE("[Score] face=%d view=%d rawScore=%.3f finalScore=%.3f",
"colorDiff=%.3f penalty=%.3f finalScore=%.3f", faceID, vid, rawScore, score);
faceID, vid, rawScore, (int)neighborColors.size(),
colorDiff, lambda * colorDiff, score);
} }
} }
// ========== 颜色代价结束 ========== // ========== 颜色代价结束 ==========
@ -17978,67 +17920,61 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(
} }
// ---------- 2. 改进的 Patch 一致性传播 ---------- // ---------- 2. 改进的 Patch 一致性传播 ----------
const int PROPAGATION_ITER = 6;
for (int iter = 0; iter < PROPAGATION_ITER; ++iter) {
std::vector<IIndex> newFaceToView = faceToView;
std::vector<float> newFaceScores = faceScores;
const int PROPAGATION_ITER = 6; // 从2改到6 for (FIndex fid = 0; fid < (FIndex)faceToView.size(); ++fid) {
for (int iter = 0; iter < PROPAGATION_ITER; ++iter) { if (faceToView[fid] == NO_ID) continue;
std::vector<IIndex> newFaceToView = faceToView; if (fid >= (FIndex)scene.mesh.faceFaces.size()) continue;
std::vector<float> newFaceScores = faceScores;
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]; const Mesh::FaceFaces& neighbors = scene.mesh.faceFaces[fid];
float currentScore = faceScores[fid]; float currentScore = faceScores[fid];
// ★ 放宽:只锁死 > 0.95 的极高分明面,其余都允许被传播覆盖 if (currentScore > 0.95f) continue;
if (currentScore > 0.95f) continue;
std::unordered_map<IIndex, int> vote; std::unordered_map<IIndex, int> vote;
vote[faceToView[fid]] = 1; vote[faceToView[fid]] = 1;
for (int k = 0; k < 3; ++k) { for (int k = 0; k < 3; ++k) {
FIndex nb = neighbors[k]; FIndex nb = neighbors[k];
if (nb == NO_ID) continue; if (nb == NO_ID) continue;
if (nb < (FIndex)faceToView.size() && faceToView[nb] != NO_ID) { if (nb < (FIndex)faceToView.size() && faceToView[nb] != NO_ID) {
vote[faceToView[nb]]++; vote[faceToView[nb]]++;
} }
} }
IIndex majorityView = faceToView[fid]; IIndex majorityView = faceToView[fid];
int maxVote = 0; int maxVote = 0;
for (const auto& v : vote) { for (const auto& v : vote) {
if (v.second > maxVote) { if (v.second > maxVote) {
maxVote = v.second; maxVote = v.second;
majorityView = v.first; majorityView = v.first;
} }
} }
// ★ 放宽:只要多数票 >= 2 且和我不一样,就考虑切换(原来是 >= 3) if (maxVote >= 2 && majorityView != faceToView[fid]) {
if (maxVote >= 2 && majorityView != faceToView[fid]) { float majorityAvgScore = 0.0f;
// 计算多数view在邻居中的平均评分 int count = 0;
float majorityAvgScore = 0.0f; for (int k = 0; k < 3; ++k) {
int count = 0; FIndex nb = neighbors[k];
for (int k = 0; k < 3; ++k) { if (nb == NO_ID) continue;
FIndex nb = neighbors[k]; if (nb < (FIndex)faceToView.size() && faceToView[nb] == majorityView) {
if (nb == NO_ID) continue; majorityAvgScore += faceScores[nb];
if (nb < (FIndex)faceToView.size() && faceToView[nb] == majorityView) { count++;
majorityAvgScore += faceScores[nb]; }
count++; }
} if (count > 0) majorityAvgScore /= count;
}
if (count > 0) majorityAvgScore /= count;
// ★ 简化:去掉颜色阻断,直接让评分说话 if (majorityAvgScore > currentScore - 0.5f) {
// 只要多数view的平均分不低于我太多(差 < 0.3),就切换 newFaceToView[fid] = majorityView;
if (majorityAvgScore > currentScore - 0.5f) { newFaceScores[fid] = majorityAvgScore;
newFaceToView[fid] = majorityView; }
newFaceScores[fid] = majorityAvgScore; }
} }
} faceToView.swap(newFaceToView);
} faceScores.swap(newFaceScores);
faceToView.swap(newFaceToView); }
faceScores.swap(newFaceScores);
}
// ---------- 3. 写回 ---------- // ---------- 3. 写回 ----------
for (size_t i = 0; i < virtualFaceMap.size(); ++i) { for (size_t i = 0; i < virtualFaceMap.size(); ++i) {
@ -18054,27 +17990,27 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(
} }
} }
// 在写回循环之后,加这个: // 后处理:再跑几轮简单投票
for (int iter = 0; iter < 3; ++iter) { for (int iter = 0; iter < 3; ++iter) {
auto newFaceToView = faceToView; auto newFaceToView = faceToView;
for (size_t i = 0; i < faceToView.size(); ++i) { for (size_t i = 0; i < faceToView.size(); ++i) {
if (faceToView[i] == NO_ID) continue; if (faceToView[i] == NO_ID) continue;
std::map<IIndex, int> vote; std::map<IIndex, int> vote;
const auto& ff = scene.mesh.faceFaces[i]; const auto& ff = scene.mesh.faceFaces[i];
for (int k = 0; k < 3; ++k) { for (int k = 0; k < 3; ++k) {
FIndex nb = ff[k]; FIndex nb = ff[k];
if (nb < (FIndex)faceToView.size() && faceToView[nb] != NO_ID) if (nb < (FIndex)faceToView.size() && faceToView[nb] != NO_ID)
vote[faceToView[nb]]++; vote[faceToView[nb]]++;
} }
if (vote.size() <= 1) continue; if (vote.size() <= 1) continue;
auto best = std::max_element(vote.begin(), vote.end(), auto best = std::max_element(vote.begin(), vote.end(),
[](const std::pair<IIndex, int>& a, const std::pair<IIndex, int>& b) { [](const std::pair<IIndex, int>& a, const std::pair<IIndex, int>& b) {
return a.second < b.second; }); return a.second < b.second; });
if (best->first != faceToView[i] && best->second >= 2) if (best->first != faceToView[i] && best->second >= 2)
newFaceToView[i] = best->first; newFaceToView[i] = best->first;
} }
faceToView.swap(newFaceToView); faceToView.swap(newFaceToView);
} }
DEBUG_EXTRA("====== Virtual Face View Selection Summary ======"); DEBUG_EXTRA("====== Virtual Face View Selection Summary ======");
DEBUG_EXTRA("Total virtual faces : %zu", virtualFaceMap.size()); DEBUG_EXTRA("Total virtual faces : %zu", virtualFaceMap.size());

Loading…
Cancel
Save