diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index 0497a7a..6adaead 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -495,7 +495,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; + void CreateVirtualFaces64(const FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; bool CreateVirtualFaces65(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; void CreateVirtualFaces8(const FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; @@ -5746,138 +5746,8 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView return true; } -bool MeshTexture::CreateVirtualFaces64(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras, float thMaxNormalDeviation) const +void MeshTexture::CreateVirtualFaces64(const FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, unsigned minCommonCameras, float thMaxNormalDeviation) const { - if (meshCurvatures.empty()) { - ComputeFaceCurvatures(); - } - - // 如果夹角小于45度(cos(45°) ≈ 0.7071),则计入覆盖 - float fAngleThreshold1 = 0.6071; // 0.7071f - float fAngleThreshold2 = 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) { - - if (mapViewCoverageData.find(idxView) == mapViewCoverageData.end()) - { - // 插入新对象 - mapViewCoverageData.emplace(idxView, ViewCoverageData(idxView)); - } - - ViewCoverageData& viewData = mapViewCoverageData[idxView]; - - 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()); - - // 遍历所有面片,统计满足条件的面片 - 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 > fAngleThreshold2) - { - coverageCount++; - - viewData.faceToIndexMap[idxFace] = idxFace; - } - - if (cosAngle > fAngleThreshold1) - { - // viewData.faceToIndexMap[idxFace] = idxFace; - } - } - - 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; - const float ratioAngleToQuality(0.67f); const float cosMaxNormalDeviation(COS(FD2R(thMaxNormalDeviation))); Mesh::FaceIdxArr remainingFaces(faces.size()); @@ -5885,94 +5755,12 @@ bool MeshTexture::CreateVirtualFaces64(FaceDataViewArr& facesDatas, FaceDataView std::vector selectedFaces(faces.size(), false); cQueue currentVirtualFaceQueue; std::unordered_set queuedFaces; - - // 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; @@ -5983,269 +5771,22 @@ bool MeshTexture::CreateVirtualFaces64(FaceDataViewArr& facesDatas, FaceDataView 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; - std::map mapSortedcams2; - 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; - } - } - - if (!scene.is_face_delete_edge(strName, virtualFaceCenterFaceID)) { - - if (scene.is_face_edge(strName, virtualFaceCenterFaceID)) - { - // if (angleDeg <= 30.0f) - { - mapSortedcams2[idxView] = angleDeg; - } - } - else - { - // if (angleDeg <= 80.0f) - { - mapSortedcams2[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排序 - }); - - // 将map中的元素放入vector以便排序 - std::vector> sortedCams2; - sortedCams2.reserve(mapSortedcams2.size()); - for (const auto& pair : mapSortedcams2) { - sortedCams2.emplace_back(pair.first, pair.second); - } - - // 按angleDeg从小到大排序 - std::sort(sortedCams2.begin(), sortedCams2.end(), - [](const std::pair& a, const std::pair& b) { - return a.second < b.second; - }); - - IIndexArr filteredCams; - - int nViewCoverage = 0; - int nViewCoverageMax = 100; - int nHit = 0; - int nHitMax = 5; - std::map mapProcessedViewIdx; - //* - for (const auto& [viewIdx, coverageCount] : viewCoverage) { - if (nViewCoverage>=nViewCoverageMax) - // if (nHit>nHitMax) - break; - - auto it_view = mapViewCoverageData.find(viewIdx); - if (it_view == mapViewCoverageData.end()) { - continue; - } - - const ViewCoverageData& viewData = it_view->second; - - const Image& imageData = images[viewIdx]; - std::string strPath = imageData.name; - std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); - // printf("strName=%s\n", strName.c_str()); - // if (strName!="94_2") - // continue; - - if (viewData.faceToIndexMap.find(virtualFaceCenterFaceID) != viewData.faceToIndexMap.end()) - { - if (!scene.is_face_delete_edge(strName, virtualFaceCenterFaceID)) { - if (scene.is_face_edge(strName, virtualFaceCenterFaceID)) - { - // if (angleDeg <= 40.0f) - { - // filteredCams.push_back(viewIdx); - } - } - else - { - // if (filteredCams.empty()) - { - // filteredCams.push_back(viewIdx); - } - } - } - - // if (!scene.is_face_delete_edge2(strName, virtualFaceCenterFaceID)) - { - filteredCams.push_back(viewIdx); - mapProcessedViewIdx[viewIdx] = viewIdx; - ++nHit; - - if (nHit>=nHitMax) - break; - } - } - - ++nViewCoverage; - } - //*/ - - nViewCoverage = 0; - nViewCoverageMax = 200; - nHit = 0; - nHitMax = 1; - for (size_t i = 0; i < sortedCams2.size(); ++i) - { - if (nViewCoverage>=nViewCoverageMax) - // if (nHit>nHitMax) - break; - - IIndex viewIdx = sortedCams2[i].first; - float val = sortedCams2[i].second; - - if (mapProcessedViewIdx.count(viewIdx) > 0) - continue; - - const Image& imageData = images[viewIdx]; - std::string strPath = imageData.name; - std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); - - // if (strName!="94_2") - // continue; - - // if (!scene.is_face_delete_edge2(strName, virtualFaceCenterFaceID)) - { - filteredCams.push_back(viewIdx); - ++nHit; - - if (nHit>=nHitMax) - break; - } - - ++nViewCoverage; - } - - if (filteredCams.empty()) { - size_t count = std::min(sortedCams.size(), static_cast(3)); - for (size_t i = 0; i < count; ++i) { - - // IIndex viewIdx = sortedCams[i].first; - // float val = sortedCams[i].second; - // const Image& imageData = images[viewIdx]; - // std::string strPath = imageData.name; - // std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); - // if (strName!="94_2") - // continue; - - filteredCams.push_back(sortedCams[i].first); - } - } - - // 确保 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; - } - //*/ - + const IIndexArr selectedCams = SelectBestViews(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality); 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; - - // 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; // 如果颜色差异太大,跳过 - } - - { - 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 - } - } - + 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) + continue; + // check if current face is seen by all cameras in selectedCams + ASSERT(!selectedCams.empty()); + if (!IsFaceVisible(facesDatas[currentFaceId], selectedCams)) + continue; // remove it from remaining faces and add it to the virtual face { const auto posToErase = remainingFaces.FindFirst(currentFaceId); @@ -6266,7 +5807,6 @@ bool MeshTexture::CreateVirtualFaces64(FaceDataViewArr& facesDatas, FaceDataView } } } while (!currentVirtualFaceQueue.IsEmpty()); - // compute virtual face quality and create virtual face for (IIndex idxView: selectedCams) { FaceData& virtualFaceData = virtualFaceDatas.emplace_back(); @@ -6275,241 +5815,46 @@ bool MeshTexture::CreateVirtualFaces64(FaceDataViewArr& facesDatas, FaceDataView #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 (bHasInvalidView) - { - - ++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; + ASSERT(processedFaces > 0); - // 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; + // 修改方案 B:使用第 20% 分位(更鲁棒) + // 收集所有 quality,排序,取较低的那个 + std::vector qualities; + for (FIndex fid : virtualFace) { + const FaceDataArr& faceDatas = facesDatas[fid]; + for (FaceData& faceData: faceDatas) { + if (faceData.idxView == idxView) { + qualities.push_back(faceData.quality); + break; } - virtualFaceData.quality = totalQuality2 / validIndices.size(); - virtualFaceData.color = totalColor2 / validIndices.size(); - - // virtualFaceData.quality = 0; - // #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA - // virtualFaceData.color = Point3f::ZERO; - // #endif } } + std::sort(qualities.begin(), qualities.end()); + virtualFaceData.quality = qualities[qualities.size() * 0.2]; // 取第20% - // virtualFaceData.bInvalidFacesRelative = (invalidCount > 1); - // virtualFaceData.bInvalidFacesRelative = (invalidCount > processedFaces * 2 / 3); + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + virtualFaceData.color /= processedFaces; + #endif } ASSERT(!virtualFaceDatas.empty()); } virtualFacesDatas.emplace_back(std::move(virtualFaceDatas)); virtualFaces.emplace_back(std::move(virtualFace)); } while (!remainingFaces.empty()); - - return true; } bool MeshTexture::CreateVirtualFaces65(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector& isVirtualFace, unsigned minCommonCameras, float thMaxNormalDeviation) const @@ -6850,6 +6195,7 @@ bool MeshTexture::CreateVirtualFaces65(FaceDataViewArr& facesDatas, FaceDataView } else if (highScoreCount2 >= 3) { kMaxViews = 10; } + for (int i = 0; i < kMaxViews && i < scores.size(); ++i) { int index = scores[i].viewIdx; float score = scores[i].score; @@ -6868,8 +6214,8 @@ bool MeshTexture::CreateVirtualFaces65(FaceDataViewArr& facesDatas, FaceDataView if (viewData.faceToIndexMap.find(virtualFaceCenterFaceID) == viewData.faceToIndexMap.end()) continue; - if (score < 0.4f) - continue; + // if (score < 0.4f) + // continue; filteredCams.push_back(index); @@ -6920,7 +6266,7 @@ bool MeshTexture::CreateVirtualFaces65(FaceDataViewArr& facesDatas, FaceDataView if (scene.is_face_edge(strName, virtualFaceCenterFaceID)) { - if (angleDeg <= 40.0f) + // if (angleDeg <= 40.0f) { mapSortedcams[idxView] = angleDeg; } @@ -7037,7 +6383,7 @@ bool MeshTexture::CreateVirtualFaces65(FaceDataViewArr& facesDatas, FaceDataView int nViewCoverage = 0; int nViewCoverageMax = 100; int nHit = 0; - int nHitMax = 5; + int nHitMax = 100; for (const auto& [viewIdx, coverageCount] : viewCoverage) { break; @@ -7101,7 +6447,7 @@ bool MeshTexture::CreateVirtualFaces65(FaceDataViewArr& facesDatas, FaceDataView nViewCoverage = 0; nViewCoverageMax = 200; nHit = 0; - nHitMax = 5; + nHitMax = 100; for (size_t i = 0; i < sortedCams2.size(); ++i) { break; @@ -9911,8 +9257,9 @@ 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); + CreateVirtualFaces64(facesDatas, virtualFacesDatas, virtualFaces, minCommonCameras); // CreateVirtualFaces65(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); - CreateVirtualFaces8(facesDatas, virtualFacesDatas, virtualFaces, minCommonCameras); + // CreateVirtualFaces8(facesDatas, virtualFacesDatas, virtualFaces, minCommonCameras); TD_TIMER_STARTD(); // CreateVirtualFaces7(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); // DEBUG_EXTRA("CreateVirtualFaces completed: %s", TD_TIMER_GET_FMT().c_str());