Browse Source

修正一些问题

ManualUV
hesuicong 3 weeks ago
parent
commit
1fe47d9448
  1. 451
      libs/MVS/SceneTexture.cpp

451
libs/MVS/SceneTexture.cpp

@ -606,7 +606,7 @@ public: @@ -606,7 +606,7 @@ public:
bool FaceViewSelectionWithVirtualFaces(unsigned minCommonCameras, float fOutlierThreshold,
float fRatioDataSmoothness, int nIgnoreMaskLabel,
const IIndexArr& views, bool bUseExistingUV);
bool ComputePureFaceVisibility(float fOutlierThreshold, int nIgnoreMaskLabel, const IIndexArr& views);
bool GenerateTextureWithVirtualFaces(bool bGlobalSeamLeveling, bool bLocalSeamLeveling,
unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic,
Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize,
@ -6948,7 +6948,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT @@ -6948,7 +6948,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT
// printf("FaceViewSelection3 2 scene.mesh.vertices.size=%d\n", scene.mesh.vertices.size());
bool bUseVirtualFaces(minCommonCameras > 0);
bUseVirtualFaces = false;
// bUseVirtualFaces = false;
// list all views for each face
FaceDataViewArr facesDatas;
@ -12784,7 +12784,7 @@ float MeshTexture::ComputeFaceDistance(FIndex fid1, FIndex fid2) @@ -12784,7 +12784,7 @@ float MeshTexture::ComputeFaceDistance(FIndex fid1, FIndex fid2)
Point3f diff = center2 - center1;
return std::sqrt(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z);
}
// 判断面是否在视图中可见
// 判断面是否在视图中可见
bool MeshTexture::IsFaceVisibleFromView(FIndex idxFace, int viewID)
{
@ -14073,6 +14073,14 @@ bool MeshTexture::RasterizeVirtualFaces( @@ -14073,6 +14073,14 @@ bool MeshTexture::RasterizeVirtualFaces(
DEBUG_EXTRA("Forward Rasterization Engine: Starting...");
TD_TIMER_START();
int totalVF = virtualFaceMap.size();
int emptyVF = 0;
for (auto& vf : virtualFaceViews)
if (vf.empty()) ++emptyVF;
DEBUG_EXTRA("VirtualFaces: total=%d empty=%d (%.1f%%)",
totalVF, emptyVF, 100.0f*emptyVF/totalVF);
if (virtualFaceMap.empty() || virtualFaceViews.size() != virtualFaceMap.size())
return false;
@ -14318,6 +14326,12 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int @@ -14318,6 +14326,12 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int
DEBUG_EXTRA("Texture Pipeline: Steps 3-4 (View Selection + VirtualFace Mapping)");
TD_TIMER_START();
// 不再重新选择视图!直接使用已有的 faceViews
if (faceViews.empty()) {
DEBUG_EXTRA("ERROR: faceViews is empty! Call FaceViewSelection first.");
return false;
}
// 1. 验证输入
if (scene.mesh.faceTexcoords.empty()) {
VERBOSE("error: mesh does not contain UV coordinates");
@ -14348,74 +14362,8 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int @@ -14348,74 +14362,8 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int
DEBUG_EXTRA("Step 4: Forced 1-to-1 mapping: %zu virtual faces for %zu original faces",
virtualFaceMap.size(), numFaces);
// 4.2 为每个虚拟面收集视图数据(用于可见性判断)
VirtualFaceDataArr virtualFaceDatas;
if (!ListCameraVirtualFaces(virtualFaceMap, virtualFaceDatas, fOutlierThreshold, nIgnoreMaskLabel, views, false)) {
return false;
}
// 4.3 单视图选择:为每个虚拟面选择最佳视图
std::vector<std::vector<IIndex>> virtualFaceViews(virtualFaceMap.size());
std::vector<std::vector<float>> virtualFaceViewWeights(virtualFaceMap.size());
size_t unassignedFaces = 0;
#ifdef _USE_OPENMP
#pragma omp parallel for reduction(+:unassignedFaces) schedule(dynamic)
#endif
for (int_t idxVF = 0; idxVF < (int_t)virtualFaceMap.size(); ++idxVF) {
const FIndex fid = virtualFaceMap[idxVF].faces[0];
const FaceDataArr& vfDatas = virtualFaceDatas[idxVF];
float bestScore = -1.0f;
IIndex bestViewID = IIndex(-1);
// 获取面片中心(用于计算距离和视角)
const Face& face = scene.mesh.faces[fid];
Point3f faceCenter = (scene.mesh.vertices[face[0]] +
scene.mesh.vertices[face[1]] +
scene.mesh.vertices[face[2]]) / 3.0f;
const Normal& faceNormal = scene.mesh.faceNormals[fid];
// 遍历能看到这个面片的所有相机
for (const FaceData& data : vfDatas) {
if (data.bInvalidFacesRelative) continue;
const Image& image = images[data.idxView];
// 使用综合评分函数
float score = ComputeComprehensiveScore(data, faceNormal, faceCenter, image);
if (score > bestScore) {
bestScore = score;
bestViewID = data.idxView;
}
}
// 如果找到了有效的视图
if (bestViewID != IIndex(-1) && bestScore > 0.1f) {
virtualFaceViews[idxVF] = { bestViewID };
virtualFaceViewWeights[idxVF] = { 1.0f }; // 单视图权重设为1
} else {
// virtualFaceViews[idxVF].clear();
// virtualFaceViewWeights[idxVF].clear();
// ++unassignedFaces;
float bestQuality = -1.0f;
for (const FaceData& data : vfDatas) {
if (data.quality > bestQuality) {
bestQuality = data.quality;
bestViewID = data.idxView;
bestScore = data.quality;
}
}
}
}
DEBUG_EXTRA("Step 3-4 completed: %zu faces processed, %zu unassigned",
numFaces, unassignedFaces);
DEBUG_EXTRA("Proceeding to Step 5: Forward Rasterization");
std::vector<std::vector<IIndex>> virtualFaceViews = faceViews;
std::vector<std::vector<float>> virtualFaceViewWeights = faceViewWeights;
// ==========================================================
// 步骤5:正向光栅化引擎
@ -14469,39 +14417,84 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int @@ -14469,39 +14417,84 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int
return true;
}
DEBUG_EXTRA("Unassigned faces: %zu / %zu", unassignedFaces, numFaces);
// DEBUG_EXTRA("Unassigned faces: %zu / %zu", unassignedFaces, numFaces);
DEBUG_EXTRA("Texture generation failed in stable mode");
return false;
}
bool MeshTexture::FaceViewSelectionWithVirtualFaces(unsigned minCommonCameras, float fOutlierThreshold,
float fRatioDataSmoothness, int nIgnoreMaskLabel,
const IIndexArr& views, bool bUseExistingUV)
bool MeshTexture::FaceViewSelectionWithVirtualFaces(
unsigned minCommonCameras,
float fOutlierThreshold,
float fRatioDataSmoothness,
int nIgnoreMaskLabel,
const IIndexArr& views,
bool bUseExistingUV)
{
DEBUG_EXTRA("Performing face view selection with virtual faces (bUseExistingUV=%d)", bUseExistingUV);
if (faceNeighbors.empty()) {
DEBUG_EXTRA("Initializing faceNeighbors via ComputePureFaceVisibility...");
if (!ComputePureFaceVisibility(fOutlierThreshold, nIgnoreMaskLabel, views)) {
return false;
}
}
if (bUseExistingUV) {
// 使用现有UV的虚拟面选择策略
VirtualFaceMap virtualFaceMap;
if (!CreateVirtualFacesForExistingUV(virtualFaceMap)) {
DEBUG_EXTRA("Failed to create virtual faces for existing UV");
return false;
}
DEBUG_EXTRA("Created %zu virtual faces", virtualFaceMap.size());
// 为虚拟面选择最佳视图
if (!SelectBestViewsForVirtualFaces(virtualFaceMap, minCommonCameras, fOutlierThreshold,
fRatioDataSmoothness, nIgnoreMaskLabel, views)) {
DEBUG_EXTRA("Failed to select best views for virtual faces");
if (!SelectBestViewsForVirtualFaces(
virtualFaceMap, minCommonCameras, fOutlierThreshold,
fRatioDataSmoothness, nIgnoreMaskLabel, views)) {
return false;
}
return true;
} else {
// 使用原始面片的虚拟面选择
return FaceViewSelection(minCommonCameras, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views);
}
// 非 UV 模式:走原生流程
return FaceViewSelection(minCommonCameras, fOutlierThreshold,
fRatioDataSmoothness, nIgnoreMaskLabel, views);
}
bool MeshTexture::ComputePureFaceVisibility(
float fOutlierThreshold,
int nIgnoreMaskLabel,
const IIndexArr& views)
{
DEBUG_EXTRA("Computing face visibility via ListCameraFaces (UV-safe)");
// 1. 调用 openMVS 原生的可见性计算
FaceDataViewArr facesDatas;
const bool bUseVirtualFaces = false; // ✅ 关键:禁用虚拟面,保持 1:1 映射
if (!ListCameraFaces(facesDatas, fOutlierThreshold, nIgnoreMaskLabel, views, bUseVirtualFaces)) {
DEBUG_EXTRA("ERROR: ListCameraFaces failed");
return false;
}
// 2. 从 facesDatas 中提取 faceNeighbors
// facesDatas[i] 是第 i 个面的候选视图数组(FaceDataArr)
// 每个 FaceData 有 .idxView 成员
faceNeighbors.resize(facesDatas.size());
for (size_t i = 0; i < facesDatas.size(); ++i) {
faceNeighbors[i].clear();
for (const FaceData& fd : facesDatas[i]) {
faceNeighbors[i].push_back(fd.idxView);
}
}
// 3. 统计
size_t visibleFaces = 0;
for (const auto& v : faceNeighbors)
if (!v.empty())
++visibleFaces;
DEBUG_EXTRA("Visibility done: %zu/%zu faces have views",
visibleFaces, facesDatas.size());
return true;
}
bool MeshTexture::GenerateTextureWithVirtualFaces(bool bGlobalSeamLeveling, bool bLocalSeamLeveling,
@ -14533,115 +14526,158 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap, @@ -14533,115 +14526,158 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
const IIndexArr& views)
{
DEBUG_EXTRA("Selecting best views for %zu virtual faces", virtualFaceMap.size());
// 为每个虚拟面计算最佳视图
faceViews.resize(virtualFaceMap.size());
faceViewWeights.resize(virtualFaceMap.size());
// 检查 m_virtualFaceGeometries 是否已初始化
if (m_virtualFaceGeometries.empty()) {
m_virtualFaceGeometries.Resize(virtualFaceMap.size());
} else if (m_virtualFaceGeometries.size() < virtualFaceMap.size()) {
if (m_virtualFaceGeometries.empty() ||
m_virtualFaceGeometries.size() < virtualFaceMap.size()) {
m_virtualFaceGeometries.Resize(virtualFaceMap.size());
}
// 初始化每个虚拟面的视图数据数组
for (auto& viewList : faceViews) {
for (auto& viewList : faceViews)
viewList.clear();
}
for (auto& weightList : faceViewWeights) {
for (auto& weightList : faceViewWeights)
weightList.clear();
}
// ===== Debug 统计 =====
size_t emptyCandidateViews = 0;
size_t emptyCommonViews = 0;
size_t fallbackByCenterFace = 0;
size_t successVF = 0;
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 (faceNeighbors[faceID2].empty()) {
DEBUG_EXTRA("FATAL: faceNeighbors[%u] is empty! FaceViewSelection mode error.", faceID2);
}
//------------------------------------------------------------------
// 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()) {
for (size_t k = 0; k < faceNeighbors[faceID].size(); ++k) {
IIndex viewID = faceNeighbors[faceID][k];
if (views.empty() || views.FindFirst(viewID) != NO_ID) {
candidateViews.insert(viewID);
faceViewCandidates[j].push_back(viewID);
}
}
}
}
// 如果候选视图为空,跳过这个虚拟面
if (candidateViews.empty()) {
continue;
}
// 找到所有虚拟面都可见的视图
std::vector<IIndex> commonViews;
for (IIndex viewID : candidateViews) {
bool allFacesVisible = true;
for (size_t j = 0; j < vf.faces.size() && allFacesVisible; ++j) {
if (std::find(faceViewCandidates[j].begin(), faceViewCandidates[j].end(), viewID) == faceViewCandidates[j].end()) {
allFacesVisible = false;
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);
}
}
if (allFacesVisible) {
commonViews.push_back(viewID);
}
}
// 如果共同视图太少,使用所有候选视图
if (commonViews.size() < minCommonCameras) {
// 将所有候选视图转换为vector
faceViews[i].assign(candidateViews.begin(), candidateViews.end());
//------------------------------------------------------------------
// 2. 【终极兜底】候选视图为空 → 强制分配一个视图
// 物理遮挡不重要,逻辑可见性最重要
//------------------------------------------------------------------
if (candidateViews.empty()) {
++emptyCandidateViews;
// 找一个可用的相机ID
// 优先级:views参数指定的 > 所有images中的第一个
IIndex forcedView = NO_ID;
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);
++fallbackByCenterFace;
// 降低日志级别,避免刷屏,用 DEBUG 而非 EXTRA
DEBUG("VF[%zu] EMPTY -> FORCED view %d (ignoring physical occlusion)",
i, forcedView);
continue;
}
// 实在没救(连images都没有),这才跳过
DEBUG_EXTRA("VF[%zu] truly hopeless: no images available", i);
continue;
}
//------------------------------------------------------------------
// 3. 【关键放松】不再强求“所有面片共视”
// 只要视图能看到任意一个面片即可
//------------------------------------------------------------------
std::vector<IIndex> usableViews(
candidateViews.begin(), candidateViews.end()
);
// (可选)按质量排序,取前 N 个
// std::sort(usableViews.begin(), usableViews.end(),
// [&](IIndex a, IIndex b) { return Quality(a) > Quality(b); });
if (usableViews.size() < minCommonCameras) {
faceViews[i] = usableViews;
} else {
// 使用共同视图
faceViews[i] = commonViews;
// 仍尊重 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;
}
}
continue;
}
// 分配相等的权重
float weight = 1.0f / faceViews[i].size();
//------------------------------------------------------------------
// 5. 权重分配(均等,最稳定)
//------------------------------------------------------------------
float weight = 1.0f / static_cast<float>(faceViews[i].size());
faceViewWeights[i].resize(faceViews[i].size(), weight);
// 计算每个视图的质量
for (size_t k = 0; k < faceViews[i].size(); ++k) {
IIndex viewID = faceViews[i][k];
// 创建FaceData
FaceData faceData;
faceData.idxView = viewID;
faceData.quality = weight; // 使用权重作为质量
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA
// 可以在这里计算和设置颜色
// 例如:faceData.color = CalculateMeanColor(viewID, vf);
#endif
faceData.bInvalidFacesRelative = false;
// 注意:m_virtualFaceGeometries 存储的是几何信息,不是视图数据
// 如果您需要存储视图数据,可以:
// 1. 创建单独的成员变量
// 2. 扩展 VirtualFaceGeometryData
// 3. 使用 faceViews 和 faceViewWeights
}
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA
if (fOutlierThreshold > 0) {
// DetectAndRemoveOutliers(...);
}
#endif
++successVF;
}
DEBUG_EXTRA("Best view selection completed for %zu virtual faces", virtualFaceMap.size());
//--------------------------------------------------------------------------
// 6. Debug 汇总(非常重要)
//--------------------------------------------------------------------------
DEBUG_EXTRA("====== Virtual Face View Selection Summary ======");
DEBUG_EXTRA("Total virtual faces : %zu", virtualFaceMap.size());
DEBUG_EXTRA("Successfully assigned : %zu", successVF);
DEBUG_EXTRA("Empty candidates : %zu", emptyCandidateViews);
DEBUG_EXTRA("Fallback by center face : %zu", fallbackByCenterFace);
DEBUG_EXTRA("Empty after relaxation : %zu", emptyCommonViews);
DEBUG_EXTRA("Expected empty ratio : %.2f%%",
100.0 * (emptyCandidateViews - fallbackByCenterFace) / virtualFaceMap.size());
DEBUG_EXTRA("=================================================");
return true;
}
@ -18633,29 +18669,48 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi @@ -18633,29 +18669,48 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
DEBUG_EXTRA("TextureMesh bUseExistingUV=%d, UVMeshFile=%s", bUseExistingUV, strUVMeshFileName.c_str());
// 处理已有UV的情况
if (bUseExistingUV && !strUVMeshFileName.empty()) {
// VERBOSE("1faceTexcoords.size=%d, faces.size=%d", mesh.faceTexcoords.size(), mesh.faces.size() * 3);
// // 使用预计算UV模式
// if (!mesh.Load(MAKE_PATH_SAFE(strUVMeshFileName), true)) {
// VERBOSE("error: cannot load mesh file with UV coordinates");
// return false;
// }
VERBOSE("2faceTexcoords.size=%d, faces.size=%d", mesh.faceTexcoords.size(), mesh.faces.size() * 3);
// mesh.CheckUVValid();
// 确保网格包含UV坐标
if (mesh.faceTexcoords.empty()) {
VERBOSE("error: the specified mesh does not contain UV coordinates");
return false;
}
if (bUseExistingUV && !strUVMeshFileName.empty()) {
MeshTexture texture(*this, nResolutionLevel, nMinResolution);
// ✅ 只用“纯可见性”,绝不碰 FaceViewSelection
if (!texture.ComputePureFaceVisibility(
fOutlierThreshold,
nIgnoreMaskLabel,
views)) {
return false;
}
// 使用虚拟面优化的纹理生成
if (!texture.TextureWithExistingUVVirtualFaces(views, nIgnoreMaskLabel, fOutlierThreshold, nTextureSizeMultiple, colEmpty, fSharpnessWeight)){
return false;
}
return true;
}
// ✅ 现在 faces 没动过,faceNeighbors 是对齐的
MeshTexture::VirtualFaceMap virtualFaceMap;
if (!texture.CreateVirtualFacesForExistingUV(virtualFaceMap)) {
return false;
}
if (!texture.SelectBestViewsForVirtualFaces(
virtualFaceMap,
1, // 单视图就够了
fOutlierThreshold,
fRatioDataSmoothness,
nIgnoreMaskLabel,
views)) {
return false;
}
// 直接光栅化
Mesh::Image8U3Arr textures;
if (!texture.RasterizeVirtualFaces(
virtualFaceMap,
texture.faceViews,
texture.faceViewWeights,
nTextureSizeMultiple,
colEmpty,
textures)) {
return false;
}
mesh.texturesDiffuse = std::move(textures);
return true;
}
// generate the texture image and atlas
{

Loading…
Cancel
Save