diff --git a/libs/MVS/Scene.h b/libs/MVS/Scene.h index 3024d60..64f4084 100644 --- a/libs/MVS/Scene.h +++ b/libs/MVS/Scene.h @@ -65,6 +65,7 @@ public: std::map> visible_faces_map; std::map> edge_faces_map; std::map> delete_edge_faces_map; + std::map> delete_edge_faces_map2; std::map> face_normal_visible_map; std::unordered_set face_visible_relative; @@ -164,6 +165,7 @@ public: std::unordered_set& face_visible_relative, std::map>& edge_faces_map, std::map>& delete_edge_faces_map, + std::map>& delete_edge_faces_map2, std::map>& face_normal_visible_map, std::string& basePath); @@ -178,6 +180,7 @@ public: bool is_face_visible_relative(int face_index); bool is_face_edge(const std::string& image_name, int face_index); bool is_face_delete_edge(const std::string& image_name, int face_index); + bool is_face_delete_edge2(const std::string& image_name, int face_index); bool is_face_normal_visible_map(const std::string& image_name, int face_index); void SegmentMeshBasedOnCurvature(Mesh::FaceIdxArr& regionMap, float curvatureThreshold); diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index 721c17a..c5e62ee 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -288,6 +288,14 @@ struct MeshTexture { #endif bool bInvalidFacesRelative = false; }; + struct ViewCoverageData { + IIndex viewIdx; + // 快速查找面片索引的映射 + std::unordered_map faceToIndexMap; + ViewCoverageData() = default; + explicit ViewCoverageData(IIndex idx) : viewIdx(idx) {} + }; + mutable std::unordered_map mapViewCoverageData; typedef cList FaceDataArr; // store information about one face seen from several views typedef cList FaceDataViewArr; // store data for all the faces of the mesh @@ -462,6 +470,7 @@ public: bool CreateVirtualFaces61(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f); bool CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataViewArr& ComputeAverageQuality, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; bool CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; + bool CreateVirtualFaces64(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; static std::string GetFileNameWithoutExtension(std::string& strPath); float CalculateBrightnessScore(const Image& imageData) const; bool IsFaceVisibleRelaxed(const FaceDataArr& faceDatas, const IIndexArr& selectedCams, float visibleRatioThreshold) const; @@ -4306,318 +4315,1518 @@ std::string MeshTexture::GetFileNameWithoutExtension(std::string& strPath) { } } -bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras, float thMaxNormalDeviation) const +bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, + VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, + unsigned minCommonCameras, float thMaxNormalDeviation) const { + if (meshCurvatures.empty()) { ComputeFaceCurvatures(); } - float thMaxColorDeviation = 130.0f; - const float QUALITY_THRESHOLD = 0.9f; // 质量阈值,可根据实际情况调整 + // 如果夹角小于45度(cos(45°) ≈ 0.7071),则计入覆盖 + float fAngleThreshold = 0.7071f; // 0.7071f + + // 初始化数据结构 + std::vector processedFaces(faces.size(), false); + std::vector> viewCoverage; // 视图索引和覆盖的面片数量 - const float ratioAngleToQuality(0.67f); - const float cosMaxNormalDeviation(COS(FD2R(thMaxNormalDeviation))); - Mesh::FaceIdxArr remainingFaces(faces.size()); - std::iota(remainingFaces.begin(), remainingFaces.end(), 0); - std::vector selectedFaces(faces.size(), false); - cQueue currentVirtualFaceQueue; - std::unordered_set queuedFaces; - - // Precompute average color for each face - Colors faceColors; - faceColors.reserve(faces.size()); - for (size_t i = 0; i < faces.size(); ++i) { - faceColors.push_back(Color::ZERO); - } - for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { - const FaceDataArr& faceDatas = facesDatas[idxFace]; - if (faceDatas.empty()) continue; - Color sumColor = Color::ZERO; - for (const FaceData& fd : faceDatas) { - sumColor += fd.color; + DEBUG_EXTRA("开始新的虚拟面片创建逻辑: 基于视图排序"); + + // 1. 计算每个视图的覆盖情况 + Util::Progress progress1(_T("计算视图覆盖"), images.size()); + for (IIndex idxView = 0; idxView < images.size(); ++idxView) { + if (!images[idxView].IsValid()) { + ++progress1; + continue; } - faceColors[idxFace] = sumColor / faceDatas.size(); - } - - do { - const FIndex startPos = RAND() % remainingFaces.size(); - const FIndex virtualFaceCenterFaceID = remainingFaces[startPos]; - - // 动态法线阈值 - const float centerCurvature = meshCurvatures[virtualFaceCenterFaceID]; - const float dynamicThreshold = (centerCurvature < 0.2f) ? 18.0f : 10.0f; // 放宽角度阈值 - const float dynamicCosTh = COS(FD2R(dynamicThreshold)); - - ASSERT(currentVirtualFaceQueue.IsEmpty()); - const Normal& normalCenter = scene.mesh.faceNormals[virtualFaceCenterFaceID]; - const FaceDataArr& centerFaceDatas = facesDatas[virtualFaceCenterFaceID]; - - // 检查中心面片是否包含无效视图 - bool bHasInvalidView = false; - int nInvalidViewCount = 0; - int nTotalViewCount = 0; - for (const FaceData& faceData : centerFaceDatas) { - if (faceData.bInvalidFacesRelative) { - bHasInvalidView = true; - ++nInvalidViewCount; - } - ++nTotalViewCount; + + int coverageCount = 0; + const Image& imageData = images[idxView]; + + // 计算相机方向 + const RMatrix& R = imageData.camera.R; + Point3f cameraForward( + -R(0,2), // 相机坐标系中-Z轴是向前方向(从相机指向场景) + -R(1,2), + -R(2,2) + ); + + // 归一化相机方向 + const float normCameraForward = std::sqrt( + cameraForward.x * cameraForward.x + + cameraForward.y * cameraForward.y + + cameraForward.z * cameraForward.z + ); + if (normCameraForward > 0) { + cameraForward /= normCameraForward; } - // 计算中心面片的质量 - float centerFaceQuality = 0.0f; - int validViewCount = 0; - for (const FaceData& fd : centerFaceDatas) { - if (!fd.bInvalidFacesRelative) { - centerFaceQuality += fd.quality; - ++validViewCount; + // 遍历所有面片,统计满足条件的面片 + for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { + // 跳过已处理的面片 + if (processedFaces[idxFace]) { + continue; + } + + // 检查面片是否有视图数据 + if (facesDatas[idxFace].empty()) { + continue; + } + + // 检查视图是否能看到这个面片 + bool viewSeesFace = false; + float bestQuality = 0.0f; + + for (const FaceData& fd : facesDatas[idxFace]) { + if (fd.idxView == idxView && !fd.bInvalidFacesRelative) { + viewSeesFace = true; + if (fd.quality > bestQuality) { + bestQuality = fd.quality; + } + } + } + + if (!viewSeesFace) { + continue; + } + + // 检查面片法线与相机方向的夹角 + const Normal& faceNormal = scene.mesh.faceNormals[idxFace]; + const float cosAngle = cameraForward.dot(Point3f(faceNormal.x, faceNormal.y, faceNormal.z)); + + if (cosAngle > fAngleThreshold) + { // 45度阈值 + coverageCount++; } } - if (validViewCount > 0) { - centerFaceQuality /= validViewCount; + + if (coverageCount > 0) { + viewCoverage.emplace_back(idxView, coverageCount); } - std::vector> sortedViews; - std::vector> sortedLuminViews; - std::vector> validViews; - sortedViews.reserve(centerFaceDatas.size()); - for (const FaceData& fd : centerFaceDatas) { - if (fd.bInvalidFacesRelative) { - sortedViews.emplace_back(fd.quality, fd.color); - sortedLuminViews.emplace_back(MeshTexture::GetLuminance(fd.color), fd.color); - } else { - sortedViews.emplace_back(fd.quality, fd.color); - sortedLuminViews.emplace_back(MeshTexture::GetLuminance(fd.color), fd.color); - validViews.emplace_back(fd.quality, fd.color); + ++progress1; + } + progress1.close(); + + // 2. 按覆盖数量对视图排序(从高到低) + std::sort(viewCoverage.begin(), viewCoverage.end(), + [](const auto& a, const auto& b) { return a.second > b.second; }); + + // 打印排序结果 + DEBUG_EXTRA("视图覆盖统计(按覆盖数量从高到低排序):"); + int totalCoverage = 0; + for (const auto& [idxView, coverage] : viewCoverage) { + const Image& imageData = images[idxView]; + DEBUG_EXTRA("视图 %s (索引 %d): 覆盖 %d 个面片", + imageData.name.c_str(), idxView, coverage); + totalCoverage += coverage; + } + + DEBUG_EXTRA("排序后视图数量: %zu,最大覆盖: %d, 共%d", viewCoverage.size(), + viewCoverage.empty() ? 0 : viewCoverage[0].second, totalCoverage); + + // 3. 按排序后的视图遍历,创建虚拟面片 + Util::Progress progress2(_T("创建虚拟面片"), viewCoverage.size()); + int totalVirtualFaces = 0; + int facesAssigned = 0; + + for (const auto& [idxView, coverage] : viewCoverage) { + if (coverage == 0) { + ++progress2; + continue; + } + + const Image& imageData = images[idxView]; + if (!imageData.IsValid()) { + ++progress2; + continue; + } + + // 获取相机方向 + const RMatrix& R = imageData.camera.R; + Point3f cameraForward(R(0,2), R(1,2), R(2,2)); + const float normCameraForward = std::sqrt( + cameraForward.x * cameraForward.x + + cameraForward.y * cameraForward.y + + cameraForward.z * cameraForward.z + ); + if (normCameraForward > 0) { + cameraForward /= normCameraForward; + } + + // 计算视图的质量阈值 + float viewQualityThreshold = 0.0f; + int validFaceCount = 0; + + for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { + if (!processedFaces[idxFace]) { + for (const FaceData& fd : facesDatas[idxFace]) { + if (fd.idxView == idxView && !fd.bInvalidFacesRelative) { + viewQualityThreshold += fd.quality; + validFaceCount++; + break; + } + } } } - std::sort(sortedViews.begin(), sortedViews.end(), - [](const auto& a, const auto& b) { return a.first > b.first; }); - std::sort(validViews.begin(), validViews.end(), - [](const auto& a, const auto& b) { return a.first > b.first; }); - - int nSize = sortedViews.size(); - float totalQuality = 0.0f; - Color totalColor(0,0,0); - for (int n = 0; n < nSize; ++n) { - totalQuality += sortedViews[n].first; - totalColor += sortedViews[n].second; + + if (validFaceCount > 0) { + viewQualityThreshold /= validFaceCount; } - const float avgQuality = totalQuality / nSize; - const Color avgColor = totalColor / nSize; - - float totalLuminance = MeshTexture::GetLuminance(totalColor); - float avgLuminance = totalLuminance / nSize; - std::sort(sortedLuminViews.begin(), sortedLuminViews.end(), - [avgLuminance](const auto& a, const auto& b) { - float luminDistA = cv::norm(avgLuminance - a.first); - float luminDistB = cv::norm(avgLuminance - b.first); - return luminDistA < luminDistB; }); - - // select the common cameras - Mesh::FaceIdxArr virtualFace; - FaceDataArr virtualFaceDatas; - if (centerFaceDatas.empty()) { - virtualFace.emplace_back(virtualFaceCenterFaceID); - selectedFaces[virtualFaceCenterFaceID] = true; - const auto posToErase = remainingFaces.FindFirst(virtualFaceCenterFaceID); - ASSERT(posToErase != Mesh::FaceIdxArr::NO_INDEX); - remainingFaces.RemoveAtMove(posToErase); - } else { - IIndexArr selectedCams = SelectBestViews(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality); + + // 收集满足条件的面片 + std::vector candidateFaces; + std::vector faceQualities; + + for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { + if (processedFaces[idxFace]) { + continue; + } - const Normal& normalCenter = scene.mesh.faceNormals[virtualFaceCenterFaceID]; - std::vector> cameraAngles; // 存储相机索引和角度 - - for (IIndex idxView : selectedCams) { - const Image& imageData = images[idxView]; - const RMatrix& R = imageData.camera.R; - Point3f localForward(0.0f, 0.0f, -1.0f); - Point3f cameraForward; - cameraForward.x = R(0,0) * localForward.x + R(0,1) * localForward.y + R(0,2) * localForward.z; - cameraForward.y = R(1,0) * localForward.x + R(1,1) * localForward.y + R(1,2) * localForward.z; - cameraForward.z = R(2,0) * localForward.x + R(2,1) * localForward.y + R(2,2) * localForward.z; - - float norm = std::sqrt(cameraForward.x * cameraForward.x + - cameraForward.y * cameraForward.y + - cameraForward.z * cameraForward.z); - if (norm > 0.0f) { - cameraForward.x /= norm; - cameraForward.y /= norm; - cameraForward.z /= norm; - } else { - cameraForward = Point3f(0, 0, -1); - } - - Point3f normalPoint(normalCenter.x, normalCenter.y, normalCenter.z); - float cosAngle = cameraForward.dot(normalPoint); - float angleDeg = std::acos(cosAngle) * 180.0f / M_PI; - - std::string strPath = imageData.name; - std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); - - if (!scene.is_face_delete_edge(strName, virtualFaceCenterFaceID)) { - if (scene.is_face_edge(strName, virtualFaceCenterFaceID)) { - if (angleDeg <= 40.0f) { - cameraAngles.emplace_back(idxView, angleDeg); - } - } else { - cameraAngles.emplace_back(idxView, angleDeg); + if (facesDatas[idxFace].empty()) { + continue; + } + + // 检查视图是否能看到这个面片 + float bestFaceQuality = 0.0f; + bool viewSeesFace = false; + + for (const FaceData& fd : facesDatas[idxFace]) { + if (fd.idxView == idxView && !fd.bInvalidFacesRelative) { + viewSeesFace = true; + if (fd.quality > bestFaceQuality) { + bestFaceQuality = fd.quality; } } } - - // 按angleDeg从小到大排序 - std::vector> sortedCams = cameraAngles; - std::sort(sortedCams.begin(), sortedCams.end(), - [](const std::pair& a, const std::pair& b) { - return a.second < b.second; - }); - IIndexArr filteredCams; - size_t count = std::min(sortedCams.size(), static_cast(3)); - for (size_t i = 0; i < count; ++i) { - filteredCams.push_back(sortedCams[i].first); + if (!viewSeesFace) { + continue; } - - if (filteredCams.empty()) { - // 处理空情况 - selectedCams = filteredCams; - isVirtualFace[virtualFaceCenterFaceID] = false; - } else { - selectedCams = filteredCams; - isVirtualFace[virtualFaceCenterFaceID] = true; + + // 检查面片法线与相机方向的夹角 + const Normal& faceNormal = scene.mesh.faceNormals[idxFace]; + const float cosAngle = cameraForward.dot(Point3f(faceNormal.x, faceNormal.y, faceNormal.z)); + + // 阈值:夹角小于45度 + if (cosAngle > fAngleThreshold && bestFaceQuality >= viewQualityThreshold * 0.5f) + { + candidateFaces.push_back(idxFace); + faceQualities.push_back(bestFaceQuality); } + } + + if (candidateFaces.empty()) { + ++progress2; + continue; + } + + // 按质量对候选面片排序 + std::vector indices(candidateFaces.size()); + std::iota(indices.begin(), indices.end(), 0); + std::sort(indices.begin(), indices.end(), + [&](size_t a, size_t b) { return faceQualities[a] > faceQualities[b]; }); + + // 使用区域增长算法创建虚拟面片 + std::vector visitedInView(candidateFaces.size(), false); + + DEBUG_EXTRA("使用区域增长算法创建虚拟面片 candidateFaces=%zu", candidateFaces.size()); - currentVirtualFaceQueue.AddTail(virtualFaceCenterFaceID); - queuedFaces.clear(); - do { - const FIndex currentFaceId = currentVirtualFaceQueue.GetHead(); - currentVirtualFaceQueue.PopHead(); + // 确保数据一致性检查 + ASSERT(candidateFaces.size() == visitedInView.size()); + if (candidateFaces.empty()) { + DEBUG_EXTRA("候选面片列表为空,跳过"); + continue; + } - const Normal& faceNormal = scene.mesh.faceNormals[currentFaceId]; - const float cosFaceToCenter(ComputeAngleN(normalCenter.ptr(), faceNormal.ptr())); - if (cosFaceToCenter < dynamicCosTh) - continue; + for (size_t i = 0; i < indices.size(); ++i) { + // 安全检查:索引有效性 + if (i >= indices.size()) { + DEBUG_EXTRA("错误: 索引 i=%zu 超出范围 indices.size()=%zu", i, indices.size()); + break; + } + + if (visitedInView[i]) { + continue; + } + + // 安全检查:indices[i] 有效性 + if (indices[i] >= candidateFaces.size()) { + DEBUG_EXTRA("错误: indices[%zu]=%zu 超出 candidateFaces 范围(%zu)", + i, indices[i], candidateFaces.size()); + continue; + } + + const FIndex startFace = candidateFaces[indices[i]]; + + // 安全检查:startFace 有效性 + if (startFace >= faces.size() || startFace >= processedFaces.size() || + startFace >= faceFaces.size() || startFace >= scene.mesh.faceNormals.size()) { + DEBUG_EXTRA("错误: 起始面片索引 %d 无效 (总数: faces=%zu, processedFaces=%zu, faceFaces=%zu, faceNormals=%zu)", + startFace, faces.size(), processedFaces.size(), faceFaces.size(), scene.mesh.faceNormals.size()); + continue; + } + + if (processedFaces[startFace]) { + visitedInView[i] = true; + continue; + } + + DEBUG_EXTRA("开始区域增长,起始面片: %d", startFace); + + // 从当前面片开始区域增长 + std::vector virtualFace; + std::queue faceQueue; + faceQueue.push(startFace); + virtualFace.push_back(startFace); + processedFaces[startFace] = true; + + // 标记在候选列表中的索引 + visitedInView[i] = true; + + while (!faceQueue.empty()) { + FIndex currentFace = faceQueue.front(); + faceQueue.pop(); + + // 安全检查:currentFace 有效性 + if (currentFace >= faceFaces.size()) { + DEBUG_EXTRA("错误: 当前面片 %d 超出 faceFaces 范围(%zu)", + currentFace, faceFaces.size()); + continue; + } + + // 检查相邻面片 + const Mesh::FaceFaces& neighbors = faceFaces[currentFace]; + for (int n = 0; n < 3; ++n) { + FIndex neighbor = neighbors[n]; + if (neighbor == NO_ID) { + continue; + } + + // 安全检查:neighbor 有效性 + if (neighbor >= faces.size() || neighbor >= processedFaces.size() || + neighbor >= faceFaces.size() || neighbor >= scene.mesh.faceNormals.size()) { + DEBUG_EXTRA("警告: 邻居面片索引 %d 无效,跳过", neighbor); + continue; + } + + if (processedFaces[neighbor]) { + continue; + } + + // 检查邻居是否在当前视图的候选列表中 + auto it = std::find(candidateFaces.begin(), candidateFaces.end(), neighbor); + if (it == candidateFaces.end()) { + continue; + } + + // 安全检查:it 的有效性 + if (it < candidateFaces.begin() || it >= candidateFaces.end()) { + DEBUG_EXTRA("警告: 无效的迭代器"); + continue; + } + + size_t neighborIdx = std::distance(candidateFaces.begin(), it); + + // 安全检查:neighborIdx 有效性 + if (neighborIdx >= candidateFaces.size() || neighborIdx >= visitedInView.size()) { + DEBUG_EXTRA("错误: 邻居索引 %zu 无效 (candidateFaces.size=%zu, visitedInView.size=%zu)", + neighborIdx, candidateFaces.size(), visitedInView.size()); + continue; + } + + if (visitedInView[neighborIdx]) { + continue; + } + + // 检查邻居面片是否满足条件 + const Normal& neighborNormal = scene.mesh.faceNormals[neighbor]; + + // 转换法线为 Point3f + Point3f neighborNormalPoint(neighborNormal.x, neighborNormal.y, neighborNormal.z); + + // 归一化 + float norm = std::sqrt(neighborNormalPoint.x * neighborNormalPoint.x + + neighborNormalPoint.y * neighborNormalPoint.y + + neighborNormalPoint.z * neighborNormalPoint.z); + if (norm > 0.0f) { + neighborNormalPoint.x /= norm; + neighborNormalPoint.y /= norm; + neighborNormalPoint.z /= norm; + } + + const float cosAngleNeighbor = cameraForward.dot(neighborNormalPoint); + + if (cosAngleNeighbor > 0.7071f) { // 45度阈值 + visitedInView[neighborIdx] = true; + virtualFace.push_back(neighbor); + faceQueue.push(neighbor); + processedFaces[neighbor] = true; + facesAssigned++; + } + } + } + + // 如果虚拟面片足够大,保存它 + if (virtualFace.size() >= 1) { + DEBUG_EXTRA("创建虚拟面片,包含 %zu 个面片", virtualFace.size()); + + // 创建虚拟面片数据 + FaceDataArr virtualFaceData; + FaceData& vfd = virtualFaceData.emplace_back(); + vfd.idxView = idxView; + vfd.quality = 0.0f; + + // 计算平均质量 + float avgQuality = 0.0f; + int validFaces = 0; + for (FIndex fid : virtualFace) { + // 安全检查:fid 有效性 + if (fid >= facesDatas.size()) { + DEBUG_EXTRA("警告: 面片索引 %d 超出 facesDatas 范围(%zu)", + fid, facesDatas.size()); + continue; + } + + float bestQuality = 0.0f; + for (const FaceData& fd : facesDatas[fid]) { + if (fd.idxView == idxView && fd.quality > bestQuality) { + bestQuality = fd.quality; + } + } + avgQuality += bestQuality; + validFaces++; + } + + if (validFaces > 0) { + vfd.quality = avgQuality / validFaces; + + // 转换为 Mesh::FaceIdxArr + Mesh::FaceIdxArr virtualFaceArr; + virtualFaceArr.reserve(virtualFace.size()); + for (FIndex fid : virtualFace) { + virtualFaceArr.emplace_back(fid); + } + + // 保存虚拟面片 + virtualFaces.push_back(virtualFaceArr); + virtualFacesDatas.push_back(virtualFaceData); + totalVirtualFaces++; + + DEBUG_EXTRA("虚拟面片 %zu: %zu 个面片,视图 %d,质量 %.3f", + totalVirtualFaces, virtualFaceArr.size(), idxView, vfd.quality); + + // 标记虚拟面片 + for (FIndex fid : virtualFace) { + if (fid < isVirtualFace.size()) { + isVirtualFace[fid] = true; + } else { + DEBUG_EXTRA("警告: 面片索引 %d 超出 isVirtualFace 范围(%zu)", + fid, isVirtualFace.size()); + } + } + } else { + DEBUG_EXTRA("警告: 虚拟面片没有有效面片"); + } + } else { + DEBUG_EXTRA("虚拟面片太小(%zu),忽略", virtualFace.size()); + + // 如果太小,恢复已处理标记 + for (FIndex fid : virtualFace) { + if (fid < processedFaces.size()) { + processedFaces[fid] = false; + } + } + } + } + + ++progress2; + } + progress2.close(); + + // 4. 处理剩余未分配的面片 + int remainingFaces = 0; + for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { + if (!processedFaces[idxFace] && !facesDatas[idxFace].empty()) { + remainingFaces++; + } + } - ASSERT(!selectedCams.empty()); - if (!IsFaceVisible(facesDatas[currentFaceId], selectedCams)) + DEBUG_EXTRA("有 %d 个面片未分配,将使用改进的后备策略", remainingFaces); + + if (remainingFaces > 0) { + + // 首先检查数据一致性 + ASSERT(processedFaces.size() == faces.size()); + ASSERT(facesDatas.size() == faces.size()); + ASSERT(faceFaces.size() == faces.size()); + if (!isVirtualFace.empty()) { + ASSERT(isVirtualFace.size() == faces.size()); + } + + // 改进的后备策略:将剩余面片分组合并 + // 这里使用 std::vector 而不是 std::set 以避免自动排序 + std::vector remainingFaceList; + for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { + if (!processedFaces[idxFace] && !facesDatas[idxFace].empty()) { + // 检查索引有效性 + if (idxFace >= faces.size()) { + DEBUG_EXTRA("错误: 面片索引 %d 超出范围 (总数=%zu)", idxFace, faces.size()); + continue; + } + remainingFaceList.push_back(idxFace); + } + } + + DEBUG_EXTRA("需要处理的剩余面片总数: %zu", remainingFaceList.size()); + if (remainingFaceList.empty()) { + DEBUG_EXTRA("没有需要处理的剩余面片"); + return false; + } + + // 分批处理 + const size_t BATCH_SIZE = 1000; + size_t batchCount = (remainingFaceList.size() + BATCH_SIZE - 1) / BATCH_SIZE; + + for (size_t batchIdx = 0; batchIdx < batchCount; ++batchIdx) { + size_t startIdx = batchIdx * BATCH_SIZE; + size_t endIdx = std::min(startIdx + BATCH_SIZE, remainingFaceList.size()); + + DEBUG_EXTRA("处理批次 %zu/%zu: 面片 %zu-%zu", + batchIdx + 1, batchCount, startIdx, endIdx - 1); + + // 检查批次索引有效性 + if (startIdx >= remainingFaceList.size() || endIdx > remainingFaceList.size()) { + DEBUG_EXTRA("错误: 批次索引越界"); + continue; + } + + // 当前批次的面片 + std::vector currentBatch( + remainingFaceList.begin() + startIdx, + remainingFaceList.begin() + endIdx + ); + + // 确保有面片需要处理 + if (currentBatch.empty()) { + continue; + } + + // 为当前批次创建虚拟面片 + std::vector batchProcessed(currentBatch.size(), false); + + for (size_t i = 0; i < currentBatch.size(); ++i) { + if (batchProcessed[i]) { continue; - - // 修改3:调整颜色差异检查 - const Color& centerColor = faceColors[virtualFaceCenterFaceID]; - const Color& currentColor = faceColors[currentFaceId]; - float colorDistance = cv::norm(centerColor - currentColor); - - // 放宽颜色差异条件 - if (colorDistance > 250.0f) { // 增加阈值 - // 不跳过,继续处理 } - if (colorDistance > thMaxColorDeviation) { - // 保持原有逻辑 + FIndex idxFace = currentBatch[i]; + + // 检查面片索引有效性 + if (idxFace >= faces.size()) { + DEBUG_EXTRA("错误: 面片索引 %d 超出范围 (总数=%zu)", idxFace, faces.size()); + batchProcessed[i] = true; + continue; } - - { - const auto posToErase = remainingFaces.FindFirst(currentFaceId); - ASSERT(posToErase != Mesh::FaceIdxArr::NO_INDEX); - remainingFaces.RemoveAtMove(posToErase); - selectedFaces[currentFaceId] = true; - virtualFace.push_back(currentFaceId); + if (idxFace >= facesDatas.size()) { + DEBUG_EXTRA("错误: facesDatas 索引越界"); + batchProcessed[i] = true; + continue; } - const Mesh::FaceFaces& ffaces = faceFaces[currentFaceId]; - for (int i = 0; i < 3; ++i) { - const FIndex fIdx = ffaces[i]; - if (fIdx == NO_ID) - continue; - if (!selectedFaces[fIdx] && queuedFaces.find(fIdx) == queuedFaces.end()) { - currentVirtualFaceQueue.AddTail(fIdx); - queuedFaces.emplace(fIdx); + // 寻找质量最高的视图 + IIndex bestView = NO_ID; + float bestQuality = -1.0f; + + for (const FaceData& fd : facesDatas[idxFace]) { + if (!fd.bInvalidFacesRelative && fd.quality > bestQuality) { + bestQuality = fd.quality; + bestView = fd.idxView; } } - } while (!currentVirtualFaceQueue.IsEmpty()); + + if (bestView == NO_ID) { + DEBUG_EXTRA("面片 %d 没有有效的视图", idxFace); + batchProcessed[i] = true; + continue; + } + + DEBUG_EXTRA("处理面片 %d, 最佳视图: %d, 质量: %.3f", idxFace, bestView, bestQuality); + + // 使用区域增长算法收集具有相同最佳视图的相邻面片 + std::vector virtualFace; + std::queue faceQueue; + + faceQueue.push(idxFace); + virtualFace.push_back(idxFace); + batchProcessed[i] = true; + if (idxFace < processedFaces.size()) { + processedFaces[idxFace] = true; + } else { + DEBUG_EXTRA("警告: processedFaces 大小 %zu, 索引 %d", processedFaces.size(), idxFace); + } + + while (!faceQueue.empty()) { + FIndex currentFace = faceQueue.front(); + faceQueue.pop(); + + // 检查当前面片索引 + if (currentFace >= facesDatas.size()) { + DEBUG_EXTRA("错误: 当前面片索引越界"); + continue; + } + + // 检查当前面片的最佳视图 + IIndex currentBestView = NO_ID; + float currentBestQuality = -1.0f; + for (const FaceData& fd : facesDatas[currentFace]) { + if (!fd.bInvalidFacesRelative && fd.quality > currentBestQuality) { + currentBestQuality = fd.quality; + currentBestView = fd.idxView; + } + } + + // 只处理具有相同最佳视图的相邻面片 + if (currentBestView == bestView) { + // 检查相邻面片索引 + if (currentFace >= faceFaces.size()) { + DEBUG_EXTRA("错误: faceFaces 索引越界"); + continue; + } + + const Mesh::FaceFaces& neighbors = faceFaces[currentFace]; + for (int n = 0; n < 3; ++n) { + FIndex neighbor = neighbors[n]; + if (neighbor == NO_ID) { + continue; + } + + // 检查邻居面片索引 + if (neighbor >= faces.size()) { + DEBUG_EXTRA("警告: 邻居面片索引 %d 超出范围", neighbor); + continue; + } + + if (neighbor >= processedFaces.size()) { + DEBUG_EXTRA("警告: processedFaces 索引越界"); + continue; + } + + if (processedFaces[neighbor]) { + continue; + } + + // 检查邻居是否在当前批次中 + auto it = std::find(currentBatch.begin(), currentBatch.end(), neighbor); + if (it == currentBatch.end()) { + continue; + } + + size_t neighborIdx = std::distance(currentBatch.begin(), it); + if (neighborIdx >= batchProcessed.size()) { + DEBUG_EXTRA("警告: batchProcessed 索引越界"); + continue; + } + + if (batchProcessed[neighborIdx]) { + continue; + } + + // 检查邻居面片数据索引 + if (neighbor >= facesDatas.size()) { + DEBUG_EXTRA("错误: 邻居面片数据索引越界"); + continue; + } + + // 检查邻居面片的最佳视图 + IIndex neighborBestView = NO_ID; + float neighborBestQuality = -1.0f; + for (const FaceData& fd : facesDatas[neighbor]) { + if (!fd.bInvalidFacesRelative && fd.quality > neighborBestQuality) { + neighborBestQuality = fd.quality; + neighborBestView = fd.idxView; + } + } + + // 如果最佳视图相同,则加入虚拟面片 + if (neighborBestView == bestView) { + // 检查法线数据索引 + if (idxFace >= scene.mesh.faceNormals.size() || + neighbor >= scene.mesh.faceNormals.size()) { + DEBUG_EXTRA("警告: 法线数据索引越界"); + continue; + } + + // 检查法线夹角 + const Normal& centerNormal = scene.mesh.faceNormals[idxFace]; + const Normal& neighborNormal = scene.mesh.faceNormals[neighbor]; + const float cosAngle = centerNormal.dot(neighborNormal); + + // 使用固定阈值 + const float cosTh = COS(FD2R(15.0f)); // 15度阈值 + + if (cosAngle >= cosTh) { + faceQueue.push(neighbor); + virtualFace.push_back(neighbor); + batchProcessed[neighborIdx] = true; + if (neighbor < processedFaces.size()) { + processedFaces[neighbor] = true; + } + } + } + } + } + } + + // 如果收集到的面片数量合适,创建虚拟面片 + if (!virtualFace.empty()) { + DEBUG_EXTRA("创建虚拟面片,包含 %zu 个面片", virtualFace.size()); + + // 计算虚拟面片的平均质量 + float avgQuality = 0.0f; + int validFaceCount = 0; + for (FIndex fid : virtualFace) { + if (fid >= facesDatas.size()) { + DEBUG_EXTRA("警告: 虚拟面片中的面片索引越界"); + continue; + } + + float faceBestQuality = 0.0f; + for (const FaceData& fd : facesDatas[fid]) { + if (fd.idxView == bestView && fd.quality > faceBestQuality) { + faceBestQuality = fd.quality; + } + } + avgQuality += faceBestQuality; + validFaceCount++; + } + + if (validFaceCount > 0) { + avgQuality /= validFaceCount; + + // 创建虚拟面片 + Mesh::FaceIdxArr virtualFaceArr; + for (FIndex fid : virtualFace) { + virtualFaceArr.emplace_back(fid); + } + + FaceDataArr virtualFaceData; + FaceData& vfd = virtualFaceData.emplace_back(); + vfd.idxView = bestView; + vfd.quality = avgQuality; + + virtualFaces.push_back(virtualFaceArr); + virtualFacesDatas.push_back(virtualFaceData); + + // 标记为虚拟面片 + for (FIndex fid : virtualFace) { + if (fid < isVirtualFace.size()) { + isVirtualFace[fid] = true; + } + } + + DEBUG_EXTRA("成功创建虚拟面片,包含 %d 个面片,视图 %d,平均质量 %.3f", + validFaceCount, bestView, avgQuality); + } else { + DEBUG_EXTRA("警告: 虚拟面片没有有效的面片"); + } + } else { + DEBUG_EXTRA("为面片 %d 创建单个面片的虚拟面片", idxFace); + + // 如果没有收集到相邻面片,至少创建一个虚拟面片包含当前面片 + Mesh::FaceIdxArr singleFace(1, idxFace); + FaceDataArr virtualFaceData; + FaceData& vfd = virtualFaceData.emplace_back(); + vfd.idxView = bestView; + vfd.quality = bestQuality; + + virtualFaces.push_back(singleFace); + virtualFacesDatas.push_back(virtualFaceData); + processedFaces[idxFace] = true; + + if (idxFace < isVirtualFace.size()) { + isVirtualFace[idxFace] = true; + } + } + } + } + + // 统计处理结果 + int finalRemaining = 0; + for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { + if (!processedFaces[idxFace] && !facesDatas[idxFace].empty()) { + finalRemaining++; + } + } + + DEBUG_EXTRA("后备策略处理后,仍有 %d 个面片未处理", finalRemaining); + } + + DEBUG_EXTRA("虚拟面片创建完成: 创建了 %d 个虚拟面片,分配了 %d 个面片", + totalVirtualFaces, facesAssigned); + DEBUG_EXTRA("剩余未处理面片: %d", remainingFaces); + + return true; +} + + +bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras, float thMaxNormalDeviation) const +{ + if (meshCurvatures.empty()) { + ComputeFaceCurvatures(); + } + + float thMaxColorDeviation = 130.0f; + + const float ratioAngleToQuality(0.67f); + const float cosMaxNormalDeviation(COS(FD2R(thMaxNormalDeviation))); + Mesh::FaceIdxArr remainingFaces(faces.size()); + std::iota(remainingFaces.begin(), remainingFaces.end(), 0); + std::vector selectedFaces(faces.size(), false); + cQueue currentVirtualFaceQueue; + std::unordered_set queuedFaces; + + // std::vector> faceValidCameras(faces.size()); + // for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { + // const FaceDataArr& faceDatas = facesDatas[idxFace]; + // for (const FaceData& fd : faceDatas) { + // if (!fd.bInvalidFacesRelative) { + // faceValidCameras[idxFace].insert(fd.idxView); + // } + // } + // } + + // Precompute average color for each face + Colors faceColors; // 创建一个空列表 + faceColors.reserve(faces.size()); // 预分配空间(如果cList有reserve方法且您关心性能) + for (size_t i = 0; i < faces.size(); ++i) { + faceColors.push_back(Color::ZERO); // 逐个添加元素 + } + for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { + const FaceDataArr& faceDatas = facesDatas[idxFace]; + if (faceDatas.empty()) continue; + Color sumColor = Color::ZERO; + for (const FaceData& fd : faceDatas) { + sumColor += fd.color; + } + faceColors[idxFace] = sumColor / faceDatas.size(); + } + + do { + const FIndex startPos = RAND() % remainingFaces.size(); + const FIndex virtualFaceCenterFaceID = remainingFaces[startPos]; + + // 动态法线阈值 + const float centerCurvature = meshCurvatures[virtualFaceCenterFaceID]; + const float dynamicThreshold = (centerCurvature < 0.2f) ? 15.0f : 8.0f; // 曲率<0.2为平坦区域 + const float dynamicCosTh = COS(FD2R(dynamicThreshold)); + + ASSERT(currentVirtualFaceQueue.IsEmpty()); + const Normal& normalCenter = scene.mesh.faceNormals[virtualFaceCenterFaceID]; + const FaceDataArr& centerFaceDatas = facesDatas[virtualFaceCenterFaceID]; + + // 检查中心面片是否包含无效视图 + bool bHasInvalidView = false; + int nInvalidViewCount = 0; + int nTotalViewCount = 0; + for (const FaceData& faceData : centerFaceDatas) { + if (faceData.bInvalidFacesRelative) { + bHasInvalidView = true; + ++nInvalidViewCount; + // break; + } + ++nTotalViewCount; + } + + std::vector> sortedViews; + std::vector> sortedLuminViews; + std::vector> validViews; + sortedViews.reserve(centerFaceDatas.size()); + for (const FaceData& fd : centerFaceDatas) { + + if (fd.bInvalidFacesRelative) + { + // invalidView = fd.idxView; + // invalidQuality = fd.quality; + sortedViews.emplace_back(fd.quality, fd.color); + sortedLuminViews.emplace_back(MeshTexture::GetLuminance(fd.color), fd.color); + } + else + { + sortedViews.emplace_back(fd.quality, fd.color); + sortedLuminViews.emplace_back(MeshTexture::GetLuminance(fd.color), fd.color); + validViews.emplace_back(fd.quality, fd.color); + } + } + std::sort(sortedViews.begin(), sortedViews.end(), + [](const auto& a, const auto& b) { return a.first > b.first; }); + std::sort(validViews.begin(), validViews.end(), + [](const auto& a, const auto& b) { return a.first > b.first; }); + + int nSize = sortedViews.size(); + // int nSize = (sortedViews.size()>1) ? 1 : sortedViews.size(); + // 计算初始平均值 + float totalQuality = 0.0f; + Color totalColor(0,0,0); + for (int n = 0; n < nSize; ++n) { + totalQuality += sortedViews[n].first; + totalColor += sortedViews[n].second; + } + const float avgQuality = totalQuality / nSize; + const Color avgColor = totalColor / nSize; + + float totalLuminance = MeshTexture::GetLuminance(totalColor); + float avgLuminance = totalLuminance / nSize; + std::sort(sortedLuminViews.begin(), sortedLuminViews.end(), + [avgLuminance](const auto& a, const auto& b) { + float luminDistA = cv::norm(avgLuminance - a.first); + float luminDistB = cv::norm(avgLuminance - b.first); + return luminDistA < luminDistB; }); + + // select the common cameras + Mesh::FaceIdxArr virtualFace; + FaceDataArr virtualFaceDatas; + if (centerFaceDatas.empty()) { + virtualFace.emplace_back(virtualFaceCenterFaceID); + selectedFaces[virtualFaceCenterFaceID] = true; + const auto posToErase = remainingFaces.FindFirst(virtualFaceCenterFaceID); + ASSERT(posToErase != Mesh::FaceIdxArr::NO_INDEX); + remainingFaces.RemoveAtMove(posToErase); + } else { + IIndexArr selectedCams = SelectBestViews(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality); + // IIndexArr selectedCams = SelectBestViews2(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality, facesDatas); + //* + // 获取中心面片的法线 (注意变量名是 normalCenter, 不是 centerNormal) + const Normal& normalCenter = scene.mesh.faceNormals[virtualFaceCenterFaceID]; + + std::map mapSortedcams; + for (IIndex idxView : selectedCams) + { + const Image& imageData = images[idxView]; + // 计算相机在世界坐标系中的朝向向量(相机镜面法线) + const RMatrix& R = imageData.camera.R; + // 相机局部坐标系中的向前向量 (0,0,-1) + Point3f localForward(0.0f, 0.0f, -1.0f); + // 手动计算矩阵乘法:cameraForward = R * localForward + Point3f cameraForward; + cameraForward.x = R(0,0) * localForward.x + R(0,1) * localForward.y + R(0,2) * localForward.z; + cameraForward.y = R(1,0) * localForward.x + R(1,1) * localForward.y + R(1,2) * localForward.z; + cameraForward.z = R(2,0) * localForward.x + R(2,1) * localForward.y + R(2,2) * localForward.z; + + // 手动归一化 cameraForward + float norm = std::sqrt(cameraForward.x * cameraForward.x + + cameraForward.y * cameraForward.y + + cameraForward.z * cameraForward.z); + if (norm > 0.0f) { + cameraForward.x /= norm; + cameraForward.y /= norm; + cameraForward.z /= norm; + } else { + cameraForward = Point3f(0, 0, -1); + } + + Point3f normalPoint(normalCenter.x, normalCenter.y, normalCenter.z); + float cosAngle = cameraForward.dot(normalPoint); + float angleDeg = std::acos(cosAngle) * 180.0f / M_PI; + + std::string strPath = imageData.name; + std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); + + if (!scene.is_face_delete_edge(strName, virtualFaceCenterFaceID)) { + + if (scene.is_face_edge(strName, virtualFaceCenterFaceID)) + { + if (angleDeg <= 40.0f) + { + mapSortedcams[idxView] = angleDeg; + } + } + else + { + mapSortedcams[idxView] = angleDeg; + } + } + } + + // 将map中的元素放入vector以便排序 + std::vector> sortedCams; + sortedCams.reserve(mapSortedcams.size()); + for (const auto& pair : mapSortedcams) { + sortedCams.emplace_back(pair.first, pair.second); + } + + // 按angleDeg从小到大排序 + std::sort(sortedCams.begin(), sortedCams.end(), + [](const std::pair& a, const std::pair& b) { + return a.second < b.second; // 按angleDeg排序 + }); + + IIndexArr filteredCams; + size_t count = std::min(sortedCams.size(), static_cast(3)); + for (size_t i = 0; i < count; ++i) { + filteredCams.push_back(sortedCams[i].first); + } + + /* + IIndexArr filteredCams; // 用于存储过滤后的视图索引 + for (IIndex idxView : selectedCams) { + const Image& imageData = images[idxView]; + // 计算相机在世界坐标系中的朝向向量(相机镜面法线) + const RMatrix& R = imageData.camera.R; // 请根据 R 的实际类型调整,可能是 Matrix3x3f 或其他 + // 相机局部坐标系中的向前向量 (0,0,-1) + Point3f localForward(0.0f, 0.0f, -1.0f); + // 手动计算矩阵乘法:cameraForward = R * localForward + Point3f cameraForward; + cameraForward.x = R(0,0) * localForward.x + R(0,1) * localForward.y + R(0,2) * localForward.z; + cameraForward.y = R(1,0) * localForward.x + R(1,1) * localForward.y + R(1,2) * localForward.z; + cameraForward.z = R(2,0) * localForward.x + R(2,1) * localForward.y + R(2,2) * localForward.z; + + // 手动归一化 cameraForward(因为 Point3f 可能没有 normalize() 成员函数) + float norm = std::sqrt(cameraForward.x * cameraForward.x + + cameraForward.y * cameraForward.y + + cameraForward.z * cameraForward.z); + if (norm > 0.0f) { + cameraForward.x /= norm; + cameraForward.y /= norm; + cameraForward.z /= norm; + } else { + // 处理零向量的情况,赋予默认值 + cameraForward = Point3f(0, 0, -1); + } + + // 计算夹角余弦值 - 使用已声明的 normalCenter + // 假设 Normal 类型可以隐式转换为 Point3f,或进行显式转换 + Point3f normalPoint(normalCenter.x, normalCenter.y, normalCenter.z); // 显式转换示例 + float cosAngle = cameraForward.dot(normalPoint); // 使用正确的变量名 normalPoint(由 normalCenter 转换而来) + float angleDeg = std::acos(cosAngle) * 180.0f / M_PI; // 将弧度转换为角度 + + std::string strPath = imageData.name; + std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); + // size_t lastSlash = strPath.find_last_of("/\\"); + // if (lastSlash == std::string::npos) lastSlash = 0; // 若无分隔符,从头开始 + // else lastSlash++; // 跳过分隔符 + + // // 查找扩展名分隔符 '.' 的位置 + // size_t lastDot = strPath.find_last_of('.'); + // if (lastDot == std::string::npos) lastDot = strPath.size(); // 若无扩展名,截到末尾 + + // // 截取文件名(不含路径和扩展名) + // std::string strName = strPath.substr(lastSlash, lastDot - lastSlash); + + // printf("CreateVirtualFace %s, %d\n", strName.c_str(), virtualFaceCenterFaceID); + + if (!scene.is_face_delete_edge(strName, virtualFaceCenterFaceID)) + { + if (scene.is_face_edge(strName, virtualFaceCenterFaceID)) + { + // printf("CreateVirtualFace %s, %d, %f\n", strName.c_str(), virtualFaceCenterFaceID, angleLimit); + + if (angleDeg <= 40.0f) + { + filteredCams.push_back(idxView); + + // float brightnessScore = CalculateBrightnessScore(imageData); // 亮度评分函数 + // float angleScore = 1.0f - (angleDeg / 45.0f); + // float qualityScore = 0.0f; + // const FaceDataArr& centerFaceDatas = facesDatas[virtualFaceCenterFaceID]; + // for (const FaceData& fd : centerFaceDatas) { + // if (fd.idxView == idxView) { + // qualityScore = fd.quality; + // break; + // } + // } + // qualityScore = std::max(0.0f, std::min(1.0f, qualityScore)); + // float overallScore = 0.5f * angleScore + 0.3f * brightnessScore + 0.2f * qualityScore; + // if (overallScore > 0.04f) { + // filteredCams.push_back(idxView); + // } + } + + } + else + { + // if (angleDeg <= 30.0f) + { + filteredCams.push_back(idxView); + } + + // float brightnessScore = CalculateBrightnessScore(imageData); // 亮度评分函数 + // float angleScore = 1.0f - (angleDeg / 45.0f); + // float qualityScore = 0.0f; + // const FaceDataArr& centerFaceDatas = facesDatas[virtualFaceCenterFaceID]; + // for (const FaceData& fd : centerFaceDatas) { + // if (fd.idxView == idxView) { + // qualityScore = fd.quality; + // break; + // } + // } + // qualityScore = std::max(0.0f, std::min(1.0f, qualityScore)); + // float overallScore = 0.5f * angleScore + 0.3f * brightnessScore + 0.2f * qualityScore; + // if (overallScore > 0.02f) { + // filteredCams.push_back(idxView); + // } + } + } + } + */ + + // 确保 selectedCams 是非 const 的,才能对其进行赋值 + // 例如,其声明应为:IIndexArr selectedCams = ...; (不能是 const IIndexArr) + if (filteredCams.empty()) { + // 处理所有视图都被过滤的情况... + // DEBUG_EXTRA("Warning: All views filtered for virtual face due to angle condition."); + + // selectedCams = SelectBestView(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality); + selectedCams = filteredCams; + isVirtualFace[virtualFaceCenterFaceID] = false; + + } else { + selectedCams = filteredCams; + isVirtualFace[virtualFaceCenterFaceID] = true; + } + //*/ + + currentVirtualFaceQueue.AddTail(virtualFaceCenterFaceID); + queuedFaces.clear(); + do { + const FIndex currentFaceId = currentVirtualFaceQueue.GetHead(); + currentVirtualFaceQueue.PopHead(); + + // check for condition to add in current virtual face + // normal angle smaller than thMaxNormalDeviation degrees + const Normal& faceNormal = scene.mesh.faceNormals[currentFaceId]; + const float cosFaceToCenter(ComputeAngleN(normalCenter.ptr(), faceNormal.ptr())); + if (cosFaceToCenter < dynamicCosTh) + continue; + // if (cosFaceToCenter < dynamicCosTh) // 使用动态阈值 + // continue; + // printf("dynamicCosTh=%f\n", dynamicCosTh); + // if (cosFaceToCenter < 0.99) // 对应60度,比原来的更宽松 + // continue; + + // check if current face is seen by all cameras in selectedCams + ASSERT(!selectedCams.empty()); + if (!IsFaceVisible(facesDatas[currentFaceId], selectedCams)) + continue; + + // 3. 放宽颜色差异条件 + const Color& centerColor = faceColors[virtualFaceCenterFaceID]; + const Color& currentColor = faceColors[currentFaceId]; + float colorDistance = cv::norm(centerColor - currentColor); + if (colorDistance > 200.0f) { // 从200.0f放宽到250.0f + // continue; // 如果颜色差异太大,跳过 + } + + // check if current face is seen by all cameras in selectedCams + // ASSERT(!selectedCams.empty()); + // if (!IsFaceVisible(facesDatas[currentFaceId], selectedCams)) + // continue; + + // // Check color similarity + // const Color& centerColor = faceColors[virtualFaceCenterFaceID]; + // const Color& currentColor = faceColors[currentFaceId]; + // if (cv::norm(centerColor) > 1e-5 && cv::norm(currentColor) > 1e-5) + { + float colorDistance = cv::norm(centerColor - currentColor); + // printf("1colorDistance=%f\n", colorDistance); + if (colorDistance > thMaxColorDeviation) { + // printf("2colorDistance=%f\n", colorDistance); + // continue; // Skip if color difference is too large + } + } + + // remove it from remaining faces and add it to the virtual face + { + const auto posToErase = remainingFaces.FindFirst(currentFaceId); + ASSERT(posToErase != Mesh::FaceIdxArr::NO_INDEX); + remainingFaces.RemoveAtMove(posToErase); + selectedFaces[currentFaceId] = true; + virtualFace.push_back(currentFaceId); + } + // add all new neighbors to the queue + const Mesh::FaceFaces& ffaces = faceFaces[currentFaceId]; + for (int i = 0; i < 3; ++i) { + const FIndex fIdx = ffaces[i]; + if (fIdx == NO_ID) + continue; + if (!selectedFaces[fIdx] && queuedFaces.find(fIdx) == queuedFaces.end()) { + currentVirtualFaceQueue.AddTail(fIdx); + queuedFaces.emplace(fIdx); + } + } + } while (!currentVirtualFaceQueue.IsEmpty()); + + // compute virtual face quality and create virtual face + for (IIndex idxView: selectedCams) { + FaceData& virtualFaceData = virtualFaceDatas.emplace_back(); + virtualFaceData.quality = 0; + virtualFaceData.idxView = idxView; + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + virtualFaceData.color = Point3f::ZERO; + #endif + + const Image& imageData = images[idxView]; + std::string strPath = imageData.name; + std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); + int invalidQuality = 0; + Color invalidColor = Point3f::ZERO; + unsigned processedFaces(0); + bool bInvalidFacesRelative = false; + int invalidCount = 0; + for (FIndex fid : virtualFace) { + const FaceDataArr& faceDatas = facesDatas[fid]; + for (FaceData& faceData: faceDatas) { + + int nViewCount = 0; + if (faceData.idxView == idxView) + { + for (const FaceData& fd : faceDatas) + { + if ( faceData.bInvalidFacesRelative) + { + ++nViewCount; + } + } + // if (faceData.bInvalidFacesRelative) + if (bHasInvalidView) + { + // invalidQuality += faceData.quality; + // #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + // invalidColor += faceData.color; + // #endif + + ++processedFaces; + } + else + { + // virtualFaceData.quality += faceData.quality; + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + // virtualFaceData.color += faceData.color; + #endif + ++processedFaces; + // break; + } + } + } + } + + float maxLuminance = 120.0f; + float minLuminance = 90.0f; + int validViewsSize = validViews.size(); + // bHasInvalidView = true; + if (bHasInvalidView) + { + // 使用鲁棒的统计方法计算颜色和亮度的中心值 + const Color medianColor = ComputeMedianColorAndQuality(sortedViews).color; + const float medianQuality = ComputeMedianColorAndQuality(sortedViews).quality; + const float medianLuminance = ComputeMedianLuminance(sortedViews); + + // 计算颜色和亮度的绝对中位差(MAD)作为偏差阈值 + const float colorMAD = ComputeColorMAD(sortedViews, medianColor); + const float luminanceMAD = ComputeLuminanceMAD(sortedViews, medianLuminance); + + // 基于MAD设置动态阈值(3倍MAD是统计学上常用的异常值阈值) + const float maxColorDeviation = 0.01f * colorMAD; + const float maxLuminanceDeviation = 0.01f * luminanceMAD; + + std::vector validIndices; + for (int n = 0; n < sortedViews.size(); ++n) { + const Color& viewColor = sortedViews[n].second; + const float viewLuminance = MeshTexture::GetLuminance(viewColor); + + const float colorDistance = cv::norm(viewColor - medianColor); + const float luminanceDistance = std::abs(viewLuminance - medianLuminance); + + if (colorDistance <= maxColorDeviation && + luminanceDistance <= maxLuminanceDeviation) + { + + if (scene.is_face_normal_visible_map(strName, virtualFaceCenterFaceID)) + validIndices.push_back(n); + } + else + { + const FIndex currentFaceId = currentVirtualFaceQueue.GetHead(); + const Normal& faceNormal = scene.mesh.faceNormals[currentFaceId]; + const float cosFaceToCenter(ComputeAngleN(normalCenter.ptr(), faceNormal.ptr())); + + bool bColorSimilarity = true; + // Check color similarity + const Color& centerColor = faceColors[virtualFaceCenterFaceID]; + const Color& currentColor = faceColors[currentFaceId]; + + float colorDistance = cv::norm(centerColor - currentColor); + // printf("1colorDistance=%f\n", colorDistance); + if (colorDistance > thMaxColorDeviation) { + // printf("2colorDistance=%f\n", colorDistance); + bColorSimilarity = false; + } + + // if ((cosFaceToCenter 0); + // virtualFaceData.quality /= processedFaces; + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + // virtualFaceData.color /= processedFaces; + #endif + + virtualFaceData.quality = 0; + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + virtualFaceData.color = Point3f::ZERO; + #endif + } + } + else + { + // 使用鲁棒的统计方法计算颜色和亮度的中心值 + const Color medianColor = ComputeMedianColorAndQuality(sortedViews).color; + const float medianQuality = ComputeMedianColorAndQuality(sortedViews).quality; + const float medianLuminance = ComputeMedianLuminance(sortedViews); + + // 计算颜色和亮度的绝对中位差(MAD)作为偏差阈值 + const float colorMAD = ComputeColorMAD(sortedViews, medianColor); + const float luminanceMAD = ComputeLuminanceMAD(sortedViews, medianLuminance); + + // 基于MAD设置动态阈值(3倍MAD是统计学上常用的异常值阈值) + const float maxColorDeviation = 0.01f * colorMAD; + // const float maxLuminanceDeviation = 0.01f * luminanceMAD; + const float maxLuminanceDeviation = 0.05f * luminanceMAD; + + std::vector validIndices; + for (int n = 0; n < sortedViews.size(); ++n) { + const Color& viewColor = sortedViews[n].second; + const float viewLuminance = MeshTexture::GetLuminance(viewColor); + + const float colorDistance = cv::norm(viewColor - medianColor); + const float luminanceDistance = std::abs(viewLuminance - medianLuminance); + + // if (colorDistance <= maxColorDeviation && + // luminanceDistance <= maxLuminanceDeviation) + // if (luminanceDistance <= maxLuminanceDeviation) + { + validIndices.push_back(n); + } + } + + if (validIndices.empty()) { + + virtualFaceData.quality = medianQuality; + virtualFaceData.color = medianColor; + + // virtualFaceData.quality = 0; + // #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + // virtualFaceData.color = Point3f::ZERO; + // #endif + } + else { + // 使用过滤后的视图重新计算平均值 + float totalQuality2 = 0.0f; + Color totalColor2 = Color(0,0,0); + for (int idx : validIndices) { + totalQuality2 += validViews[idx].first; + totalColor2 += validViews[idx].second; + } + virtualFaceData.quality = totalQuality2 / validIndices.size(); + virtualFaceData.color = totalColor2 / validIndices.size(); + + // virtualFaceData.quality = 0; + // #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + // virtualFaceData.color = Point3f::ZERO; + // #endif + } + } + + // virtualFaceData.bInvalidFacesRelative = (invalidCount > 1); + // virtualFaceData.bInvalidFacesRelative = (invalidCount > processedFaces * 2 / 3); + } + ASSERT(!virtualFaceDatas.empty()); + } + virtualFacesDatas.emplace_back(std::move(virtualFaceDatas)); + virtualFaces.emplace_back(std::move(virtualFace)); + } while (!remainingFaces.empty()); + + return true; +} + +bool MeshTexture::CreateVirtualFaces64(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras, float thMaxNormalDeviation) const +{ + if (meshCurvatures.empty()) { + ComputeFaceCurvatures(); + } + + // 如果夹角小于45度(cos(45°) ≈ 0.7071),则计入覆盖 + float fAngleThreshold = 0.8571; // 0.7071f + + // 初始化数据结构 + std::vector processedFaces(faces.size(), false); + std::vector> viewCoverage; // 视图索引和覆盖的面片数量 + + DEBUG_EXTRA("开始新的虚拟面片创建逻辑: 基于视图排序"); + + // 1. 计算每个视图的覆盖情况 + Util::Progress progress1(_T("计算视图覆盖"), images.size()); + for (IIndex idxView = 0; idxView < images.size(); ++idxView) { - // 计算虚拟面质量并创建虚拟面 - for (IIndex idxView: selectedCams) { - FaceData& virtualFaceData = virtualFaceDatas.emplace_back(); + if (mapViewCoverageData.find(idxView) == mapViewCoverageData.end()) { + // 插入新对象 + mapViewCoverageData.emplace(idxView, ViewCoverageData(idxView)); + } + + ViewCoverageData& viewData = mapViewCoverageData[idxView]; - virtualFaceData.quality = 0; - virtualFaceData.idxView = idxView; - #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA - virtualFaceData.color = Point3f::ZERO; - #endif + if (!images[idxView].IsValid()) { + ++progress1; + continue; + } + + int coverageCount = 0; + const Image& imageData = images[idxView]; + + // 计算相机方向 + const RMatrix& R = imageData.camera.R; + Point3f cameraForward( + -R(0,2), // 相机坐标系中-Z轴是向前方向(从相机指向场景) + -R(1,2), + -R(2,2) + ); + + // 归一化相机方向 + const float normCameraForward = std::sqrt( + cameraForward.x * cameraForward.x + + cameraForward.y * cameraForward.y + + cameraForward.z * cameraForward.z + ); + if (normCameraForward > 0) { + cameraForward /= normCameraForward; + } + + FaceDataViewArr facesDatasPreprocess; + facesDatasPreprocess.resize(faces.size()); - const Image& imageData = images[idxView]; - std::string strPath = imageData.name; - std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); - int invalidQuality = 0; - Color invalidColor = Point3f::ZERO; - unsigned processedFaces(0); - int invalidCount = 0; - - for (FIndex fid : virtualFace) { - const FaceDataArr& faceDatas = facesDatas[fid]; - for (FaceData& faceData: faceDatas) { - int nViewCount = 0; - if (faceData.idxView == idxView) { - for (const FaceData& fd : faceDatas) { - if (faceData.bInvalidFacesRelative) { - ++nViewCount; - } - } - if (bHasInvalidView) { - ++processedFaces; - } else { - #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA - #endif - ++processedFaces; - } - } + // 遍历所有面片,统计满足条件的面片 + for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { + // 跳过已处理的面片 + if (processedFaces[idxFace]) { + continue; + } + + // 检查面片是否有视图数据 + if (facesDatas[idxFace].empty()) { + continue; + } + + // 检查视图是否能看到这个面片 + bool viewSeesFace = false; + float bestQuality = 0.0f; + + for (const FaceData& fd : facesDatas[idxFace]) { + if (fd.idxView == idxView && !fd.bInvalidFacesRelative) { + viewSeesFace = true; + if (fd.quality > bestQuality) { + bestQuality = fd.quality; } } + } + + if (!viewSeesFace) { + continue; + } + + // 检查面片法线与相机方向的夹角 + const Normal& faceNormal = scene.mesh.faceNormals[idxFace]; + const float cosAngle = cameraForward.dot(Point3f(faceNormal.x, faceNormal.y, faceNormal.z)); + + if (cosAngle > fAngleThreshold) + { // 45度阈值 + coverageCount++; - int validViewsSize = validViews.size(); - if (bHasInvalidView) { - // 使用简化逻辑 - const Color medianColor = ComputeMedianColorAndQuality(sortedViews).color; - const float medianQuality = ComputeMedianColorAndQuality(sortedViews).quality; - - // 直接使用中位数计算 - virtualFaceData.quality = medianQuality; - virtualFaceData.color = medianColor; - } else { - // 使用有效视图计算 - if (!validViews.empty()) { - float totalQuality2 = 0.0f; - Color totalColor2 = Color(0,0,0); - for (const auto& v : validViews) { - totalQuality2 += v.first; - totalColor2 += v.second; - } - virtualFaceData.quality = totalQuality2 / validViews.size(); - virtualFaceData.color = totalColor2 / validViews.size(); - } else { - // 回退到平均值 - virtualFaceData.quality = avgQuality; - virtualFaceData.color = avgColor; - } - } + viewData.faceToIndexMap[idxFace] = idxFace; } - ASSERT(!virtualFaceDatas.empty()); } - virtualFacesDatas.emplace_back(std::move(virtualFaceDatas)); - virtualFaces.emplace_back(std::move(virtualFace)); - } while (!remainingFaces.empty()); - - return true; -} - -bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras, float thMaxNormalDeviation) const -{ - if (meshCurvatures.empty()) { - ComputeFaceCurvatures(); + + if (coverageCount > 0) { + viewCoverage.emplace_back(idxView, coverageCount); + } + + ++progress1; + } + progress1.close(); + + // 2. 按覆盖数量对视图排序(从高到低) + std::sort(viewCoverage.begin(), viewCoverage.end(), + [](const auto& a, const auto& b) { return a.second > b.second; }); + + // 打印排序结果 + DEBUG_EXTRA("视图覆盖统计(按覆盖数量从高到低排序):"); + int totalCoverage = 0; + for (const auto& [idxView, coverage] : viewCoverage) { + const Image& imageData = images[idxView]; + DEBUG_EXTRA("视图 %s (索引 %d): 覆盖 %d 个面片", + imageData.name.c_str(), idxView, coverage); + totalCoverage += coverage; } + + DEBUG_EXTRA("排序后视图数量: %zu,最大覆盖: %d, 共%d", viewCoverage.size(), + viewCoverage.empty() ? 0 : viewCoverage[0].second, totalCoverage); float thMaxColorDeviation = 130.0f; @@ -4629,16 +5838,6 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView cQueue currentVirtualFaceQueue; std::unordered_set queuedFaces; - // std::vector> faceValidCameras(faces.size()); - // for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { - // const FaceDataArr& faceDatas = facesDatas[idxFace]; - // for (const FaceData& fd : faceDatas) { - // if (!fd.bInvalidFacesRelative) { - // faceValidCameras[idxFace].insert(fd.idxView); - // } - // } - // } - // Precompute average color for each face Colors faceColors; // 创建一个空列表 faceColors.reserve(faces.size()); // 预分配空间(如果cList有reserve方法且您关心性能) @@ -4803,115 +6002,60 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView [](const std::pair& a, const std::pair& b) { return a.second < b.second; // 按angleDeg排序 }); - + IIndexArr filteredCams; - size_t count = std::min(sortedCams.size(), static_cast(3)); - for (size_t i = 0; i < count; ++i) { - filteredCams.push_back(sortedCams[i].first); - } - /* - IIndexArr filteredCams; // 用于存储过滤后的视图索引 - for (IIndex idxView : selectedCams) { - const Image& imageData = images[idxView]; - // 计算相机在世界坐标系中的朝向向量(相机镜面法线) - const RMatrix& R = imageData.camera.R; // 请根据 R 的实际类型调整,可能是 Matrix3x3f 或其他 - // 相机局部坐标系中的向前向量 (0,0,-1) - Point3f localForward(0.0f, 0.0f, -1.0f); - // 手动计算矩阵乘法:cameraForward = R * localForward - Point3f cameraForward; - cameraForward.x = R(0,0) * localForward.x + R(0,1) * localForward.y + R(0,2) * localForward.z; - cameraForward.y = R(1,0) * localForward.x + R(1,1) * localForward.y + R(1,2) * localForward.z; - cameraForward.z = R(2,0) * localForward.x + R(2,1) * localForward.y + R(2,2) * localForward.z; - - // 手动归一化 cameraForward(因为 Point3f 可能没有 normalize() 成员函数) - float norm = std::sqrt(cameraForward.x * cameraForward.x + - cameraForward.y * cameraForward.y + - cameraForward.z * cameraForward.z); - if (norm > 0.0f) { - cameraForward.x /= norm; - cameraForward.y /= norm; - cameraForward.z /= norm; - } else { - // 处理零向量的情况,赋予默认值 - cameraForward = Point3f(0, 0, -1); + int nMaxViewCoverage = 0; + for (const auto& [viewIdx, coverageCount] : viewCoverage) { + if (nMaxViewCoverage>6) + break; + auto it_view = mapViewCoverageData.find(viewIdx); + if (it_view == mapViewCoverageData.end()) { + continue; } + + const ViewCoverageData& viewData = it_view->second; - // 计算夹角余弦值 - 使用已声明的 normalCenter - // 假设 Normal 类型可以隐式转换为 Point3f,或进行显式转换 - Point3f normalPoint(normalCenter.x, normalCenter.y, normalCenter.z); // 显式转换示例 - float cosAngle = cameraForward.dot(normalPoint); // 使用正确的变量名 normalPoint(由 normalCenter 转换而来) - float angleDeg = std::acos(cosAngle) * 180.0f / M_PI; // 将弧度转换为角度 - + const Image& imageData = images[viewIdx]; std::string strPath = imageData.name; - std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); - // size_t lastSlash = strPath.find_last_of("/\\"); - // if (lastSlash == std::string::npos) lastSlash = 0; // 若无分隔符,从头开始 - // else lastSlash++; // 跳过分隔符 - - // // 查找扩展名分隔符 '.' 的位置 - // size_t lastDot = strPath.find_last_of('.'); - // if (lastDot == std::string::npos) lastDot = strPath.size(); // 若无扩展名,截到末尾 - - // // 截取文件名(不含路径和扩展名) - // std::string strName = strPath.substr(lastSlash, lastDot - lastSlash); + std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); - // printf("CreateVirtualFace %s, %d\n", strName.c_str(), virtualFaceCenterFaceID); - - if (!scene.is_face_delete_edge(strName, virtualFaceCenterFaceID)) + if (viewData.faceToIndexMap.find(virtualFaceCenterFaceID) != viewData.faceToIndexMap.end()) { - if (scene.is_face_edge(strName, virtualFaceCenterFaceID)) - { - // printf("CreateVirtualFace %s, %d, %f\n", strName.c_str(), virtualFaceCenterFaceID, angleLimit); - - if (angleDeg <= 40.0f) + if (!scene.is_face_delete_edge(strName, virtualFaceCenterFaceID)) { + if (scene.is_face_edge(strName, virtualFaceCenterFaceID)) { - filteredCams.push_back(idxView); - - // float brightnessScore = CalculateBrightnessScore(imageData); // 亮度评分函数 - // float angleScore = 1.0f - (angleDeg / 45.0f); - // float qualityScore = 0.0f; - // const FaceDataArr& centerFaceDatas = facesDatas[virtualFaceCenterFaceID]; - // for (const FaceData& fd : centerFaceDatas) { - // if (fd.idxView == idxView) { - // qualityScore = fd.quality; - // break; - // } - // } - // qualityScore = std::max(0.0f, std::min(1.0f, qualityScore)); - // float overallScore = 0.5f * angleScore + 0.3f * brightnessScore + 0.2f * qualityScore; - // if (overallScore > 0.04f) { - // filteredCams.push_back(idxView); - // } + // if (angleDeg <= 40.0f) + { + // filteredCams.push_back(viewIdx); + } } - - } - else - { - // if (angleDeg <= 30.0f) + else { - filteredCams.push_back(idxView); + // if (filteredCams.empty()) + { + // filteredCams.push_back(viewIdx); + } } + } - // float brightnessScore = CalculateBrightnessScore(imageData); // 亮度评分函数 - // float angleScore = 1.0f - (angleDeg / 45.0f); - // float qualityScore = 0.0f; - // const FaceDataArr& centerFaceDatas = facesDatas[virtualFaceCenterFaceID]; - // for (const FaceData& fd : centerFaceDatas) { - // if (fd.idxView == idxView) { - // qualityScore = fd.quality; - // break; - // } - // } - // qualityScore = std::max(0.0f, std::min(1.0f, qualityScore)); - // float overallScore = 0.5f * angleScore + 0.3f * brightnessScore + 0.2f * qualityScore; - // if (overallScore > 0.02f) { - // filteredCams.push_back(idxView); - // } + if (!scene.is_face_delete_edge2(strName, virtualFaceCenterFaceID)) + { + filteredCams.push_back(viewIdx); } + + break; + } + + ++nMaxViewCoverage; + } + + if (filteredCams.empty()) { + size_t count = std::min(sortedCams.size(), static_cast(3)); + for (size_t i = 0; i < count; ++i) { + filteredCams.push_back(sortedCams[i].first); } } - */ // 确保 selectedCams 是非 const 的,才能对其进行赋值 // 例如,其声明应为:IIndexArr selectedCams = ...; (不能是 const IIndexArr) @@ -4941,11 +6085,6 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView const float cosFaceToCenter(ComputeAngleN(normalCenter.ptr(), faceNormal.ptr())); if (cosFaceToCenter < dynamicCosTh) continue; - // if (cosFaceToCenter < dynamicCosTh) // 使用动态阈值 - // continue; - // printf("dynamicCosTh=%f\n", dynamicCosTh); - // if (cosFaceToCenter < 0.99) // 对应60度,比原来的更宽松 - // continue; // check if current face is seen by all cameras in selectedCams ASSERT(!selectedCams.empty()); @@ -4960,15 +6099,6 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView // continue; // 如果颜色差异太大,跳过 } - // check if current face is seen by all cameras in selectedCams - // ASSERT(!selectedCams.empty()); - // if (!IsFaceVisible(facesDatas[currentFaceId], selectedCams)) - // continue; - - // // Check color similarity - // const Color& centerColor = faceColors[virtualFaceCenterFaceID]; - // const Color& currentColor = faceColors[currentFaceId]; - // if (cv::norm(centerColor) > 1e-5 && cv::norm(currentColor) > 1e-5) { float colorDistance = cv::norm(centerColor - currentColor); // printf("1colorDistance=%f\n", colorDistance); @@ -5030,13 +6160,8 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView ++nViewCount; } } - // if (faceData.bInvalidFacesRelative) if (bHasInvalidView) { - // invalidQuality += faceData.quality; - // #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA - // invalidColor += faceData.color; - // #endif ++processedFaces; } @@ -7553,7 +8678,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT // CreateVirtualFaces6(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); // CreateVirtualFaces61(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); CreateVirtualFaces62(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); - // CreateVirtualFaces63(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); + // CreateVirtualFaces64(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); TD_TIMER_STARTD(); // CreateVirtualFaces7(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); DEBUG_EXTRA("CreateVirtualFaces completed: %s", TD_TIMER_GET_FMT().c_str()); @@ -10881,6 +12006,18 @@ void Scene::SaveVisibleFacesData(std::map>& } mapFile3.close(); } + + std::ofstream mapFile4(basePath + "_delete_edge_faces_map2.txt"); + if (mapFile4.is_open()) { + for (const auto& entry : delete_edge_faces_map2) { + mapFile4 << entry.first; + for (int face : entry.second) { + mapFile4 << " " << face; + } + mapFile4 << "\n"; + } + mapFile4.close(); + } } // 从文件加载遮挡数据 @@ -10888,14 +12025,15 @@ bool Scene::LoadVisibleFacesData(std::map>& std::unordered_set& face_visible_relative, std::map>& edge_faces_map, std::map>& delete_edge_faces_map, + std::map>& delete_edge_faces_map2, std::map>& face_normal_visible_map, std::string& basePath) { printf("LoadVisibleFacesData %s\n", basePath.c_str()); + std::ifstream mapFile(basePath + "_visible_faces_map.txt"); if (!mapFile.is_open()) { return false; } - std::string line; while (std::getline(mapFile, line)) { std::istringstream iss(line); @@ -10914,7 +12052,6 @@ bool Scene::LoadVisibleFacesData(std::map>& if (!relativeFile.is_open()) { return false; } - while (std::getline(relativeFile, line)) { int face_index = std::stoi(line); face_visible_relative.insert(face_index); @@ -10925,7 +12062,6 @@ bool Scene::LoadVisibleFacesData(std::map>& if (!mapFile2.is_open()) { return false; } - while (std::getline(mapFile2, line)) { std::istringstream iss(line); std::string image_name; @@ -10943,7 +12079,6 @@ bool Scene::LoadVisibleFacesData(std::map>& if (!mapFile3.is_open()) { return false; } - while (std::getline(mapFile3, line)) { std::istringstream iss(line); std::string image_name; @@ -10957,11 +12092,10 @@ bool Scene::LoadVisibleFacesData(std::map>& } mapFile3.close(); - std::ifstream mapFile4(basePath + "_face_normal_visible_map.txt"); + std::ifstream mapFile4(basePath + "_delete_edge_faces_map2.txt"); if (!mapFile4.is_open()) { return false; } - while (std::getline(mapFile4, line)) { std::istringstream iss(line); std::string image_name; @@ -10971,12 +12105,29 @@ bool Scene::LoadVisibleFacesData(std::map>& while (iss >> face_index) { faces.insert(face_index); } - face_normal_visible_map[image_name] = faces; + delete_edge_faces_map2[image_name] = faces; } mapFile4.close(); + std::ifstream mapFile5(basePath + "_face_normal_visible_map.txt"); + if (!mapFile5.is_open()) { + return false; + } + while (std::getline(mapFile5, line)) { + std::istringstream iss(line); + std::string image_name; + iss >> image_name; + std::unordered_set faces; + int face_index; + while (iss >> face_index) { + faces.insert(face_index); + } + face_normal_visible_map[image_name] = faces; + } + mapFile5.close(); + return true; -} +} // texture mesh // - minCommonCameras: generate texture patches using virtual faces composed of coplanar triangles sharing at least this number of views (0 - disabled, 3 - good value) @@ -11073,7 +12224,7 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi // printf("basePath=%s\n", basePath.c_str()); - if (!LoadVisibleFacesData(visible_faces_map, face_visible_relative, edge_faces_map, delete_edge_faces_map, face_normal_visible_map, basePath)) + if (!LoadVisibleFacesData(visible_faces_map, face_visible_relative, edge_faces_map, delete_edge_faces_map, delete_edge_faces_map2, face_normal_visible_map, basePath)) { printf("LoadVisibleFacesData error\n"); } @@ -11227,6 +12378,28 @@ bool Scene::is_face_delete_edge(const std::string& image_name, int face_index) { return false; } +bool Scene::is_face_delete_edge2(const std::string& image_name, int face_index) { + +#ifndef MASK_FACE_OCCLUSION + return true; +#endif + + auto it = delete_edge_faces_map2.find(image_name); + if (it != delete_edge_faces_map2.end()) { + // printf("is_face_delete_edge2 %s, %d, %d\n", image_name.c_str(), it->second.size(), face_index); + + for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { + // std::cout << *it2 << " "; + } + // std::cout << std::endl; + + // if (it->second.find(face_index) != it->second.end()) + // printf("find is_face_delete_edge %s, %d, %d\n", image_name.c_str(), it->second.size(), face_index); + return it->second.find(face_index) != it->second.end(); + } + return false; +} + bool Scene::is_face_normal_visible_map(const std::string& image_name, int face_index) { #ifndef MASK_FACE_OCCLUSION @@ -11240,7 +12413,6 @@ bool Scene::is_face_normal_visible_map(const std::string& image_name, int face_i return false; } - void Scene::SegmentMeshBasedOnCurvature(Mesh::FaceIdxArr& regionMap, float curvatureThreshold) { // 确保网格数据有效 if (mesh.faces.empty() || mesh.vertices.empty() || diff --git a/libs/MVS/mask_face_occlusion.py b/libs/MVS/mask_face_occlusion.py index 2e12ac0..bfeb71d 100755 --- a/libs/MVS/mask_face_occlusion.py +++ b/libs/MVS/mask_face_occlusion.py @@ -1427,13 +1427,15 @@ class ModelProcessor: # ============ 法线夹角过滤结束 ============ # 使用与CPU版本相同的后续处理 - shrunk_visibility = self._shrink_face_visibility(face_visible.cpu().numpy(), 12) + shrunk_visibility = self._shrink_face_visibility(face_visible.cpu().numpy(), 6) expanded_visibility = self._expand_face_visibility(face_visible.cpu().numpy(), 0) shrunk_visibility2 = self._shrink_face_visibility(face_visible.cpu().numpy(), 0) + shrunk_visibility3 = self._shrink_face_visibility(face_visible.cpu().numpy(), 100) expanded_edge = expanded_visibility & ~shrunk_visibility2 delete_edge = face_visible.cpu().numpy() & ~shrunk_visibility + delete_edge2 = face_visible.cpu().numpy() & ~shrunk_visibility3 - return shrunk_visibility, expanded_edge, delete_edge, face_normal_visible + return shrunk_visibility, expanded_edge, delete_edge, delete_edge2, face_normal_visible """ def _gen_depth_image_gpu(self, cam_data, render): @@ -1464,6 +1466,7 @@ class ModelProcessor: visible_faces_dict = {} edge_faces_dict = {} delete_edge_faces_dict = {} + delete_edge_faces_dict2 = {} face_normal_visible_dict = {} total_start = time.time() @@ -1490,13 +1493,14 @@ class ModelProcessor: # continue start_time = time.time() - face_visibility, face_edge, face_delete_edge, face_normal_visible = self._flag_model_gpu(camera_data) + face_visibility, face_edge, face_delete_edge, face_delete_edge2, face_normal_visible = self._flag_model_gpu(camera_data) processing_time = time.time() - start_time visible_faces = np.where(face_visibility)[0].tolist() visible_faces_dict[img_name] = visible_faces edge_faces_dict[img_name] = np.where(face_edge)[0].tolist() delete_edge_faces_dict[img_name] = np.where(face_delete_edge)[0].tolist() + delete_edge_faces_dict2[img_name] = np.where(face_delete_edge2)[0].tolist() face_normal_visible_dict[img_name] = np.where(face_normal_visible.cpu().numpy())[0].tolist() print(f"图像 {img_name} 处理完成,耗时: {processing_time:.2f}秒,可见面数量{len(visible_faces)}") @@ -1505,13 +1509,14 @@ class ModelProcessor: print(f"所有图像处理完成,总耗时: {total_time:.2f}秒") print(f"平均每张图像耗时: {total_time/len(images):.2f}秒") - self.save_occlusion_data(visible_faces_dict, edge_faces_dict, delete_edge_faces_dict, face_normal_visible_dict, self.asset_dir) + self.save_occlusion_data(visible_faces_dict, edge_faces_dict, delete_edge_faces_dict, delete_edge_faces_dict2, face_normal_visible_dict, self.asset_dir) return { "result1": visible_faces_dict, "result2": edge_faces_dict, "result3": delete_edge_faces_dict, - "result4": face_normal_visible_dict + "result4": delete_edge_faces_dict2, + "result5": face_normal_visible_dict } #""" @@ -2098,6 +2103,7 @@ class ModelProcessor: result2: Dict[str, List[int]], result3: Dict[str, List[int]], result4: Dict[str, List[int]], + result5: Dict[str, List[int]], base_path: str) -> None: """ 保存遮挡数据到文件 @@ -2133,8 +2139,12 @@ class ModelProcessor: for image_name, face_list in result3.items(): delete_edge_faces_map[image_name] = set(face_list) - face_normal_visible_map: Dict[str, Set[int]] = {} + delete_edge_faces_map2: Dict[str, Set[int]] = {} for image_name, face_list in result4.items(): + delete_edge_faces_map2[image_name] = set(face_list) + + face_normal_visible_map: Dict[str, Set[int]] = {} + for image_name, face_list in result5.items(): face_normal_visible_map[image_name] = set(face_list) # 保存 visible_faces_map @@ -2181,16 +2191,27 @@ class ModelProcessor: except IOError as e: print(f"Error writing delete_edge_faces_map file: {e}") + # 保存 delete_edge_faces_map2 + try: + file_name = "_delete_edge_faces_map2.txt" + file_path = Path(base_path) / file_name + with open(file_path, "w", encoding='utf-8') as map_file4: + for image_name, face_set in delete_edge_faces_map2.items(): + line = image_name + " " + " ".join(str(face) for face in face_set) + "\n" + map_file4.write(line) + except IOError as e: + print(f"Error writing delete_edge_faces_map2 file: {e}") + # 保存 face_normal_visible_map try: file_name = "_face_normal_visible_map.txt" file_path = Path(base_path) / file_name - with open(file_path, "w", encoding='utf-8') as map_file4: + with open(file_path, "w", encoding='utf-8') as map_file5: for image_name, face_set in face_normal_visible_map.items(): line = image_name + " " + " ".join(str(face) for face in face_set) + "\n" - map_file4.write(line) + map_file5.write(line) except IOError as e: - print(f"Error writing delete_edge_faces_map file: {e}") + print(f"Error writing _face_normal_visible_map file: {e}") def process(self):