diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index fb7f2b5..f09fa61 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -476,6 +476,8 @@ public: bool CreateVirtualFaces7(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; IIndexArr SelectBestViews(const FaceDataArr& faceDatas, FIndex fid, unsigned minCommonCameras, float ratioAngleToQuality) const; + IIndexArr SelectBestViews2(const FaceDataArr& faceDatas, FIndex fid, unsigned minCommonCameras, float ratioAngleToQuality, FaceDataViewArr& facesDatas) const; + IIndexArr SelectBestView(const FaceDataArr& faceDatas, FIndex fid, unsigned minCommonCameras, float ratioAngleToQuality) const; bool FaceViewSelection(unsigned minCommonCameras, float fOutlierThreshold, float fRatioDataSmoothness, int nIgnoreMaskLabel, const IIndexArr& views); @@ -1776,6 +1778,97 @@ void MeshTexture::PerformLocalDepthConsistencyCheck(DepthMap& depthMap, FaceMap& } //*/ +IIndexArr MeshTexture::SelectBestViews2(const FaceDataArr& faceDatas, FIndex fid, unsigned minCommonCameras, float ratioAngleToQuality, FaceDataViewArr& facesDatas) const +{ + ASSERT(!faceDatas.empty()); + + // 计算每个视图能看到的相邻面片数量 + std::unordered_map viewCoverageCount; + for (const FaceData& fd : faceDatas) { + if (!fd.bInvalidFacesRelative) { + viewCoverageCount[fd.idxView] = 0; + } + } + + // 统计每个视图能看到的面片数 + for (const FaceData& fd : faceDatas) { + if (!fd.bInvalidFacesRelative) { + // 统计这个视图能看到的所有相邻面片 + const Mesh::FaceFaces& ffaces = faceFaces[fid]; + for (int i = 0; i < 3; ++i) { + const FIndex neighborIdx = ffaces[i]; + if (neighborIdx != NO_ID) { + const FaceDataArr& neighborDatas = facesDatas[neighborIdx]; + for (const FaceData& neighborFd : neighborDatas) { + if (neighborFd.idxView == fd.idxView && !neighborFd.bInvalidFacesRelative) { + viewCoverageCount[fd.idxView]++; + break; + } + } + } + } + } + } + + // 重新计算分数,考虑覆盖范围 + float maxQuality = 0; + for (const FaceData& faceData: faceDatas) + maxQuality = MAXF(maxQuality, faceData.quality); + const Face& f = faces[fid]; + const Vertex faceCenter((vertices[f[0]] + vertices[f[1]] + vertices[f[2]]) / 3.f); + + CLISTDEF0IDX(float,IIndex) scores(faceDatas.size()); + FOREACH(idxFaceData, faceDatas) { + const FaceData& faceData = faceDatas[idxFaceData]; + if (faceData.bInvalidFacesRelative) { + scores[idxFaceData] = -1.0f; // 无效视图分数为负 + continue; + } + + const Image& imageData = images[faceData.idxView]; + const Point3f camDir(Cast(imageData.camera.C) - faceCenter); + const Normal& faceNormal = scene.mesh.faceNormals[fid]; + const float cosFaceCam(ComputeAngle(camDir.ptr(), faceNormal.ptr())); + + // 计算覆盖范围分数(0-1之间) + float coverageScore = 0.0f; + if (viewCoverageCount.find(faceData.idxView) != viewCoverageCount.end()) { + int maxCoverage = 0; + for (const auto& pair : viewCoverageCount) { + maxCoverage = MAX(maxCoverage, pair.second); + } + if (maxCoverage > 0) { + coverageScore = static_cast(viewCoverageCount[faceData.idxView]) / maxCoverage; + } + } + + // 综合角度、质量和覆盖范围 + const float angleScore = ratioAngleToQuality * cosFaceCam; + const float qualityScore = (1.0f - ratioAngleToQuality) * faceData.quality / maxQuality; + const float coverageWeight = 0.3f; // 覆盖范围权重 + const float combinedScore = 0.4f * angleScore + 0.3f * qualityScore + coverageWeight * coverageScore; + + scores[idxFaceData] = combinedScore; + } + + // 按分数排序 + IIndexArr scorePodium(faceDatas.size()); + std::iota(scorePodium.begin(), scorePodium.end(), 0); + scorePodium.Sort([&scores](IIndex i, IIndex j) { + return scores[i] > scores[j]; + }); + + // 选择最佳视图 + IIndexArr cameras; + for (IIndex i = 0; i < MIN(minCommonCameras, faceDatas.size()); ++i) { + if (scores[scorePodium[i]] > 0.1f) { // 分数阈值 + cameras.push_back(faceDatas[scorePodium[i]].idxView); + } + } + + return cameras; +} + // order the camera view scores with highest score first and return the list of first cameras // ratioAngleToQuality represents the ratio in witch we combine normal angle to quality for a face to obtain the selection score // - a ratio of 1 means only angle is considered @@ -2962,8 +3055,8 @@ bool MeshTexture::CreateVirtualFaces6(FaceDataViewArr& facesDatas, FaceDataViewA ASSERT(posToErase != Mesh::FaceIdxArr::NO_INDEX); remainingFaces.RemoveAtMove(posToErase); } else { + // IIndexArr selectedCams = SelectBestViews2(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality, facesDatas); IIndexArr selectedCams = SelectBestViews(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality); - //* // 获取中心面片的法线 (注意变量名是 normalCenter, 不是 centerNormal) const Normal& normalCenter = scene.mesh.faceNormals[virtualFaceCenterFaceID]; @@ -4228,6 +4321,16 @@ 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方法且您关心性能) @@ -4326,7 +4429,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView 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]; @@ -4383,7 +4486,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView { // printf("CreateVirtualFace %s, %d, %f\n", strName.c_str(), virtualFaceCenterFaceID, angleLimit); - if (angleDeg <= 45.0f) + if (angleDeg <= 35.0f) { filteredCams.push_back(idxView); /* @@ -4455,22 +4558,40 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView 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 < cosMaxNormalDeviation) + if (cosFaceToCenter < dynamicCosTh) + continue; + // if (cosFaceToCenter < dynamicCosTh) // 使用动态阈值 + // continue; + // printf("dynamicCosTh=%f\n", dynamicCosTh); + // if (cosFaceToCenter < 0.99) // 对应60度,比原来的更宽松 // continue; - if (cosFaceToCenter < dynamicCosTh) // 使用动态阈值 - continue; + // check if current face is seen by all cameras in selectedCams ASSERT(!selectedCams.empty()); if (!IsFaceVisible(facesDatas[currentFaceId], selectedCams)) continue; - // Check color similarity + // 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); @@ -7040,7 +7161,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT } } */ - + // construct and use virtual faces for patch creation instead of actual mesh faces; // the virtual faces are composed of coplanar triangles sharing same views if (bUseVirtualFaces) { @@ -7058,7 +7179,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT CreateVirtualFaces62(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); TD_TIMER_STARTD(); // CreateVirtualFaces7(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); - DEBUG_EXTRA("CreateVirtualFaces7 completed: %s", TD_TIMER_GET_FMT().c_str()); + DEBUG_EXTRA("CreateVirtualFaces completed: %s", TD_TIMER_GET_FMT().c_str()); size_t controlCounter(0); FOREACH(idxVF, virtualFaces) {