diff --git a/libs/MVS/Scene.h b/libs/MVS/Scene.h index f4eab4c..f8562c8 100644 --- a/libs/MVS/Scene.h +++ b/libs/MVS/Scene.h @@ -164,7 +164,22 @@ public: std::map>& edge_faces_map, std::map>& delete_edge_faces_map, std::string& basePath); - + bool LoadVisibleFacesData() { + std::map> visible_faces_map; + std::unordered_set face_visible_relative; + std::map> edge_faces_map; + std::map> delete_edge_faces_map; + std::string basePath = GetDefaultBasePath(); // 你需要实现这个函数 + + return LoadVisibleFacesData(visible_faces_map, face_visible_relative, + edge_faces_map, delete_edge_faces_map, basePath); + } + std::string GetDefaultBasePath() { + // 根据你的需求实现这个函数 + // 例如:返回一个默认的路径,或者从配置中读取 + return "default_path"; + } + // Mesh texturing bool TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsigned minCommonCameras=0, float fOutlierThreshold=0.f, float fRatioDataSmoothness=0.3f, bool bGlobalSeamLeveling=true, bool bLocalSeamLeveling=true, unsigned nTextureSizeMultiple=0, unsigned nRectPackingHeuristic=3, Pixel8U colEmpty=Pixel8U(255,127,39), diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index 51b6b72..bfa9673 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -202,6 +202,14 @@ struct PixelSample { std::vector patchQualityInfos; +struct VirtualFaceGeometryData { + IIndexArr faceIndices; // 虚拟面对应的原始面片索引 + Point3f center; // 虚拟面中心点 + Point3f normal; // 虚拟面法向量 + float area; // 虚拟面面积 +}; +typedef cList VirtualFaceGeometryArr; + struct MeshTexture { // used to render the surface to a view camera typedef TImage FaceMap; @@ -333,6 +341,24 @@ struct MeshTexture { typedef uint32_t Label; typedef cList LabelArr; + // VirtualFace 结构体定义 + struct VirtualFace { + Mesh::FaceIdxArr faces; // 面片索引数组 + Point3f center; // 虚拟面的中心点 + Normal normal; // 虚拟面的法线 + float area; // 虚拟面的面积 + AABB2f uvBounds; // UV边界框 + + VirtualFace() : center(Point3f::ZERO), normal(Normal::ZERO), area(0.0f) {} + }; + + // VirtualFaceMap 类型定义 + typedef cList VirtualFaceMap; + + // VirtualFaceDataArr 类型定义 + // 注意:这里使用FaceDataViewArr,因为虚拟面的视图数据结构和面片视图数据结构相同 + typedef FaceDataViewArr VirtualFaceDataArr; + // represents a texture patch struct TexturePatch { Label label; // view index @@ -524,6 +550,26 @@ public: void ListVertexFaces(bool bUseExistingUV = false); + bool ListCameraVirtualFaces(const VirtualFaceMap& virtualFaceMap, + VirtualFaceDataArr& virtualFaceDatas, + float fOutlierThreshold, + int nIgnoreMaskLabel, + const IIndexArr& _views, + bool bUseVirtualFaces); + void ProcessVirtualFacesInView(const VirtualFaceMap& virtualFaceMap, + VirtualFaceDataArr& virtualFaceDatas, + IIndex idxView, + const DepthMap& depthMap, + const FaceMap& faceMap, + const Mesh::FaceIdxArr& cameraFaces, + const Image& imageData, + const Mesh::VertexArr& vertices, + const Mesh::FaceArr& faces, + const Mesh::NormalArr& faceNormals); + void CalculateVirtualFaceProperties(VirtualFace& vf); + void CalculateVirtualFaceUVBounds(VirtualFace& vf); + bool AreFacesUVContinuous(FIndex fid1, FIndex fid2); + bool ListCameraFaces(FaceDataViewArr&, float fOutlierThreshold, int nIgnoreMaskLabel, const IIndexArr& views, bool bUseVirtualFaces); bool CheckInvalidFaces(FaceDataViewArr& facesDatas, float fOutlierThreshold, int nIgnoreMaskLabel, const IIndexArr& _views, bool bUseVirtualFaces); bool IsFaceVisibleAndValid(const FaceDataArr& faceDatas, const IIndexArr& selectedCams) const; @@ -550,6 +596,37 @@ public: bool FaceViewSelection4( unsigned minCommonCameras, float fOutlierThreshold, float fRatioDataSmoothness, int nIgnoreMaskLabel, const IIndexArr& views, const Mesh::FaceIdxArr* faceIndices = nullptr); void CreateAdaptiveVirtualFaces(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, unsigned minCommonCameras); bool ShouldMergeVirtualFace(const MeshTexture::FaceDataViewArr& facesDatas, const Mesh::FaceIdxArr& currentVirtualFace, FIndex candidateFace, unsigned minCommonCameras); + bool FaceViewSelectionWithVirtualFaces(unsigned minCommonCameras, float fOutlierThreshold, + float fRatioDataSmoothness, int nIgnoreMaskLabel, + const IIndexArr& views, bool bUseExistingUV); + + bool GenerateTextureWithVirtualFaces(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, + unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, + Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, + const SEACAVE::String& baseFileName, bool bOriginFaceview, Scene* pScene); + bool GenerateTextureWithVirtualFacesInternal(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, + unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, + Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, + const SEACAVE::String& baseFileName, Scene* pScene); + bool SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap, + unsigned minCommonCameras, float fOutlierThreshold, + float fRatioDataSmoothness, int nIgnoreMaskLabel, + const IIndexArr& views); + std::vector> faceViews; + std::vector> faceViewWeights; + + // 虚拟面相关数据结构 + struct VirtualFaceData { + std::vector faceIndices; // 虚拟面对应的原始面片索引 + Point3f center; // 虚拟面中心 + Point3f normal; // 虚拟面法向量 + float area; // 虚拟面面积 + }; + + std::vector virtualFaceDatas; + std::vector> faceNeighbors; + VirtualFaceGeometryArr m_virtualFaceGeometries; + uint32_t FindNearestPatchForFaces(const std::vector& faceIndices); void FixIsolatedComponents(); void ReinitializeSeamData(); @@ -567,6 +644,7 @@ public: void LocalSeamLevelingExternalUV(); void GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, const SEACAVE::String& baseFileName, bool bOriginFaceview, Scene *pScene); + void GenerateTextureForUV(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, const SEACAVE::String& basename, bool bOriginFaceview, Scene *pScene, Mesh::TexCoordArr& existingTexcoords, Mesh::TexIndexArr& existingTexindices); void GenerateTexture2(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, const SEACAVE::String& baseFileName); bool TextureWithExistingUV( @@ -580,6 +658,28 @@ public: const Mesh::TexCoordArr& existingTexcoords, // 添加已有UV参数 const Mesh::TexIndexArr& existingTexindices // 添加已有纹理索引参数 ); + bool TextureWithExistingUVVirtualFaces(const IIndexArr& views, int nIgnoreMaskLabel, + float fOutlierThreshold, unsigned nTextureSizeMultiple, + Pixel8U colEmpty, float fSharpnessWeight); + bool CreateVirtualFacesForExistingUV(VirtualFaceMap& virtualFaceMap); + bool CheckUVContinuity(const std::vector& faceList); + Mesh::Image8U3Arr GenerateMultiViewTextureAtlasWithVirtualFaces( + const VirtualFaceMap& virtualFaceMap, + const VirtualFaceDataArr& virtualFaceDatas, // 改为 VirtualFaceDataArr + const std::vector>& faceViews, + const std::vector>& faceViewWeights, + unsigned nTextureSizeMultiple, + Pixel8U colEmpty, + float fSharpnessWeight); + std::vector GetPixelsInTriangle( + const cv::Point2f& p1, + const cv::Point2f& p2, + const cv::Point2f& p3, + int textureSize) const; + float TriangleArea( + const cv::Point2f& p1, + const cv::Point2f& p2, + const cv::Point2f& p3) const; bool GenerateTextureWithViewConsistency( bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, @@ -1038,6 +1138,395 @@ void MeshTexture::ListVertexFaces(bool bUseExistingUV) scene.mesh.ListIncidenteFaceFaces(); } +// extract array of virtual faces viewed by each image +bool MeshTexture::ListCameraVirtualFaces(const VirtualFaceMap& virtualFaceMap, + VirtualFaceDataArr& virtualFaceDatas, + float fOutlierThreshold, + int nIgnoreMaskLabel, + const IIndexArr& _views, + bool bUseVirtualFaces) +{ + // 创建面片八叉树加速可见性查询 + Mesh::Octree octree; + Mesh::FacesInserter::CreateOctree(octree, scene.mesh); + + // 初始化视图数组 + IIndexArr views(_views); + if (views.empty()) { + views.resize(images.size()); + std::iota(views.begin(), views.end(), IIndex(0)); + } + + // 初始化虚拟面数据数组 + virtualFaceDatas.resize(virtualFaceMap.size()); + + // 初始化深度图和面图 + DepthMap depthMap; + FaceMap faceMap; + + // 获取网格数据引用 + const Mesh::VertexArr& vertices = scene.mesh.vertices; + const Mesh::FaceArr& faces = scene.mesh.faces; + const Mesh::NormalArr& faceNormals = scene.mesh.faceNormals; + + Util::Progress progress(_T("Processing virtual faces"), views.size()); + + // 为每个视图创建可见面列表 + Mesh::FaceIdxArr cameraFaces; + + // 遍历所有视图 + for (IIndex idxView : views) { + Image& imageData = images[idxView]; + if (!imageData.IsValid()) { + ++progress; + continue; + } + + // 加载图像 + unsigned level(nResolutionLevel); + const unsigned imageSize(imageData.RecomputeMaxResolution(level, nMinResolution)); + if ((imageData.image.empty() || MAXF(imageData.width, imageData.height) != imageSize) && + !imageData.ReloadImage(imageSize)) { + return false; + } + imageData.UpdateCamera(scene.platforms); + + // 选择视锥体内的面片 + Mesh::FacesInserter inserter(cameraFaces); + const TFrustum frustum(Matrix3x4f(imageData.camera.P), (float)imageData.width, (float)imageData.height); + octree.Traverse(frustum, inserter); + + // 创建深度图和面图 + depthMap.create(imageData.GetSize()); + faceMap.create(imageData.GetSize()); + + // 创建光栅化器 + RasterMesh rasterer(*this, vertices, imageData.camera, depthMap, faceMap, scene.mesh, false); + RasterMesh::Triangle triangle; + RasterMesh::TriangleRasterizer triangleRasterizer(triangle, rasterer); + + // 处理掩码 + if (nIgnoreMaskLabel >= 0) { + BitMatrix bmask; + DepthEstimator::ImportIgnoreMask(imageData, imageData.GetSize(), (uint16_t)nIgnoreMaskLabel, bmask, &rasterer.mask); + } else if (nIgnoreMaskLabel == -1) { + rasterer.mask = DetectInvalidImageRegions(imageData.image); + } + + rasterer.Clear(); + + // 光栅化所有可见面片 + for (FIndex idxFace : cameraFaces) { + rasterer.validFace = true; + const Mesh::Face& facet = faces[idxFace]; + rasterer.idxFace = idxFace; + rasterer.Project(facet, triangleRasterizer); + if (!rasterer.validFace) { + rasterer.Project(facet, triangleRasterizer); + } + } + + // 计算虚拟面在视图中的可见性 + ProcessVirtualFacesInView(virtualFaceMap, virtualFaceDatas, idxView, depthMap, faceMap, + cameraFaces, imageData, vertices, faces, faceNormals); + + ++progress; + } + + progress.close(); + + // 异常视图检测 + if (fOutlierThreshold > 0) { + for (FaceDataArr& faceDatas : virtualFaceDatas) { + FaceOutlierDetection(faceDatas, fOutlierThreshold); + } + } + + return true; +} + +// 处理单个视图中虚拟面的可见性 +void MeshTexture::ProcessVirtualFacesInView(const VirtualFaceMap& virtualFaceMap, + VirtualFaceDataArr& virtualFaceDatas, + IIndex idxView, + const DepthMap& depthMap, + const FaceMap& faceMap, + const Mesh::FaceIdxArr& cameraFaces, + const Image& imageData, + const Mesh::VertexArr& vertices, + const Mesh::FaceArr& faces, + const Mesh::NormalArr& faceNormals) +{ + // 为每个虚拟面计算可见性 + std::vector virtualFaceVisible(virtualFaceMap.size(), false); + + // 创建原始面片到虚拟面的映射 + std::unordered_map faceToVirtualFaceMap; + for (VIndex vfIdx = 0; vfIdx < virtualFaceMap.size(); ++vfIdx) { + const VirtualFace& vf = virtualFaceMap[vfIdx]; + for (FIndex faceIdx : vf.faces) { + faceToVirtualFaceMap[faceIdx] = vfIdx; + } + } + + // 遍历深度图和面图,收集虚拟面的可见像素 + std::vector>> virtualFacePixels(virtualFaceMap.size()); + std::vector> virtualFaceGradients(virtualFaceMap.size()); + + for (int j = 0; j < faceMap.rows; ++j) { + for (int i = 0; i < faceMap.cols; ++i) { + cuint32_t faceIdxTemp = faceMap(j, i); + if (faceIdxTemp == 0) { // 假设 0 表示无效面 + continue; + } + + FIndex idxFace = static_cast(faceIdxTemp); + + if (idxFace == NO_ID || depthMap(j, i) > 999.0f) { + continue; + } + + // 查找这个面片属于哪个虚拟面 + auto it = faceToVirtualFaceMap.find(idxFace); + if (it == faceToVirtualFaceMap.end()) { + continue; + } + + VIndex vfIdx = it->second; + + // 记录像素颜色和深度 + virtualFaceVisible[vfIdx] = true; + const Pixel8U& pixel = imageData.image(j, i); + + // 记录像素颜色 + virtualFacePixels[vfIdx].emplace_back(depthMap(j, i), Color(pixel)); + + // 记录梯度值(使用简单灰度值代替实际梯度计算) + float grayValue = (pixel.r + pixel.g + pixel.b) / 3.0f / 255.0f; + virtualFaceGradients[vfIdx].push_back(grayValue); + } + } + + // 为每个虚拟面计算视图数据 + for (VIndex vfIdx = 0; vfIdx < virtualFaceMap.size(); ++vfIdx) { + if (!virtualFaceVisible[vfIdx]) { + continue; + } + + const VirtualFace& vf = virtualFaceMap[vfIdx]; + FaceDataArr& faceDatas = virtualFaceDatas[vfIdx]; + + // 计算虚拟面的平均质量和颜色 + float totalQuality = 0.0f; + Color totalColor(0, 0, 0); + int pixelCount = 0; + + // 计算深度值的统计数据 + std::vector depths; + for (const auto& pixel : virtualFacePixels[vfIdx]) { + depths.push_back(pixel.first); + totalColor += pixel.second; + pixelCount++; + } + + // 计算梯度值的平均值 + for (float grad : virtualFaceGradients[vfIdx]) { + totalQuality += grad; + } + + if (pixelCount > 0) { + // 计算平均颜色 + Color avgColor = totalColor * (1.0f / pixelCount); + + // 计算平均质量 + float avgQuality = totalQuality / pixelCount; + + // 计算深度变化 + std::sort(depths.begin(), depths.end()); + float medianDepth = depths[depths.size() / 2]; + float depthVariance = 0.0f; + for (float depth : depths) { + depthVariance += (depth - medianDepth) * (depth - medianDepth); + } + depthVariance /= depths.size(); + + // 计算虚拟面中心 + Point3f virtualFaceCenter(0, 0, 0); + for (FIndex faceIdx : vf.faces) { + const Mesh::Face& facet = faces[faceIdx]; + virtualFaceCenter += (vertices[facet[0]] + vertices[facet[1]] + vertices[facet[2]]) / 3.0f; + } + virtualFaceCenter /= vf.faces.size(); + + Normal virtualFaceNormal(0, 0, 0); + for (FIndex faceIdx : vf.faces) { + virtualFaceNormal += faceNormals[faceIdx]; + } + + // 手动归一化 + float norm = cv::norm(virtualFaceNormal); + if (norm > 0) { + virtualFaceNormal.x /= norm; + virtualFaceNormal.y /= norm; + virtualFaceNormal.z /= norm; + } + + // 计算相机方向 + const Point3f camDir(Cast(imageData.camera.C) - virtualFaceCenter); + const float cosFaceCam = MAXF(0.001f, ComputeAngle(camDir.ptr(), virtualFaceNormal.ptr())); + + // 调整质量:考虑视角和深度一致性 + float angleFactor = SQUARE(cosFaceCam); + float depthConsistencyFactor = 1.0f / (1.0f + depthVariance); + float adjustedQuality = avgQuality * angleFactor * depthConsistencyFactor; + + // 创建新的FaceData + FaceData& faceData = faceDatas.emplace_back(); + faceData.idxView = idxView; + faceData.quality = adjustedQuality; + faceData.bInvalidFacesRelative = false; + + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + faceData.color = avgColor; + #endif + } + } + + // 额外的可见性检查:如果虚拟面在多个视图中都可见,但只有少数像素可见,可能需要调整权重 + for (VIndex vfIdx = 0; vfIdx < virtualFaceMap.size(); ++vfIdx) { + if (virtualFaceVisible[vfIdx] && virtualFacePixels[vfIdx].size() < 10) { + // 如果虚拟面可见像素很少,降低其质量权重 + FaceDataArr& faceDatas = virtualFaceDatas[vfIdx]; + for (auto& fd : faceDatas) { + if (fd.idxView == idxView) { + fd.quality *= 0.5f; // 减少小可见区域的影响 + break; + } + } + } + } +} + +// 计算虚拟面的属性 +// 计算虚拟面的属性 +void MeshTexture::CalculateVirtualFaceProperties(VirtualFace& vf) { + if (vf.faces.empty()) { + vf.center = Point3f::ZERO; + vf.normal = Normal::ZERO; + vf.area = 0.0f; + return; + } + + const Mesh::VertexArr& vertices = scene.mesh.vertices; + const Mesh::NormalArr& faceNormals = scene.mesh.faceNormals; + + vf.center = Point3f::ZERO; + vf.normal = Normal::ZERO; + vf.area = 0.0f; + + for (FIndex faceIdx : vf.faces) { + const Mesh::Face& facet = faces[faceIdx]; + + // 计算面片中心 + Point3f faceCenter = (vertices[facet[0]] + vertices[facet[1]] + vertices[facet[2]]) / 3.0f; + vf.center += faceCenter; + + // 累加法线 + vf.normal += faceNormals[faceIdx]; + + // 计算面片面积 - 修复1:手动计算三角形面积 + const Point3f& v0 = vertices[facet[0]]; + const Point3f& v1 = vertices[facet[1]]; + const Point3f& v2 = vertices[facet[2]]; + + // 计算三角形的两个边向量 + Point3f edge1 = v1 - v0; + Point3f edge2 = v2 - v0; + + // 计算叉积 + Point3f crossProd( + edge1.y * edge2.z - edge1.z * edge2.y, + edge1.z * edge2.x - edge1.x * edge2.z, + edge1.x * edge2.y - edge1.y * edge2.x + ); + + // 计算面积 = 0.5 * 叉积的模 + float area = 0.5f * std::sqrt( + crossProd.x * crossProd.x + + crossProd.y * crossProd.y + + crossProd.z * crossProd.z + ); + + vf.area += area; + } + + // 计算平均值 + vf.center /= vf.faces.size(); + + // 修复2:手动归一化法线向量 + float norm = std::sqrt( + vf.normal.x * vf.normal.x + + vf.normal.y * vf.normal.y + + vf.normal.z * vf.normal.z + ); + + if (norm > 0) { + vf.normal.x /= norm; + vf.normal.y /= norm; + vf.normal.z /= norm; + } +} +// 计算虚拟面的UV边界 +void MeshTexture::CalculateVirtualFaceUVBounds(VirtualFace& vf) { + if (vf.faces.empty() || !scene.mesh.HasTexture()) { + // 修正1: 不使用 ZERO,而是创建一个空的边界框 + vf.uvBounds = AABB2f(); // 使用默认构造函数 + return; + } + + const TexCoord* texcoords = scene.mesh.faceTexcoords.data(); + bool first = true; + + for (FIndex faceIdx : vf.faces) { + for (int i = 0; i < 3; ++i) { + const TexCoord& uv = texcoords[faceIdx * 3 + i]; + if (first) { + // 修正2: 使用 ptMin 和 ptMax + vf.uvBounds.ptMin = uv; + vf.uvBounds.ptMax = uv; + first = false; + } else { + vf.uvBounds.Insert(uv); + } + } + } +} +// 检查两个面片在UV空间中是否连续 +bool MeshTexture::AreFacesUVContinuous(FIndex fid1, FIndex fid2) { + if (!scene.mesh.HasTexture()) { + return false; + } + + const TexCoord* uv1 = &scene.mesh.faceTexcoords[fid1 * 3]; + const TexCoord* uv2 = &scene.mesh.faceTexcoords[fid2 * 3]; + + float minDistance = std::numeric_limits::max(); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + float dx = uv1[i].x - uv2[j].x; + float dy = uv1[i].y - uv2[j].y; + float dist = sqrt(dx * dx + dy * dy); + if (dist < minDistance) { + minDistance = dist; + } + } + } + + const float uvContinuityThreshold = 0.01f; + return minDistance < uvContinuityThreshold; +} + // extract array of faces viewed by each image bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThreshold, int nIgnoreMaskLabel, const IIndexArr& _views, bool bUseVirtualFaces) { @@ -14270,125 +14759,942 @@ void MeshTexture::FillTextureHoles(std::vector& textures, Pixel8U colE DEBUG_EXTRA("Hole filling completed"); } -bool MeshTexture::TextureWithExistingUV( - const IIndexArr& views, - int nIgnoreMaskLabel, - float fOutlierThreshold, - unsigned nTextureSizeMultiple, - Pixel8U colEmpty, - float fSharpnessWeight, - const Mesh::Image8U3Arr& existingTextures, - const Mesh::TexCoordArr& existingTexcoords, - const Mesh::TexIndexArr& existingTexindices) +bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int nIgnoreMaskLabel, + float fOutlierThreshold, unsigned nTextureSizeMultiple, + Pixel8U colEmpty, float fSharpnessWeight) { - DEBUG_EXTRA("TextureWithExistingUV - 使用3D几何坐标和多视图融合"); + DEBUG_EXTRA("TextureWithExistingUVVirtualFaces with multi-view blending"); + TD_TIMER_START(); + // 1. 验证输入 if (scene.mesh.faceTexcoords.empty()) { - VERBOSE("错误: 网格没有UV坐标"); + VERBOSE("error: mesh does not contain UV coordinates"); return false; } - // 1. 为每个面选择最佳视图 - FaceDataViewArr facesDatas; - if (!ListCameraFaces(facesDatas, fOutlierThreshold, nIgnoreMaskLabel, views, false)) { - VERBOSE("错误: 无法列举相机-面片关系"); + if (scene.mesh.faceTexcoords.size() != scene.mesh.faces.size() * 3) { + VERBOSE("error: UV coordinates count does not match face count, %d, %d", + scene.mesh.faceTexcoords.size(), scene.mesh.faces.size() * 3); return false; } - // 2. 分配面片标签 - LabelArr faceLabels(scene.mesh.faces.size()); - std::vector faceConfidences(scene.mesh.faces.size(), 0.0f); + // 2. 创建虚拟面 + DEBUG_EXTRA("Creating virtual faces for existing UV texture mapping..."); + VirtualFaceMap virtualFaceMap; + if (!CreateVirtualFacesForExistingUV(virtualFaceMap)) { + DEBUG_EXTRA("Failed to create virtual faces, falling back to original faces"); + // 回退到原始面片 + virtualFaceMap.clear(); + for (FIndex fid = 0; fid < faces.size(); ++fid) { + virtualFaceMap.push_back(VirtualFace()); + VirtualFace& vf = virtualFaceMap.back(); + vf.faces.push_back(fid); + } + } + + DEBUG_EXTRA("Created %zu virtual faces (original faces: %zu)", virtualFaceMap.size(), faces.size()); + + // 3. 为每个虚拟面收集视图数据 + VirtualFaceDataArr virtualFaceDatas; + if (!ListCameraVirtualFaces(virtualFaceMap, virtualFaceDatas, fOutlierThreshold, nIgnoreMaskLabel, views, false)) { + return false; + } + + // 4. 为每个虚拟面选择最佳视图,支持多视图融合 + std::vector> virtualFaceViews(virtualFaceMap.size()); + std::vector> virtualFaceViewWeights(virtualFaceMap.size()); #ifdef _USE_OPENMP #pragma omp parallel for schedule(dynamic) + for (int_t idxVF = 0; idxVF < (int_t)virtualFaceMap.size(); ++idxVF) { + #else + for (size_t idxVF = 0; idxVF < virtualFaceMap.size(); ++idxVF) { #endif - for (int_t idxFace = 0; idxFace < (int_t)scene.mesh.faces.size(); ++idxFace) { - FIndex faceID = (FIndex)idxFace; - const FaceDataArr& faceDatas = facesDatas[faceID]; + const FaceDataArr& vfDatas = virtualFaceDatas[idxVF]; + std::vector> viewScores; - if (faceDatas.empty()) { - faceLabels[faceID] = 0; - faceConfidences[faceID] = 0.0f; - continue; + // 收集所有有效视图 + for (const FaceData& data : vfDatas) { + if (!data.bInvalidFacesRelative) { + // 计算视图质量权重 + float weight = data.quality; + + // 添加视角与法线夹角的权重 + const Image& image = images[data.idxView]; + const Normal& faceNormal = scene.mesh.faceNormals[virtualFaceMap[idxVF].faces[0]]; // 使用第一个面的法线 + + // 计算相机方向 + Point3f cameraForward(0, 0, -1); // 相机前方 + Point3f cameraForwardWorld; + cameraForwardWorld.x = (float)(image.camera.R(0,0) * cameraForward.x + + image.camera.R(0,1) * cameraForward.y + + image.camera.R(0,2) * cameraForward.z); + cameraForwardWorld.y = (float)(image.camera.R(1,0) * cameraForward.x + + image.camera.R(1,1) * cameraForward.y + + image.camera.R(1,2) * cameraForward.z); + cameraForwardWorld.z = (float)(image.camera.R(2,0) * cameraForward.x + + image.camera.R(2,1) * cameraForward.y + + image.camera.R(2,2) * cameraForward.z); + cameraForward = cameraForwardWorld; + + float len = sqrt(cameraForward.x * cameraForward.x + + cameraForward.y * cameraForward.y + + cameraForward.z * cameraForward.z); + if (len > 0) { + cameraForward.x /= len; + cameraForward.y /= len; + cameraForward.z /= len; + } + + // 法线与相机方向的点积(越大越好,表示面正对相机) + float dotProduct = faceNormal.dot(cameraForward); + float angleWeight = (dotProduct + 1.0f) * 0.5f; // 归一化到[0,1] + + // 综合权重 + float finalWeight = weight * 0.7f + angleWeight * 0.3f; + + viewScores.emplace_back(finalWeight, data.idxView); + } } - // 计算面法线 - const Face& face = scene.mesh.faces[faceID]; - Vertex v0 = vertices[face[1]] - vertices[face[0]]; - Vertex v1 = vertices[face[2]] - vertices[face[0]]; - Vertex normal = v0.cross(v1); - double normVal = cv::norm(normal); - if (normVal > 0) normal = normal / (float)normVal; - else normal = Vertex(0, 0, 1); - - // 计算面中心 - Vertex faceCenter(0, 0, 0); - for (int v = 0; v < 3; ++v) faceCenter += vertices[face[v]]; - faceCenter /= 3.0f; + // 按权重排序,选择前N个视图 + std::sort(viewScores.begin(), viewScores.end(), + [](const auto& a, const auto& b) { return a.first > b.first; }); - // 选择最佳视图 - IIndex bestView = NO_ID; - float bestScore = -1.0f; + const int maxViews = 5; // 最多使用5个视图进行融合 + float totalWeight = 0.0f; - for (const FaceData& data : faceDatas) { - if (data.bInvalidFacesRelative) continue; - - float score = ComputeViewScore(images[data.idxView], faceCenter, normal); - if (score > bestScore) { - bestScore = score; - bestView = data.idxView; + for (int i = 0; i < std::min((int)viewScores.size(), maxViews); ++i) { + if (viewScores[i].first > 0.1f) { // 质量阈值 + virtualFaceViews[idxVF].push_back(viewScores[i].second); + virtualFaceViewWeights[idxVF].push_back(viewScores[i].first); + totalWeight += viewScores[i].first; } } - if (bestView != NO_ID && bestScore > 0.1f) { - faceLabels[faceID] = bestView + 1; - faceConfidences[faceID] = bestScore; - } else { - faceLabels[faceID] = 0; - faceConfidences[faceID] = 0.0f; + // 归一化权重 + if (totalWeight > 0.0f) { + for (float& w : virtualFaceViewWeights[idxVF]) { + w /= totalWeight; + } } } - // 3. 统计 - int labeledFaces = 0; - for (Label label : faceLabels) { - if (label > 0) labeledFaces++; - } - - DEBUG_EXTRA("面片标签分配完成: %d/%d (%.1f%%) 个面有视图", - labeledFaces, scene.mesh.faces.size(), - (float)labeledFaces * 100 / scene.mesh.faces.size()); - - // 4. 生成纹理 - Mesh::Image8U3Arr generatedTextures = GenerateTextureAtlasWith3DBridge( - faceLabels, views, existingTextures, existingTexcoords, existingTexindices, - nTextureSizeMultiple, colEmpty, fSharpnessWeight - ); + // 5. 为虚拟面生成纹理图集(使用多视图融合) + Mesh::Image8U3Arr textures = GenerateMultiViewTextureAtlasWithVirtualFaces(virtualFaceMap, virtualFaceDatas, + virtualFaceViews, virtualFaceViewWeights, + nTextureSizeMultiple, colEmpty, fSharpnessWeight); - if (!generatedTextures.empty()) { - scene.mesh.texturesDiffuse = std::move(generatedTextures); + if (!textures.empty()) { + scene.mesh.texturesDiffuse = std::move(textures); - if (scene.mesh.texturesDiffuse.size() > 1) { - scene.mesh.faceTexindices.resize(scene.mesh.faces.size()); - for (size_t i = 0; i < scene.mesh.faces.size(); ++i) { - scene.mesh.faceTexindices[i] = 0; - } - } else { - scene.mesh.faceTexindices.Release(); + // 设置纹理索引 + scene.mesh.faceTexindices.resize(scene.mesh.faces.size()); + for (size_t i = 0; i < scene.mesh.faces.size(); ++i) { + scene.mesh.faceTexindices[i] = 0; + } + + DEBUG_EXTRA("Successfully generated %zu texture atlases with virtual faces", scene.mesh.texturesDiffuse.size()); + + // 保存纹理 + std::string outputDir = "texture_output"; + if (SaveGeneratedTextures(scene.mesh.texturesDiffuse, outputDir)) { + DEBUG_EXTRA("Textures saved to: %s", outputDir.c_str()); } - DEBUG_EXTRA("纹理生成成功: %zu 个纹理", scene.mesh.texturesDiffuse.size()); return true; } - DEBUG_EXTRA("纹理生成失败"); + DEBUG_EXTRA("Texture generation with virtual faces failed"); return false; } -void MeshTexture::ApplyColorConsistencyOptimization( - Image8U3& texture, - const std::vector>& pixelSamples, - int textureSize, +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 (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"); + return false; + } + + return true; + } else { + // 使用原始面片的虚拟面选择 + return FaceViewSelection(minCommonCameras, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views); + } +} + +bool MeshTexture::GenerateTextureWithVirtualFaces(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, + unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, + Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, + const SEACAVE::String& baseFileName, bool bOriginFaceview, Scene* pScene) +{ + DEBUG_EXTRA("Generating texture with virtual faces (bOriginFaceview=%d)", bOriginFaceview); + + if (bOriginFaceview) { + // 使用原始面片生成纹理 + // GenerateTexture 是 void 函数,没有返回值 + GenerateTexture(bGlobalSeamLeveling, bLocalSeamLeveling, nTextureSizeMultiple, + nRectPackingHeuristic, colEmpty, fSharpnessWeight, maxTextureSize, + baseFileName, bOriginFaceview, pScene); + return true; // 假设成功执行 + } else { + // 使用虚拟面生成纹理 + return GenerateTextureWithVirtualFacesInternal(bGlobalSeamLeveling, bLocalSeamLeveling, + nTextureSizeMultiple, nRectPackingHeuristic, + colEmpty, fSharpnessWeight, maxTextureSize, + baseFileName, pScene); + } +} + +bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap, + unsigned minCommonCameras, float fOutlierThreshold, + float fRatioDataSmoothness, int nIgnoreMaskLabel, + 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()) { + m_virtualFaceGeometries.Resize(virtualFaceMap.size()); + } + + // 初始化每个虚拟面的视图数据数组 + for (auto& viewList : faceViews) { + viewList.clear(); + } + for (auto& weightList : faceViewWeights) { + weightList.clear(); + } + + for (size_t i = 0; i < virtualFaceMap.size(); ++i) { + const VirtualFace& vf = virtualFaceMap[i]; + + // 收集所有相关视图 + std::unordered_set candidateViews; + std::vector> 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 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 (allFacesVisible) { + commonViews.push_back(viewID); + } + } + + // 如果共同视图太少,使用所有候选视图 + if (commonViews.size() < minCommonCameras) { + // 将所有候选视图转换为vector + faceViews[i].assign(candidateViews.begin(), candidateViews.end()); + } else { + // 使用共同视图 + faceViews[i] = commonViews; + } + + // 如果仍然没有视图,则跳过 + if (faceViews[i].empty()) { + continue; + } + + // 分配相等的权重 + float weight = 1.0f / 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 + } + + DEBUG_EXTRA("Best view selection completed for %zu virtual faces", virtualFaceMap.size()); + return true; +} + +bool MeshTexture::GenerateTextureWithVirtualFacesInternal(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, + unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, + Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, + const SEACAVE::String& baseFileName, Scene* pScene) +{ + DEBUG_EXTRA("Generating texture with virtual faces internal method"); + + // 1. 加载可见性数据 + std::map> visible_faces_map; + std::unordered_set face_visible_relative; + std::map> edge_faces_map; + std::map> delete_edge_faces_map; + + // 获取基础路径 + std::string basePathStr(baseFileName); + size_t dotPos = basePathStr.find_last_of("."); + if (dotPos != std::string::npos) { + basePathStr = basePathStr.substr(0, dotPos); + } + + if (!scene.LoadVisibleFacesData(visible_faces_map, face_visible_relative, + edge_faces_map, delete_edge_faces_map, basePathStr)) { + DEBUG_EXTRA("Failed to load visibility data"); + return false; + } + + // 2. 创建虚拟面 + VirtualFaceMap virtualFaceMap; + if (!CreateVirtualFacesForExistingUV(virtualFaceMap)) { + DEBUG_EXTRA("Failed to create virtual faces"); + return false; + } + + // 3. 为虚拟面选择最佳视图 + if (!SelectBestViewsForVirtualFaces(virtualFaceMap, 1, 0.0f, 1.0f, -1, IIndexArr())) { + DEBUG_EXTRA("Failed to select best views for virtual faces"); + return false; + } + + // 4. 生成多视图纹理图集 + // 直接调用函数,不进行类型转换 + Mesh::Image8U3Arr textures = GenerateMultiViewTextureAtlasWithVirtualFaces( + virtualFaceMap, virtualFaceDatas, faceViews, faceViewWeights, + nTextureSizeMultiple, colEmpty, fSharpnessWeight); + + if (textures.empty()) { + DEBUG_EXTRA("Failed to generate texture atlas"); + return false; + } + + // 5. 存储纹理 + scene.mesh.texturesDiffuse.swap(textures); + + // 6. 应用UV映射 + if (bGlobalSeamLeveling) { + // TODO: 实现全局缝合优化 + } + + if (bLocalSeamLeveling) { + // TODO: 实现局部缝合优化 + } + + DEBUG_EXTRA("Texture generation with virtual faces completed"); + return true; +} + +bool MeshTexture::CreateVirtualFacesForExistingUV(VirtualFaceMap& virtualFaceMap) { + DEBUG_EXTRA("Creating virtual faces for existing UV texture mapping"); + + // 1. 确保网格拓扑已计算 + if (scene.mesh.faceFaces.empty()) { + scene.mesh.ListIncidenteFaces(); + scene.mesh.ListIncidenteFaceFaces(); + } + + if (scene.mesh.faceNormals.empty()) { + scene.mesh.ComputeNormalFaces(); + } + + // 2. 初始化原始面片标记 + const FIndex numFaces = scene.mesh.faces.size(); + std::vector processedFaces(numFaces, false); + + // 3. 基于曲率分割网格 + Mesh::FaceIdxArr regionMap; + scene.SegmentMeshBasedOnCurvature(regionMap, 0.2f); + + // 4. 统计每个区域的面积 + std::unordered_map regionAreas; + for (FIndex fid = 0; fid < numFaces; ++fid) { + int region = regionMap[fid]; + + // 修复:手动计算三角形面积 + const Mesh::Face& face = scene.mesh.faces[fid]; + const Point3f& v0 = scene.mesh.vertices[face[0]]; + const Point3f& v1 = scene.mesh.vertices[face[1]]; + const Point3f& v2 = scene.mesh.vertices[face[2]]; + + // 计算三角形面积 + Point3f edge1 = v1 - v0; + Point3f edge2 = v2 - v0; + + Point3f crossProd( + edge1.y * edge2.z - edge1.z * edge2.y, + edge1.z * edge2.x - edge1.x * edge2.z, + edge1.x * edge2.y - edge1.y * edge2.x + ); + + float area = 0.5f * std::sqrt( + crossProd.x * crossProd.x + + crossProd.y * crossProd.y + + crossProd.z * crossProd.z + ); + + regionAreas[region] += area; + } + + // 5. 为每个区域创建虚拟面 + std::unordered_map> regionFaces; + for (FIndex fid = 0; fid < numFaces; ++fid) { + regionFaces[regionMap[fid]].push_back(fid); + } + + // 6. 创建虚拟面 + for (const auto& region : regionFaces) { + int regionID = region.first; + const std::vector& faceList = region.second; + + // 检查区域面积是否足够大 + if (regionAreas[regionID] < 0.001f) { // 面积阈值 + // 区域太小,不创建虚拟面 + for (FIndex fid : faceList) { + virtualFaceMap.push_back(VirtualFace()); + virtualFaceMap.back().faces.push_back(fid); + } + continue; + } + + // 检查UV连续性 + if (!CheckUVContinuity(faceList)) { + // UV不连续,保持原始面片 + for (FIndex fid : faceList) { + virtualFaceMap.push_back(VirtualFace()); + virtualFaceMap.back().faces.push_back(fid); + } + continue; + } + + // 创建虚拟面 + VirtualFace vf; + vf.faces = faceList; + + // 计算虚拟面的中心、法线和面积 + CalculateVirtualFaceProperties(vf); + + // 计算虚拟面的UV边界 + CalculateVirtualFaceUVBounds(vf); + + virtualFaceMap.push_back(vf); + } + + DEBUG_EXTRA("Created %zu virtual faces (original faces: %zu)", virtualFaceMap.size(), numFaces); + + return !virtualFaceMap.empty(); +} + +bool MeshTexture::CheckUVContinuity(const std::vector& faceList) { + if (faceList.empty()) return false; + + // 检查UV坐标是否连续 + for (size_t i = 0; i < faceList.size() - 1; ++i) { + const TexCoord* uv1 = &scene.mesh.faceTexcoords[faceList[i] * 3]; + const TexCoord* uv2 = &scene.mesh.faceTexcoords[faceList[i + 1] * 3]; + + // 计算UV坐标的平均距离 + float totalDist = 0.0f; + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 3; ++k) { + float dx = uv1[j].x - uv2[k].x; + float dy = uv1[j].y - uv2[k].y; + totalDist += sqrt(dx*dx + dy*dy); + } + } + + float avgDist = totalDist / 9.0f; + if (avgDist > 0.1f) { // UV不连续性阈值 + return false; + } + } + + return true; +} + +// 在 MeshTexture 类中添加这个函数 +std::vector MeshTexture::GetPixelsInTriangle( + const cv::Point2f& p1, + const cv::Point2f& p2, + const cv::Point2f& p3, + int textureSize) const +{ + std::vector pixels; + + // 获取三角形的边界框 + float minX = std::min({p1.x, p2.x, p3.x}); + float minY = std::min({p1.y, p2.y, p3.y}); + float maxX = std::max({p1.x, p2.x, p3.x}); + float maxY = std::max({p1.y, p2.y, p3.y}); + + // 确保边界框在纹理范围内 + int startX = std::max(0, (int)std::floor(minX)); + int startY = std::max(0, (int)std::floor(minY)); + int endX = std::min(textureSize - 1, (int)std::ceil(maxX)); + int endY = std::min(textureSize - 1, (int)std::ceil(maxY)); + + // 计算三角形的面积 + float area = TriangleArea(p1, p2, p3); + if (area < 1e-6f) { + return pixels; // 退化三角形 + } + + // 扫描线算法 + for (int y = startY; y <= endY; ++y) { + for (int x = startX; x <= endX; ++x) { + // 使用像素中心点 + float px = x + 0.5f; + float py = y + 0.5f; + + // 计算重心坐标 + float w0 = TriangleArea(p2, p3, cv::Point2f(px, py)) / area; + float w1 = TriangleArea(p3, p1, cv::Point2f(px, py)) / area; + float w2 = TriangleArea(p1, p2, cv::Point2f(px, py)) / area; + + // 检查点是否在三角形内 + if (w0 >= 0.0f && w1 >= 0.0f && w2 >= 0.0f) { + pixels.push_back(cv::Point(x, y)); + } + } + } + + return pixels; +} + +// 辅助函数:计算三角形面积 +float MeshTexture::TriangleArea( + const cv::Point2f& p1, + const cv::Point2f& p2, + const cv::Point2f& p3) const +{ + return 0.5f * std::abs( + (p2.x - p1.x) * (p3.y - p1.y) - + (p3.x - p1.x) * (p2.y - p1.y) + ); +} + +Mesh::Image8U3Arr MeshTexture::GenerateMultiViewTextureAtlasWithVirtualFaces( + const VirtualFaceMap& virtualFaceMap, + const VirtualFaceDataArr& virtualFaceDatas, // 改为 VirtualFaceDataArr + const std::vector>& faceViews, + const std::vector>& faceViewWeights, + unsigned nTextureSizeMultiple, + Pixel8U colEmpty, + float fSharpnessWeight) +{ + DEBUG_EXTRA("Generating multi-view texture atlas with virtual faces"); + + // 1. 分析UV布局 + AABB2f uvBounds(true); + FOREACH(i, scene.mesh.faceTexcoords) { + const TexCoord& uv = scene.mesh.faceTexcoords[i]; + uvBounds.InsertFull(uv); + } + + // 2. 计算纹理尺寸 + float uvWidth = uvBounds.ptMax.x() - uvBounds.ptMin.x(); + float uvHeight = uvBounds.ptMax.y() - uvBounds.ptMin.y(); + + if (uvWidth < 0.001f) uvWidth = 1.0f; + if (uvHeight < 0.001f) uvHeight = 1.0f; + + const int textureSize = ComputeOptimalTextureSize(uvWidth, uvHeight, nTextureSizeMultiple); + + // 3. 创建纹理图集 + Mesh::Image8U3Arr textures; + Image8U3& textureAtlas = textures.emplace_back(textureSize, textureSize); + textureAtlas.setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r)); + + // 4. 创建权重图、累积颜色图和采样计数图,用于混合 + cv::Mat1f weightAccum(textureSize, textureSize, 0.0f); + cv::Mat3f colorAccum(textureSize, textureSize, cv::Vec3f(0, 0, 0)); // 用浮点数累积颜色 + cv::Mat1i sampleCount(textureSize, textureSize, 0); // 采样计数,用于统计每个像素被采样了多少次 + + DEBUG_EXTRA("Texture atlas size: %dx%d, UV bounds: [%.3f,%.3f]-[%.3f,%.3f]", + textureSize, textureSize, + uvBounds.ptMin.x(), uvBounds.ptMin.y(), + uvBounds.ptMax.x(), uvBounds.ptMax.y()); + + // 5. 处理每个虚拟面 + #ifdef _USE_OPENMP + #pragma omp parallel for schedule(dynamic) + for (int_t idxVF = 0; idxVF < (int_t)virtualFaceMap.size(); ++idxVF) { + #else + for (size_t idxVF = 0; idxVF < virtualFaceMap.size(); ++idxVF) { + #endif + const VirtualFace& vf = virtualFaceMap[idxVF]; + + // 检查虚拟面是否有可用视图 + if (faceViews[idxVF].empty()) { + continue; + } + + // 处理虚拟面中的每个原始面片 + for (FIndex faceID : vf.faces) { + const Face& face = scene.mesh.faces[faceID]; + const TexCoord* uvCoords = &scene.mesh.faceTexcoords[faceID * 3]; + + // 计算面片在纹理空间中的边界框 + AABB2f faceUVBounds(true); + for (int i = 0; i < 3; ++i) { + faceUVBounds.InsertFull(uvCoords[i]); + } + + const int startX = std::max(0, (int)(faceUVBounds.ptMin.x() * textureSize)); + const int startY = std::max(0, (int)(faceUVBounds.ptMin.y() * textureSize)); + const int endX = std::min(textureSize - 1, (int)(faceUVBounds.ptMax.x() * textureSize)); + const int endY = std::min(textureSize - 1, (int)(faceUVBounds.ptMax.y() * textureSize)); + + // 为当前面片预计算3D点的重心坐标映射 + std::vector texPoints; + std::vector pointColors; // 存储每个采样点的颜色 + + // 均匀采样面片内部 + for (int y = startY; y <= endY; ++y) { + for (int x = startX; x <= endX; ++x) { + const Point2f texCoord((float)x / textureSize, (float)y / textureSize); + + // 计算重心坐标 + Point3f barycentric; + if (PointInTriangle(texCoord, uvCoords[0], uvCoords[1], uvCoords[2], barycentric)) { + // 计算3D点 + const Vertex worldPoint = + vertices[face[0]] * barycentric.x + + vertices[face[1]] * barycentric.y + + vertices[face[2]] * barycentric.z; + + // 为每个视图采样颜色 + cv::Vec3f accumColor(0, 0, 0); + float totalWeight = 0.0f; + + for (size_t viewIdx = 0; viewIdx < faceViews[idxVF].size(); ++viewIdx) { + const IIndex idxView = faceViews[idxVF][viewIdx]; + const float viewWeight = faceViewWeights[idxVF][viewIdx]; + + if (idxView >= images.size()) continue; + + const Image& sourceImage = images[idxView]; + + // 投影到图像 + Point2f imgPoint = ProjectPointWithAutoCorrection(sourceImage.camera, worldPoint, sourceImage); + + // 验证投影 + if (!ValidateProjection(worldPoint, sourceImage, imgPoint) || + !sourceImage.image.isInside(imgPoint) || + !sourceImage.camera.IsInFront(worldPoint)) { + continue; + } + + // 采样图像 + Pixel8U sampledColor = SampleImageBilinear(sourceImage.image, imgPoint); + + // 累积加权颜色 + accumColor[0] += sampledColor.r * viewWeight; + accumColor[1] += sampledColor.g * viewWeight; + accumColor[2] += sampledColor.b * viewWeight; + totalWeight += viewWeight; + } + + if (totalWeight > 0.0f) { + // 平均颜色 + accumColor /= totalWeight; + + // 保存采样点和颜色 + texPoints.emplace_back(texCoord); + pointColors.push_back(accumColor); + } + } + } + } + + // 使用Delaunay三角剖分在面片内部生成均匀采样 + if (texPoints.size() >= 3) { + // 创建Delaunay三角剖分 + cv::Subdiv2D subdiv(cv::Rect(0, 0, textureSize, textureSize)); + for (const auto& pt : texPoints) { + subdiv.insert(cv::Point2f(pt.x * textureSize, pt.y * textureSize)); + } + + std::vector triangleList; + subdiv.getTriangleList(triangleList); + + // 遍历三角形并填充 + for (const auto& t : triangleList) { + cv::Point2f pt1(t[0], t[1]); + cv::Point2f pt2(t[2], t[3]); + cv::Point2f pt3(t[4], t[5]); + + // 获取三角形内的像素 + std::vector pixels = GetPixelsInTriangle(pt1, pt2, pt3, textureSize); + + for (const auto& pixel : pixels) { + if (pixel.x < 0 || pixel.x >= textureSize || + pixel.y < 0 || pixel.y >= textureSize) { + continue; + } + + const Point2f texCoord((float)pixel.x / textureSize, (float)pixel.y / textureSize); + + // 找到最近采样点(使用最近邻插值) + int nearestIdx = 0; + float minDist = std::numeric_limits::max(); + for (size_t i = 0; i < texPoints.size(); ++i) { + float dx = texPoints[i].x - texCoord.x; + float dy = texPoints[i].y - texCoord.y; + float dist = dx*dx + dy*dy; // 使用平方距离避免sqrt + if (dist < minDist) { + minDist = dist; + nearestIdx = i; + } + } + + if (minDist < 25.0f / (textureSize * textureSize)) { // 距离阈值 + // 获取最近采样点的颜色 + const cv::Vec3f& newColor = pointColors[nearestIdx]; + + // 累加颜色和权重 + #ifdef _USE_OPENMP + #pragma omp atomic + #endif + weightAccum(pixel.y, pixel.x) += 1.0f; + + #ifdef _USE_OPENMP + #pragma omp atomic + #endif + sampleCount(pixel.y, pixel.x) += 1; + + #ifdef _USE_OPENMP + #pragma omp critical + #endif + { + colorAccum(pixel.y, pixel.x) += newColor; + } + } + } + } + } + } + } + + // 6. 应用权重归一化 + DEBUG_EXTRA("Applying weight normalization for virtual faces"); + for (int y = 0; y < textureSize; ++y) { + for (int x = 0; x < textureSize; ++x) { + float weight = weightAccum(y, x); + if (weight > 0.0f) { + // 计算加权平均颜色 + cv::Vec3f avgColor = colorAccum(y, x) / weight; + + // 转换为Pixel8U + Pixel8U finalColor; + finalColor.r = (unsigned char)cv::saturate_cast(avgColor[0]); + finalColor.g = (unsigned char)cv::saturate_cast(avgColor[1]); + finalColor.b = (unsigned char)cv::saturate_cast(avgColor[2]); + + textureAtlas(y, x) = finalColor; + } else { + // 保持背景色 + textureAtlas(y, x) = colEmpty; + } + } + } + + // 7. 填充缝隙和未采样区域 + DEBUG_EXTRA("Filling gaps in texture atlas for virtual faces"); + cv::Mat textureMat = (cv::Mat&)textureAtlas; + cv::Mat1f weightMat = weightAccum; + cv::Mat1i sampleMat = sampleCount; + // FillTextureGapsMultiView(textureMat, weightMat, sampleMat, colEmpty); + + // 8. 应用锐化 + if (fSharpnessWeight > 0) { + // ApplySharpening(textureMat, fSharpnessWeight); + } + + DEBUG_EXTRA("Multi-view texture atlas generation with virtual faces complete"); + return textures; +} + +bool MeshTexture::TextureWithExistingUV( + const IIndexArr& views, + int nIgnoreMaskLabel, + float fOutlierThreshold, + unsigned nTextureSizeMultiple, + Pixel8U colEmpty, + float fSharpnessWeight, + const Mesh::Image8U3Arr& existingTextures, + const Mesh::TexCoordArr& existingTexcoords, + const Mesh::TexIndexArr& existingTexindices) +{ + DEBUG_EXTRA("TextureWithExistingUV - 使用3D几何坐标和多视图融合"); + + if (scene.mesh.faceTexcoords.empty()) { + VERBOSE("错误: 网格没有UV坐标"); + return false; + } + + // 1. 为每个面选择最佳视图 + FaceDataViewArr facesDatas; + if (!ListCameraFaces(facesDatas, fOutlierThreshold, nIgnoreMaskLabel, views, false)) { + VERBOSE("错误: 无法列举相机-面片关系"); + return false; + } + + // 2. 分配面片标签 + LabelArr faceLabels(scene.mesh.faces.size()); + std::vector faceConfidences(scene.mesh.faces.size(), 0.0f); + + #ifdef _USE_OPENMP + #pragma omp parallel for schedule(dynamic) + #endif + for (int_t idxFace = 0; idxFace < (int_t)scene.mesh.faces.size(); ++idxFace) { + FIndex faceID = (FIndex)idxFace; + const FaceDataArr& faceDatas = facesDatas[faceID]; + + if (faceDatas.empty()) { + faceLabels[faceID] = 0; + faceConfidences[faceID] = 0.0f; + continue; + } + + // 计算面法线 + const Face& face = scene.mesh.faces[faceID]; + Vertex v0 = vertices[face[1]] - vertices[face[0]]; + Vertex v1 = vertices[face[2]] - vertices[face[0]]; + Vertex normal = v0.cross(v1); + double normVal = cv::norm(normal); + if (normVal > 0) normal = normal / (float)normVal; + else normal = Vertex(0, 0, 1); + + // 计算面中心 + Vertex faceCenter(0, 0, 0); + for (int v = 0; v < 3; ++v) faceCenter += vertices[face[v]]; + faceCenter /= 3.0f; + + // 选择最佳视图 + IIndex bestView = NO_ID; + float bestScore = -1.0f; + + for (const FaceData& data : faceDatas) { + if (data.bInvalidFacesRelative) continue; + + float score = ComputeViewScore(images[data.idxView], faceCenter, normal); + if (score > bestScore) { + bestScore = score; + bestView = data.idxView; + } + } + + if (bestView != NO_ID && bestScore > 0.1f) { + faceLabels[faceID] = bestView + 1; + faceConfidences[faceID] = bestScore; + } else { + faceLabels[faceID] = 0; + faceConfidences[faceID] = 0.0f; + } + } + + // 3. 统计 + int labeledFaces = 0; + for (Label label : faceLabels) { + if (label > 0) labeledFaces++; + } + + DEBUG_EXTRA("面片标签分配完成: %d/%d (%.1f%%) 个面有视图", + labeledFaces, scene.mesh.faces.size(), + (float)labeledFaces * 100 / scene.mesh.faces.size()); + + // 4. 生成纹理 + Mesh::Image8U3Arr generatedTextures = GenerateTextureAtlasWith3DBridge( + faceLabels, views, existingTextures, existingTexcoords, existingTexindices, + nTextureSizeMultiple, colEmpty, fSharpnessWeight + ); + + if (!generatedTextures.empty()) { + scene.mesh.texturesDiffuse = std::move(generatedTextures); + + if (scene.mesh.texturesDiffuse.size() > 1) { + scene.mesh.faceTexindices.resize(scene.mesh.faces.size()); + for (size_t i = 0; i < scene.mesh.faces.size(); ++i) { + scene.mesh.faceTexindices[i] = 0; + } + } else { + scene.mesh.faceTexindices.Release(); + } + + DEBUG_EXTRA("纹理生成成功: %zu 个纹理", scene.mesh.texturesDiffuse.size()); + return true; + } + + DEBUG_EXTRA("纹理生成失败"); + return false; +} + +void MeshTexture::ApplyColorConsistencyOptimization( + Image8U3& texture, + const std::vector>& pixelSamples, + int textureSize, Pixel8U colEmpty) { if (pixelSamples.empty()) return; @@ -16856,36 +18162,33 @@ void MeshTexture::OptimizeViewSelectionWithGraphCut(std::vector& face // - fSharpnessWeight: sharpness weight to be applied on the texture (0 - disabled, 0.5 - good value) // - nIgnoreMaskLabel: label value to ignore in the image mask, stored in the MVS scene or next to each image with '.mask.png' extension (-1 - auto estimate mask for lens distortion, -2 - disabled) bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsigned minCommonCameras, float fOutlierThreshold, float fRatioDataSmoothness, - bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, - int nIgnoreMaskLabel, int maxTextureSize, const IIndexArr& views, const SEACAVE::String& baseFileName, bool bOriginFaceview, - const std::string& inputFileName, const std::string& meshFileName, bool bUseExistingUV, const std::string& strUVMeshFileName) + bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, + int nIgnoreMaskLabel, int maxTextureSize, const IIndexArr& views, const SEACAVE::String& baseFileName, bool bOriginFaceview, + const std::string& inputFileName, const std::string& meshFileName, bool bUseExistingUV, const std::string& strUVMeshFileName) { - nTextureSizeMultiple = 8192; // 8192 4096 + nTextureSizeMultiple = 8192; // 8192 4096 - // if (!bOriginFaceview && !bUseExistingUV) - if (!bOriginFaceview) - { - // 确保网格拓扑结构已计算 - if (mesh.faceFaces.empty()) { - mesh.ListIncidenteFaces(); // 计算顶点-面邻接关系 - mesh.ListIncidenteFaceFaces(); // 计算面-面邻接关系 - } - - // 确保法向量已计算 - if (mesh.faceNormals.empty()) { - mesh.ComputeNormalFaces(); // 计算面法向量 - } - - // 确保顶点边界信息已计算 - if (mesh.vertexBoundary.empty()) { - mesh.ListBoundaryVertices(); // 计算边界顶点 - } - - Mesh::FaceIdxArr regionMap; - this->SegmentMeshBasedOnCurvature(regionMap, 0.2f); // 曲率阈值设为0.2 - } + // 预处理:计算网格拓扑和几何信息 + if (!bOriginFaceview) + { + // 确保网格拓扑结构已计算 + if (mesh.faceFaces.empty()) { + mesh.ListIncidenteFaces(); // 计算顶点-面邻接关系 + mesh.ListIncidenteFaceFaces(); // 计算面-面邻接关系 + } + + // 确保法向量已计算 + if (mesh.faceNormals.empty()) { + mesh.ComputeNormalFaces(); // 计算面法向量 + } + + // 确保顶点边界信息已计算 + if (mesh.vertexBoundary.empty()) { + mesh.ListBoundaryVertices(); // 计算边界顶点 + } + } - MeshTexture texture(*this, nResolutionLevel, nMinResolution); + MeshTexture texture(*this, nResolutionLevel, nMinResolution); std::string id; @@ -16912,105 +18215,99 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi printf("id=%s\n", id.c_str()); #ifdef MASK_FACE_OCCLUSION - fs::path p(baseFileName.c_str()); + // 加载可见性数据 + //* + fs::path p(baseFileName.c_str()); + // 2. 获取父路径 (e.g., /path/to/data/scene) fs::path parent = p.parent_path(); + // 4. 转换为字符串,并附加一个路径分隔符 + // ( / "" 会自动处理,确保 /path/to/data 变为 /path/to/data/ ) std::string basePath = (parent / "").string(); + //*/ + /* + std::string basePath = ""; + size_t lastSlash = baseFileName.find_last_of('/'); + size_t secondLastSlash = baseFileName.find_last_of('/', lastSlash - 1); + if (secondLastSlash == std::string::npos) + basePath = baseFileName; + basePath = baseFileName.substr(0, secondLastSlash + 1); + /*/ - if (!LoadVisibleFacesData(visible_faces_map, face_visible_relative, edge_faces_map, delete_edge_faces_map, basePath)) - { - printf("LoadVisibleFacesData error\n"); - } + // printf("basePath=%s\n", basePath.c_str()); + + if (!LoadVisibleFacesData(visible_faces_map, face_visible_relative, edge_faces_map, delete_edge_faces_map, basePath)) + { + printf("LoadVisibleFacesData error\n"); + } #endif - // 为每个面分配最佳视图 - { - TD_TIMER_STARTD(); - if (bOriginFaceview) - { - if (!texture.FaceViewSelection(minCommonCameras, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views)) - return false; - } - else - { - // 使用原来的函数,避免编译错误 - if (!texture.FaceViewSelection3(minCommonCameras, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views, bUseExistingUV)) - return false; - - DEBUG_EXTRA("Enhanced face view selection completed: %u faces (%s)", - mesh.faces.size(), TD_TIMER_GET_FMT().c_str()); - } - DEBUG_EXTRA("Assigning the best view to each face completed: %u faces (%s)", mesh.faces.size(), TD_TIMER_GET_FMT().c_str()); - } + // assign the best view to each face + { + TD_TIMER_STARTD(); + if (bOriginFaceview) + { + // 使用原始面片视图选择 + if (!texture.FaceViewSelection(minCommonCameras, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views)) + return false; + } + else + { + // 使用虚拟面优化策略 + if (!texture.FaceViewSelectionWithVirtualFaces(minCommonCameras, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views, bUseExistingUV)) + return false; + + DEBUG_EXTRA("Virtual face view selection completed: %u faces (%s)", mesh.faces.size(), TD_TIMER_GET_FMT().c_str()); + } + DEBUG_EXTRA("Assigning the best view to each face completed: %u faces (%s)", mesh.faces.size(), TD_TIMER_GET_FMT().c_str()); + } - // mesh.CheckUVValid(); + // 检查UV有效性 + mesh.CheckUVValid(); - DEBUG_EXTRA("TextureMesh %b, %s", bUseExistingUV, strUVMeshFileName.c_str()); - if (bUseExistingUV && !strUVMeshFileName.empty()) { - // 1. 生成临时纹理和UV - Mesh::TexCoordArr existingTexcoords; - Mesh::TexIndexArr existingTexindices; - - // 使用原来的GenerateTexture函数 - texture.GenerateTexture( - bGlobalSeamLeveling, bLocalSeamLeveling, nTextureSizeMultiple, - nRectPackingHeuristic, colEmpty, fSharpnessWeight, maxTextureSize, - baseFileName, bOriginFaceview, this); - - // 保存生成的纹理数据 - Mesh::Image8U3Arr existingTextures = texture.texturesDiffuseTemp; - - VERBOSE("1faceTexcoords.size=%d, faces.size=%d", mesh.faceTexcoords.size(), mesh.faces.size() * 3); - - // 2. 使用预计算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); - - if (mesh.faceTexcoords.empty()) { - VERBOSE("error: the specified mesh does not contain UV coordinates"); - return false; - } - - // 3. 使用新的纹理生成方法 - MeshTexture texture2(*this, nResolutionLevel, nMinResolution); - - // 关键:确保几何信息正确 - texture2.scene.mesh.vertices = mesh.vertices; - texture2.scene.mesh.faces = mesh.faces; - texture2.scene.mesh.faceTexcoords = mesh.faceTexcoords; // 使用外部UV - - // 使用原来的TextureWithExistingUV函数 - if (!texture2.TextureWithExistingUV(views, nIgnoreMaskLabel, fOutlierThreshold, - nTextureSizeMultiple, colEmpty, fSharpnessWeight, - existingTextures, existingTexcoords, existingTexindices)) { - return false; - } - - // 4. 将生成的纹理赋值回场景网格 - mesh.texturesDiffuse = std::move(texture2.scene.mesh.texturesDiffuse); - mesh.faceTexindices = std::move(texture2.scene.mesh.faceTexindices); - - return true; - } + 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; + } - // mesh.CheckUVValid(); + // 使用虚拟面优化的纹理生成 + if (!texture.TextureWithExistingUVVirtualFaces(views, nIgnoreMaskLabel, fOutlierThreshold, nTextureSizeMultiple, colEmpty, fSharpnessWeight)){ + return false; + } + return true; + } - // 生成纹理图像和图集 - { - TD_TIMER_STARTD(); - - // 使用原来的GenerateTexture函数 - texture.GenerateTexture(bGlobalSeamLeveling, bLocalSeamLeveling, nTextureSizeMultiple, nRectPackingHeuristic, colEmpty, fSharpnessWeight, maxTextureSize, baseFileName, bOriginFaceview, this); - DEBUG_EXTRA("Generating enhanced texture completed: %u textures (%s)", - mesh.texturesDiffuse.size(), TD_TIMER_GET_FMT().c_str()); - } + // generate the texture image and atlas + { + TD_TIMER_STARTD(); + if (!texture.GenerateTextureWithVirtualFaces(bGlobalSeamLeveling, bLocalSeamLeveling, nTextureSizeMultiple, nRectPackingHeuristic, + colEmpty, fSharpnessWeight, maxTextureSize, baseFileName, bOriginFaceview, this)) + { + return false; + } + DEBUG_EXTRA("Generating texture atlas and image completed: %u patches, %u image size, %u textures (%s)", + texture.texturePatches.size(), mesh.texturesDiffuse[0].width(), mesh.texturesDiffuse.size(), TD_TIMER_GET_FMT().c_str()); + } - // mesh.CheckUVValid(); + // 最终UV检查 + mesh.CheckUVValid(); - return true; + return true; } // TextureMesh std::string Scene::runPython(const std::string& command) {