|
|
|
@ -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,9 +17668,28 @@ 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, |
|
|
|
@ -17682,77 +17702,10 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( |
|
|
|
(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(); |
|
|
|
|
|
|
|
|
|
|
|
@ -17777,16 +17730,15 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( |
|
|
|
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; } |
|
|
|
@ -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)==========
|
|
|
|
|
|
|
|
|
|
|
|
// 采样当前候选视图下面中心的颜色
|
|
|
|
|
|
|
|
cv::Vec3f candidateColor = SampleFaceCenterColor(vid, faceCenter); |
|
|
|
|
|
|
|
if (candidateColor[0] < 0) { |
|
|
|
|
|
|
|
// 投影失败,跳过颜色代价但不 return
|
|
|
|
|
|
|
|
// 保持 score 不变
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// 收集邻居颜色:已分配的面,采样邻居面中心在邻居视图下的颜色
|
|
|
|
std::vector<cv::Vec3f> neighborColors; |
|
|
|
std::vector<cv::Vec3f> neighborColors; |
|
|
|
if (!scene.mesh.faceFaces.empty() && faceID < scene.mesh.faceFaces.size()) { |
|
|
|
if (!scene.mesh.faceFaces.empty() && faceID < scene.mesh.faceFaces.size()) { |
|
|
|
const Mesh::Face& topoNeighbors = scene.mesh.faceFaces[faceID]; |
|
|
|
const Mesh::FaceFaces& topoNeighbors = scene.mesh.faceFaces[faceID]; |
|
|
|
for (int k = 0; k < 3; ++k) { |
|
|
|
for (int k = 0; k < 3; ++k) { |
|
|
|
FIndex nb = topoNeighbors[k]; |
|
|
|
FIndex nb = topoNeighbors[k]; |
|
|
|
if (nb == NO_ID || nb >= (FIndex)faceToView.size()) continue; |
|
|
|
if (nb == NO_ID || nb >= (FIndex)faceToView.size()) continue; |
|
|
|
|
|
|
|
|
|
|
|
IIndex nbView = faceToView[nb]; |
|
|
|
IIndex nbView = faceToView[nb]; |
|
|
|
if (nbView == NO_ID) { |
|
|
|
if (nbView == NO_ID) { |
|
|
|
// fallback: 邻居还没分配 view,用第一个可见相机
|
|
|
|
|
|
|
|
if (nb < (FIndex)faceNeighbors.size() && !faceNeighbors[nb].empty()) { |
|
|
|
if (nb < (FIndex)faceNeighbors.size() && !faceNeighbors[nb].empty()) { |
|
|
|
nbView = faceNeighbors[nb][0]; |
|
|
|
nbView = faceNeighbors[nb][0]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (nbView != NO_ID && nbView < (IIndex)g_avgColors.size()) { |
|
|
|
if (nbView == NO_ID || nbView >= (IIndex)images.size()) continue; |
|
|
|
const cv::Vec3f& nc = g_avgColors[nbView]; |
|
|
|
|
|
|
|
if (nc[0] >= 0) { // 有效颜色才收集
|
|
|
|
// 计算邻居面中心
|
|
|
|
neighborColors.push_back(nc); |
|
|
|
const Mesh::Face& nbFace = scene.mesh.faces[nb]; |
|
|
|
} |
|
|
|
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; |
|
|
|
float colorDiff = 0.0f; |
|
|
|
if (!neighborColors.empty()) { |
|
|
|
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,8 +17920,7 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ---------- 2. 改进的 Patch 一致性传播 ----------
|
|
|
|
// ---------- 2. 改进的 Patch 一致性传播 ----------
|
|
|
|
|
|
|
|
const int PROPAGATION_ITER = 6; |
|
|
|
const int PROPAGATION_ITER = 6; // 从2改到6
|
|
|
|
|
|
|
|
for (int iter = 0; iter < PROPAGATION_ITER; ++iter) { |
|
|
|
for (int iter = 0; iter < PROPAGATION_ITER; ++iter) { |
|
|
|
std::vector<IIndex> newFaceToView = faceToView; |
|
|
|
std::vector<IIndex> newFaceToView = faceToView; |
|
|
|
std::vector<float> newFaceScores = faceScores; |
|
|
|
std::vector<float> newFaceScores = faceScores; |
|
|
|
@ -17988,10 +17929,9 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( |
|
|
|
if (faceToView[fid] == NO_ID) continue; |
|
|
|
if (faceToView[fid] == NO_ID) continue; |
|
|
|
if (fid >= (FIndex)scene.mesh.faceFaces.size()) 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; |
|
|
|
@ -18013,9 +17953,7 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ★ 放宽:只要多数票 >= 2 且和我不一样,就考虑切换(原来是 >= 3)
|
|
|
|
|
|
|
|
if (maxVote >= 2 && majorityView != faceToView[fid]) { |
|
|
|
if (maxVote >= 2 && majorityView != faceToView[fid]) { |
|
|
|
// 计算多数view在邻居中的平均评分
|
|
|
|
|
|
|
|
float majorityAvgScore = 0.0f; |
|
|
|
float majorityAvgScore = 0.0f; |
|
|
|
int count = 0; |
|
|
|
int count = 0; |
|
|
|
for (int k = 0; k < 3; ++k) { |
|
|
|
for (int k = 0; k < 3; ++k) { |
|
|
|
@ -18028,8 +17966,6 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( |
|
|
|
} |
|
|
|
} |
|
|
|
if (count > 0) majorityAvgScore /= count; |
|
|
|
if (count > 0) majorityAvgScore /= count; |
|
|
|
|
|
|
|
|
|
|
|
// ★ 简化:去掉颜色阻断,直接让评分说话
|
|
|
|
|
|
|
|
// 只要多数view的平均分不低于我太多(差 < 0.3),就切换
|
|
|
|
|
|
|
|
if (majorityAvgScore > currentScore - 0.5f) { |
|
|
|
if (majorityAvgScore > currentScore - 0.5f) { |
|
|
|
newFaceToView[fid] = majorityView; |
|
|
|
newFaceToView[fid] = majorityView; |
|
|
|
newFaceScores[fid] = majorityAvgScore; |
|
|
|
newFaceScores[fid] = majorityAvgScore; |
|
|
|
@ -18054,7 +17990,7 @@ 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) { |
|
|
|
|