|
|
|
|
@ -444,3 +444,324 @@ void ColorComparisonFace::saveColorInfoToFile() {
@@ -444,3 +444,324 @@ void ColorComparisonFace::saveColorInfoToFile() {
|
|
|
|
|
printf("✅ 三角形汇总统计信息已保存到: %s\n", summaryPath.c_str()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 在ColorComparisonFace.cpp中添加以下函数实现
|
|
|
|
|
|
|
|
|
|
// 添加连续区域信息
|
|
|
|
|
void ColorComparisonFace::addContinuousRegionInfo(int regionId, |
|
|
|
|
const std::set<unsigned int>& 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()); |
|
|
|
|
} |
|
|
|
|
} |