diff --git a/libs/MVS/ColorComparisonFace.cpp b/libs/MVS/ColorComparisonFace.cpp index 2e4fe45..45477a2 100644 --- a/libs/MVS/ColorComparisonFace.cpp +++ b/libs/MVS/ColorComparisonFace.cpp @@ -443,4 +443,325 @@ void ColorComparisonFace::saveColorInfoToFile() { fclose(summaryFp); printf("✅ 三角形汇总统计信息已保存到: %s\n", summaryPath.c_str()); } +} + +// 在ColorComparisonFace.cpp中添加以下函数实现 + +// 添加连续区域信息 +void ColorComparisonFace::addContinuousRegionInfo(int regionId, + const std::set& faceIds, // 修改为 unsigned int + MeshColor regionGaussianColor) { + if (continuousRegions.find(regionId) == continuousRegions.end()) { + ContinuousRegionInfo regionInfo; + regionInfo.regionId = regionId; + regionInfo.faceIds = faceIds; // 这里类型匹配 + regionInfo.regionGaussianColor = regionGaussianColor; + regionInfo.totalPixels = 0; + continuousRegions[regionId] = regionInfo; + + printf("添加连续区域 %d: 包含 %zu 个面\n", regionId, faceIds.size()); + } +} + +// 添加连续区域在特定视图中的信息 +void ColorComparisonFace::addRegionViewInfo(int regionId, + const std::string& filename, + MeshColor viewColor, + const cv::Mat& regionImage, + const cv::Mat& visualization, + float colorDistance) { + if (continuousRegions.find(regionId) != continuousRegions.end()) { + ContinuousRegionInfo& regionInfo = continuousRegions[regionId]; + regionInfo.viewColors[filename] = viewColor; + regionInfo.viewRegions[filename] = regionImage.clone(); + regionInfo.viewVisualizations[filename] = visualization.clone(); + regionInfo.viewDistances[filename] = colorDistance; + + printf(" 视图 %s: 颜色(R=%d,G=%d,B=%d), 距离=%.4f\n", + filename.c_str(), viewColor.r, viewColor.g, viewColor.b, colorDistance); + } +} + +// 获取连续区域数 +int ColorComparisonFace::getTotalRegions() const { + return continuousRegions.size(); +} + +// 创建连续区域跨视图比较图 +void ColorComparisonFace::createContinuousRegionComparison(int maxBlocksPerRow, int maxRegionsPerImage) { + if (continuousRegions.empty()) { + printf("⚠️ 没有连续区域信息可生成\n"); + return; + } + + printf("正在创建连续区域跨视图比较图...\n"); + printf("总连续区域数: %zu\n", continuousRegions.size()); + + // 限制处理的区域数 + int regionsToProcess = std::min((int)continuousRegions.size(), maxRegionsPerImage); + + // 处理前N个区域 + int regionCount = 0; + for (const auto& regionEntry : continuousRegions) { + if (regionCount >= regionsToProcess) break; + + int regionId = regionEntry.first; + const ContinuousRegionInfo& regionInfo = regionEntry.second; + + printf("处理连续区域 %d: 在 %zu 个视图中可见\n", regionId, regionInfo.viewColors.size()); + + if (regionInfo.viewColors.size() < 2) { + printf(" 区域 %d 在少于2个视图中可见,跳过跨视图比较\n", regionId); + regionCount++; + continue; + } + + // 块参数 + int regionSize = 200; // 区域显示大小 + int colorBlockSize = 100; // 颜色块大小 + int blockMargin = 20; // 块之间的边距 + int infoHeight = 120; // 信息区域高度 + + // 计算需要的行数和列数 + int numBlocks = regionInfo.viewColors.size(); + int numCols = std::min(maxBlocksPerRow, numBlocks); + int numRows = (numBlocks + numCols - 1) / numCols; + + // 计算每个块的宽度和高度 + int blockWidth = colorBlockSize + regionSize + blockMargin * 3; + int blockHeight = regionSize + blockMargin + infoHeight; + + // 图片总尺寸 + int totalWidth = numCols * (blockWidth + blockMargin) + blockMargin; + int totalHeight = 100 + (numRows * (blockHeight + blockMargin)) + blockMargin; + + // 创建大图 + cv::Mat regionImage(totalHeight, totalWidth, CV_8UC3, cv::Scalar(240, 240, 240)); + + // 添加标题 + std::string title = cv::format("Continuous Region %d - Cross-View Comparison", regionId); + cv::putText(regionImage, title, + cv::Point(20, 30), + cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 0), 2); + + // 添加区域统计信息 + std::string regionStats = cv::format("Contains %zu faces, Visible in %zu views", + regionInfo.faceIds.size(), regionInfo.viewColors.size()); + cv::putText(regionImage, regionStats, + cv::Point(20, 60), + cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 0, 0), 1); + + std::string gaussStats = cv::format("Region Gaussian Color: R=%d, G=%d, B=%d", + regionInfo.regionGaussianColor.r, + regionInfo.regionGaussianColor.g, + regionInfo.regionGaussianColor.b); + cv::putText(regionImage, gaussStats, + cv::Point(20, 85), + cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(255, 0, 0), 1); + + int blockIndex = 0; + int currentRow = 0; + int currentCol = 0; + + // 计算统计数据 + float sumDistances = 0.0f; + float maxDistance = 0.0f; + std::string worstView; + + // 遍历这个区域的所有视图 + for (const auto& viewEntry : regionInfo.viewColors) { + const std::string& viewName = viewEntry.first; + const MeshColor& viewColor = viewEntry.second; + float colorDistance = regionInfo.viewDistances.at(viewName); + + sumDistances += colorDistance; + if (colorDistance > maxDistance) { + maxDistance = colorDistance; + worstView = viewName; + } + + // 计算当前块的位置 + int blockX = blockMargin + currentCol * (blockWidth + blockMargin); + int blockY = 100 + blockMargin + currentRow * (blockHeight + blockMargin); + + // 绘制块背景 + cv::rectangle(regionImage, + cv::Rect(blockX, blockY, blockWidth, blockHeight), + cv::Scalar(255, 255, 255), -1); + cv::rectangle(regionImage, + cv::Rect(blockX, blockY, blockWidth, blockHeight), + cv::Scalar(200, 200, 200), 2); + + // 绘制区域高斯颜色块 + int gaussianX = blockX + blockMargin; + int gaussianY = blockY + blockMargin; + + cv::Scalar gaussianBGR(regionInfo.regionGaussianColor[2], + regionInfo.regionGaussianColor[1], + regionInfo.regionGaussianColor[0]); + cv::rectangle(regionImage, + cv::Rect(gaussianX, gaussianY, colorBlockSize, colorBlockSize), + gaussianBGR, -1); + cv::rectangle(regionImage, + cv::Rect(gaussianX, gaussianY, colorBlockSize, colorBlockSize), + cv::Scalar(0, 0, 0), 2); + + // 添加高斯标签 + cv::putText(regionImage, "REGION GAUSS", + cv::Point(gaussianX + 5, gaussianY - 5), + cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(0, 0, 0), 1); + + // 绘制区域图像块 + int regionX = blockX + blockMargin + colorBlockSize + blockMargin; + int regionY = blockY + blockMargin; + + auto visIt = regionInfo.viewVisualizations.find(viewName); + if (visIt != regionInfo.viewVisualizations.end() && !visIt->second.empty()) { + cv::Mat resizedRegion; + cv::resize(visIt->second, resizedRegion, cv::Size(regionSize, regionSize)); + + // 将区域图像绘制到指定位置 + resizedRegion.copyTo(regionImage(cv::Rect(regionX, regionY, regionSize, regionSize))); + + cv::rectangle(regionImage, + cv::Rect(regionX, regionY, regionSize, regionSize), + cv::Scalar(0, 0, 0), 2); + + // 添加视图标签 + cv::putText(regionImage, "VIEW REGION", + cv::Point(regionX + 5, regionY - 5), + cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(0, 0, 0), 1); + } + + // 绘制信息区域 + int infoY = blockY + blockMargin + regionSize; + cv::rectangle(regionImage, + cv::Rect(blockX, infoY, blockWidth, infoHeight), + cv::Scalar(240, 240, 240), -1); + cv::rectangle(regionImage, + cv::Rect(blockX, infoY, blockWidth, infoHeight), + cv::Scalar(200, 200, 200), 1); + + // 添加视图信息 + std::string displayName = viewName; + if (displayName.length() > 20) { + displayName = displayName.substr(0, 18) + "..."; + } + + cv::putText(regionImage, cv::format("View: %s", displayName.c_str()), + cv::Point(blockX + 10, infoY + 20), + cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(0, 0, 0), 1); + + cv::putText(regionImage, cv::format("Region: %d", regionId), + cv::Point(blockX + 10, infoY + 40), + cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(0, 0, 0), 1); + + // 添加颜色值 + cv::putText(regionImage, + cv::format("Region Gauss: (%d,%d,%d)", + regionInfo.regionGaussianColor[0], + regionInfo.regionGaussianColor[1], + regionInfo.regionGaussianColor[2]), + cv::Point(blockX + 10, infoY + 60), + cv::FONT_HERSHEY_SIMPLEX, 0.35, cv::Scalar(0, 0, 0), 1); + + cv::putText(regionImage, + cv::format("View Color: (%d,%d,%d)", + viewColor[0], viewColor[1], viewColor[2]), + cv::Point(blockX + 10, infoY + 80), + cv::FONT_HERSHEY_SIMPLEX, 0.35, cv::Scalar(0, 0, 0), 1); + + // 添加距离和阈值 + cv::putText(regionImage, + cv::format("Distance: %.4f", colorDistance), + cv::Point(blockX + 10, infoY + 100), + cv::FONT_HERSHEY_SIMPLEX, 0.35, cv::Scalar(0, 0, 0), 1); + + // 添加判断结果 + int resultX = blockX + blockWidth - 50; + int resultY = infoY + 30; + + std::string resultText = (colorDistance > 0.31f) ? "FIX" : "OK"; + cv::Scalar resultColor = (colorDistance > 0.31f) ? cv::Scalar(0, 0, 255) : cv::Scalar(0, 180, 0); + + cv::putText(regionImage, resultText, + cv::Point(resultX, resultY), + cv::FONT_HERSHEY_SIMPLEX, 0.6, resultColor, 1); + + // 更新行和列索引 + blockIndex++; + currentCol++; + if (currentCol >= numCols) { + currentCol = 0; + currentRow++; + } + } + + // 在底部添加统计信息 + float avgDistance = sumDistances / regionInfo.viewColors.size(); + std::string stats = cv::format("Avg Distance: %.4f, Max Distance: %.4f (in %s)", + avgDistance, maxDistance, worstView.c_str()); + cv::putText(regionImage, stats, + cv::Point(20, totalHeight - 20), + cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 0, 0), 1); + + // 保存图片 + std::string outputPath = outputDir + cv::format("continuous_region_%d_comparison.png", regionId); + + if (!cv::imwrite(outputPath, regionImage)) { + printf("❌❌ 无法保存连续区域 %d 的对比图: %s\n", regionId, outputPath.c_str()); + } else { + printf("✅ 连续区域 %d 对比图已保存: %s\n", regionId, outputPath.c_str()); + } + + regionCount++; + } + + // 保存连续区域信息到CSV文件 + std::string regionSummaryPath = outputDir + "continuous_regions_summary.csv"; + FILE* regionFp = fopen(regionSummaryPath.c_str(), "w"); + + if (regionFp) { + fprintf(regionFp, "RegionID,FaceCount,Views,AvgDistance,MaxDistance,WorstView,NeedsFixCount,NeedsFix%%\n"); + + for (const auto& regionEntry : continuousRegions) { + int regionId = regionEntry.first; + const ContinuousRegionInfo& regionInfo = regionEntry.second; + + float sumDist = 0.0f; + float maxDist = 0.0f; + int needsFixCount = 0; + + for (const auto& distEntry : regionInfo.viewDistances) { + float dist = distEntry.second; + sumDist += dist; + if (dist > maxDist) maxDist = dist; + if (dist > 0.31f) needsFixCount++; + } + + float avgDist = (regionInfo.viewDistances.size() > 0) ? + (sumDist / regionInfo.viewDistances.size()) : 0.0f; + float fixPercentage = (regionInfo.viewDistances.size() > 0) ? + (needsFixCount * 100.0f / regionInfo.viewDistances.size()) : 0.0f; + + fprintf(regionFp, "%d,%zu,%zu,%.4f,%.4f,", + regionId, regionInfo.faceIds.size(), regionInfo.viewDistances.size(), + avgDist, maxDist); + + // 找到最差的视图 + std::string worstView = ""; + for (const auto& distEntry : regionInfo.viewDistances) { + if (distEntry.second == maxDist) { + worstView = distEntry.first; + break; + } + } + + fprintf(regionFp, "%s,%d,%.2f%%\n", + worstView.c_str(), needsFixCount, fixPercentage); + } + + fclose(regionFp); + printf("✅ 连续区域汇总统计信息已保存到: %s\n", regionSummaryPath.c_str()); + } } \ No newline at end of file diff --git a/libs/MVS/ColorComparisonFace.h b/libs/MVS/ColorComparisonFace.h index ee38757..c2c3212 100644 --- a/libs/MVS/ColorComparisonFace.h +++ b/libs/MVS/ColorComparisonFace.h @@ -4,6 +4,7 @@ #include #include #include +#include #include // 不使用前向声明,直接定义简单的颜色结构 @@ -24,6 +25,7 @@ struct MeshColor { class ColorComparisonFace { private: + // 单面信息结构 struct FaceColorInfo { int faceId; // 面的ID MeshColor gaussianColor; // 高斯颜色 @@ -34,9 +36,25 @@ private: float threshold; // 阈值 std::string filename; // 文件名 }; + + // 连续区域信息结构 + struct ContinuousRegionInfo { + int regionId; // 区域ID + std::set faceIds; // 修改为 unsigned int + MeshColor regionGaussianColor; // 区域的整体高斯颜色 + std::map viewColors; // 每个视图的颜色 + std::map viewRegions; // 每个视图的区域图像 + std::map viewVisualizations; // 每个视图的可视化 + std::map viewDistances; // 每个视图的距离 + int totalPixels; // 区域总像素数 + }; // 使用嵌套map: faceid -> filename -> FaceColorInfo列表 std::map>> faceViewColorMap; + + // 连续区域映射: regionId -> ContinuousRegionInfo + std::map continuousRegions; + std::string outputDir; public: @@ -56,9 +74,25 @@ public: float threshold, const std::string& filename); + // 添加连续区域信息 + void addContinuousRegionInfo(int regionId, + const std::set& faceIds, // 修改为 unsigned int + MeshColor regionGaussianColor); + + // 添加连续区域在特定视图中的信息 + void addRegionViewInfo(int regionId, + const std::string& filename, + MeshColor viewColor, + const cv::Mat& regionImage, + const cv::Mat& visualization, + float colorDistance); + // 创建三角形区域对比图 void createBatchComparison(int maxBlocksPerRow = 6, int maxFacesPerImage = 20); + // 创建连续区域跨视图比较图 + void createContinuousRegionComparison(int maxBlocksPerRow = 6, int maxRegionsPerImage = 20); + // 保存颜色信息到CSV文件 void saveColorInfoToFile(); @@ -70,6 +104,9 @@ public: // 获取faceid列表 std::vector getFaceIds() const; + + // 获取连续区域数 + int getTotalRegions() const; }; #endif // COLORCOMPARISONBFACE_H \ No newline at end of file diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index b8df367..e120d10 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -78,7 +78,7 @@ using namespace MVS; #define TEXOPT_INFERENCE_TRWS 2 #define TEXOPT_INFERENCE TEXOPT_INFERENCE_LBP #define MASK_FACE_OCCLUSION -// #define TEST +#define TEST // #define USE_CUDA @@ -985,6 +985,77 @@ public: image = visualization; } + // 判断两个面是否相邻(共享一条边) + static bool areFacesAdjacent(const Mesh::Face& face1, const Mesh::Face& face2) { + int sharedVertices = 0; + + // 检查共享的顶点数量 + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (face1[i] == face2[j]) { + sharedVertices++; + } + } + } + + // 如果共享2个顶点,说明共享一条边 + return sharedVertices == 2; + } + + // 修改 mergeContinuousFaces 函数的类型 + static std::map> mergeContinuousFaces( // 返回类型改为 unsigned int + const std::set& testFaces, // 参数类型改为 unsigned int + const Mesh& mesh) { + + std::map> regions; // 返回类型改为 unsigned int + std::set processed; // 类型改为 unsigned int + int regionId = 0; + + // 遍历所有测试面 + for (unsigned int face : testFaces) { // 类型改为 unsigned int + if (processed.find(face) != processed.end()) { + continue; + } + + // 开始新区域 + std::set currentRegion; // 类型改为 unsigned int + std::queue faceQueue; // 类型改为 unsigned int + faceQueue.push(face); + + while (!faceQueue.empty()) { + unsigned int currentFace = faceQueue.front(); // 类型改为 unsigned int + faceQueue.pop(); + + if (processed.find(currentFace) != processed.end()) { + continue; + } + + // 添加到当前区域 + currentRegion.insert(currentFace); + processed.insert(currentFace); + + // 查找相邻的测试面 + for (unsigned int otherFace : testFaces) { // 类型改为 unsigned int + if (processed.find(otherFace) != processed.end()) { + continue; + } + + // 检查是否相邻 + if (areFacesAdjacent(mesh.faces[currentFace], mesh.faces[otherFace])) { + faceQueue.push(otherFace); + } + } + } + + if (!currentRegion.empty()) { + regions[regionId] = currentRegion; + regionId++; + } + } + + return regions; + } + //*/ /* // 采用ITU-R BT.601标准系数,增加数值稳定性处理 @@ -1200,13 +1271,63 @@ static ColorComparisonPixel* g_colorComparisonPixel = nullptr; bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThreshold, int nIgnoreMaskLabel, const IIndexArr& _views, bool bUseVirtualFaces) { #ifdef TEST - std::string outputDir = scene.base_path + std::string("/color_comparison/"); - printf("ListCameraFaces outputDir=%s\n", outputDir.c_str()); + std::string outputDir = scene.base_path + std::string("/color_comparison/"); + printf("ListCameraFaces outputDir=%s\n", outputDir.c_str()); g_colorComparisonFace = new ColorComparisonFace(outputDir); - std::map>> testFacePixelsByView; + std::map>> testFacePixelsByView; - g_colorComparisonPixel = new ColorComparisonPixel(outputDir); + g_colorComparisonPixel = new ColorComparisonPixel(outputDir); + + // 1. 收集所有测试面 + std::set allTestFaces; // 修改为 unsigned int + for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { + if (isTestFace(scene.face_test, idxFace)) { + allTestFaces.insert(idxFace); + } + } + + printf("找到 %zu 个测试面\n", allTestFaces.size()); + + // 2. 合并连续的三角形为区域 + std::map> continuousRegions = mergeContinuousFaces(allTestFaces, scene.mesh); + printf("将测试面合并为 %zu 个连续区域\n", continuousRegions.size()); + + // 3. 为每个区域计算平均高斯颜色 + std::map regionGaussianColors; + for (const auto& regionEntry : continuousRegions) { + int regionId = regionEntry.first; + const std::set& regionFaces = regionEntry.second; // 修改为 unsigned int + + float sumR = 0, sumG = 0, sumB = 0; + int faceCount = 0; + + for (unsigned int faceId : regionFaces) { // 修改为 unsigned int + if (faceId < faceColorsGaussian.size()) { + Mesh::Color gaussianColor = faceColorsGaussian[faceId]; + sumR += gaussianColor.r; + sumG += gaussianColor.g; + sumB += gaussianColor.b; + faceCount++; + } + } + + if (faceCount > 0) { + MeshColor avgColor( + static_cast(sumR / faceCount), + static_cast(sumG / faceCount), + static_cast(sumB / faceCount) + ); + regionGaussianColors[regionId] = avgColor; + + printf("区域 %d: 包含 %zu 个面,高斯颜色(R=%d,G=%d,B=%d)\n", + regionId, regionFaces.size(), + avgColor.r, avgColor.g, avgColor.b); + + // 添加到批处理器 + g_colorComparisonFace->addContinuousRegionInfo(regionId, regionFaces, avgColor); + } + } #endif // create faces octree