Browse Source

色块比较工具更新

ColorComparison
hesuicong 2 weeks ago
parent
commit
de24080606
  1. 123
      libs/MVS/ColorComparisonFace.cpp
  2. 39
      libs/MVS/ColorComparisonFace.h
  3. 373
      libs/MVS/SceneTexture.cpp

123
libs/MVS/ColorComparisonFace.cpp

@ -66,16 +66,27 @@ ColorComparisonFace::ColorComparisonFace(const std::string& dir) : outputDir(dir @@ -66,16 +66,27 @@ ColorComparisonFace::ColorComparisonFace(const std::string& dir) : outputDir(dir
}
}
// 添加颜色信息(带图像区域)
void ColorComparisonFace::addColorInfo(int faceId,
const MeshColor& gaussianColor,
const MeshColor& originalColor,
const cv::Mat& imageRegion,
float distance, float threshold,
void ColorComparisonFace::addExactTriangleInfo(int faceId,
MeshColor gaussianColor,
MeshColor originalColor,
const cv::Mat& triangleRegionWithAlpha, // 带透明通道
const cv::Mat& visualization, // 可视化图像
float colorDistance,
float threshold,
const std::string& filename) {
ColorInfo info = {faceId, gaussianColor, originalColor, imageRegion.clone(), distance, threshold, filename};
// 存储信息
FaceColorInfo info;
info.faceId = faceId;
info.gaussianColor = gaussianColor;
info.originalColor = originalColor;
info.triangleRegion = triangleRegionWithAlpha.clone(); // 带透明通道
info.visualization = visualization.clone(); // 可视化图像
info.colorDistance = colorDistance;
info.threshold = threshold;
info.filename = filename;
faceViewColorMap[faceId][filename].push_back(info);
printf("addColorInfo faceId=%d", faceId);
printf("addExactTriangleInfo faceId=%d\n", faceId);
}
// 获取总face数
@ -103,20 +114,20 @@ std::vector<int> ColorComparisonFace::getFaceIds() const { @@ -103,20 +114,20 @@ std::vector<int> ColorComparisonFace::getFaceIds() const {
return faceIds;
}
// 创建实际图像区域对比图
// 创建三角形区域对比图
void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFacesPerImage) {
if (faceViewColorMap.empty()) {
printf(" 没有颜色信息可生成\n");
return;
}
printf("正在创建实际图像区域对比图...\n");
printf("正在创建三角形区域对比图...\n");
printf("总face数: %zu\n", faceViewColorMap.size());
printf("总记录数: %d\n", getTotalRecords());
// 块参数
int imageRegionSize = 200; // 图像区域显示大小
int colorBlockSize = 100; // 高斯颜色块大小
int triangleSize = 200; // 三角形区域显示大小
int colorBlockSize = 100; // 颜色块大小
int blockMargin = 20; // 块之间的边距
int infoHeight = 100; // 信息区域高度
@ -143,8 +154,8 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace @@ -143,8 +154,8 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace
int numRows = (numBlocks + numCols - 1) / numCols;
// 计算每个块的宽度和高度
int blockWidth = colorBlockSize + imageRegionSize + blockMargin * 3;
int blockHeight = imageRegionSize + blockMargin + infoHeight;
int blockWidth = colorBlockSize + triangleSize + blockMargin * 3;
int blockHeight = triangleSize + blockMargin + infoHeight;
// 图片总尺寸
int totalWidth = numCols * (blockWidth + blockMargin) + blockMargin;
@ -154,7 +165,7 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace @@ -154,7 +165,7 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace
cv::Mat faceImage(totalHeight, totalWidth, CV_8UC3, cv::Scalar(245, 245, 245));
// 添加标题
std::string title = cv::format("Face %d - Image Region Comparison", faceId);
std::string title = cv::format("Face %d - Triangle Region Comparison", faceId);
cv::putText(faceImage, title,
cv::Point(20, 30),
cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(0, 0, 0), 2);
@ -165,7 +176,7 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace @@ -165,7 +176,7 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace
for (const auto& viewEntry : viewMap) {
totalRecords += viewEntry.second.size();
for (const auto& info : viewEntry.second) {
if (info.distance > info.threshold) needFixCount++;
if (info.colorDistance > info.threshold) needFixCount++;
}
}
@ -182,7 +193,7 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace @@ -182,7 +193,7 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace
// 遍历这个face的所有视图
for (const auto& viewEntry : viewMap) {
const std::string& viewName = viewEntry.first;
const std::vector<ColorInfo>& infos = viewEntry.second;
const std::vector<FaceColorInfo>& infos = viewEntry.second;
for (const auto& info : infos) {
// 计算当前块的位置
@ -214,42 +225,42 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace @@ -214,42 +225,42 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace
cv::Point(gaussianX + 10, gaussianY - 5),
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0), 1);
// 绘制图像区域
int imageX = blockX + blockMargin + colorBlockSize + blockMargin;
int imageY = blockY + blockMargin;
// 绘制三角形区域
int triangleX = blockX + blockMargin + colorBlockSize + blockMargin;
int triangleY = blockY + blockMargin;
if (!info.imageRegion.empty()) {
// 调整图像区域大小
cv::Mat resizedRegion;
cv::resize(info.imageRegion, resizedRegion, cv::Size(imageRegionSize, imageRegionSize));
if (!info.visualization.empty()) {
// 调整三角形区域大小
cv::Mat resizedTriangle;
cv::resize(info.visualization, resizedTriangle, cv::Size(triangleSize, triangleSize));
// 将图像区域绘制到指定位置
resizedRegion.copyTo(faceImage(cv::Rect(imageX, imageY, imageRegionSize, imageRegionSize)));
// 将三角形区域绘制到指定位置(已经是RGB顺序)
resizedTriangle.copyTo(faceImage(cv::Rect(triangleX, triangleY, triangleSize, triangleSize)));
cv::rectangle(faceImage,
cv::Rect(imageX, imageY, imageRegionSize, imageRegionSize),
cv::Rect(triangleX, triangleY, triangleSize, triangleSize),
cv::Scalar(0, 0, 0), 2);
// 添加原始图像标签
cv::putText(faceImage, "ORIGINAL",
cv::Point(imageX + 10, imageY - 5),
// 添加三角形标签
cv::putText(faceImage, "TRIANGLE",
cv::Point(triangleX + 10, triangleY - 5),
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0), 1);
} else {
// 如果没有图像区域,绘制占位符
// 如果没有三角形区域,绘制占位符
cv::rectangle(faceImage,
cv::Rect(imageX, imageY, imageRegionSize, imageRegionSize),
cv::Rect(triangleX, triangleY, triangleSize, triangleSize),
cv::Scalar(200, 200, 200), -1);
cv::rectangle(faceImage,
cv::Rect(imageX, imageY, imageRegionSize, imageRegionSize),
cv::Rect(triangleX, triangleY, triangleSize, triangleSize),
cv::Scalar(150, 150, 150), 2);
cv::putText(faceImage, "NO IMAGE",
cv::Point(imageX + imageRegionSize/2 - 40, imageY + imageRegionSize/2),
cv::putText(faceImage, "NO TRIANGLE",
cv::Point(triangleX + triangleSize/2 - 40, triangleY + triangleSize/2),
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(100, 100, 100), 1);
}
// 绘制信息区域
int infoY = blockY + blockMargin + imageRegionSize;
int infoY = blockY + blockMargin + triangleSize;
cv::rectangle(faceImage,
cv::Rect(blockX, infoY, blockWidth, infoHeight),
cv::Scalar(240, 240, 240), -1);
@ -286,7 +297,7 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace @@ -286,7 +297,7 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace
// 添加距离和阈值
cv::putText(faceImage,
cv::format("Distance: %.4f", info.distance),
cv::format("Distance: %.4f", info.colorDistance),
cv::Point(blockX + 10, infoY + 80),
cv::FONT_HERSHEY_SIMPLEX, 0.35, cv::Scalar(0, 0, 0), 1);
@ -299,8 +310,8 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace @@ -299,8 +310,8 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace
int resultX = blockX + blockWidth - 60;
int resultY = infoY + 25;
std::string resultText = (info.distance > info.threshold) ? "FIX" : "OK";
cv::Scalar resultColor = (info.distance > info.threshold) ? cv::Scalar(0, 0, 255) : cv::Scalar(0, 180, 0);
std::string resultText = (info.colorDistance > info.threshold) ? "FIX" : "OK";
cv::Scalar resultColor = (info.colorDistance > info.threshold) ? cv::Scalar(0, 0, 255) : cv::Scalar(0, 180, 0);
cv::putText(faceImage, resultText,
cv::Point(resultX, resultY),
@ -327,12 +338,12 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace @@ -327,12 +338,12 @@ void ColorComparisonFace::createBatchComparison(int maxBlocksPerRow, int maxFace
}
// 保存图片
std::string outputPath = outputDir + cv::format("face_%d_image_comparison.png", faceId);
std::string outputPath = outputDir + cv::format("face_%d_triangle_comparison.png", faceId);
if (!cv::imwrite(outputPath, faceImage)) {
printf(" 无法保存face %d的图像区域对比图: %s\n", faceId, outputPath.c_str());
printf("❌ 无法保存face %d的三角形对比图: %s\n", faceId, outputPath.c_str());
} else {
printf("✅ face %d图像区域对比图已保存: %s\n", faceId, outputPath.c_str());
printf("✅ face %d三角形对比图已保存: %s\n", faceId, outputPath.c_str());
printf(" 尺寸: %d x %d 像素, 视图数: %zu, 记录数: %d\n",
totalWidth, totalHeight, viewMap.size(), totalRecords);
}
@ -355,11 +366,11 @@ void ColorComparisonFace::saveColorInfoToFile() { @@ -355,11 +366,11 @@ void ColorComparisonFace::saveColorInfoToFile() {
continue;
}
std::string filePath = outputDir + cv::format("face_%d_colors.csv", faceId);
std::string filePath = outputDir + cv::format("face_%d_triangle_colors.csv", faceId);
FILE* fp = fopen(filePath.c_str(), "w");
if (!fp) {
printf("❌ 无法创建文件: %s\n", filePath.c_str());
printf(" 无法创建文件: %s\n", filePath.c_str());
continue;
}
@ -368,26 +379,26 @@ void ColorComparisonFace::saveColorInfoToFile() { @@ -368,26 +379,26 @@ void ColorComparisonFace::saveColorInfoToFile() {
for (const auto& viewEntry : viewMap) {
const std::string& viewName = viewEntry.first;
const std::vector<ColorInfo>& infos = viewEntry.second;
const std::vector<FaceColorInfo>& infos = viewEntry.second;
for (int i = 0; i < (int)infos.size(); i++) {
const ColorInfo& info = infos[i];
bool needsFix = (info.distance > info.threshold);
const FaceColorInfo& info = infos[i];
bool needsFix = (info.colorDistance > info.threshold);
fprintf(fp, "%d,%s,%d,%d,%d,%.4f,%.4f,%s\n",
faceId,
viewName.c_str(),
info.gaussianColor[0], info.gaussianColor[1], info.gaussianColor[2],
info.distance, info.threshold,
info.colorDistance, info.threshold,
needsFix ? "YES" : "NO");
}
}
fclose(fp);
printf("✅ face %d颜色信息已保存到: %s\n", faceId, filePath.c_str());
printf("✅ face %d三角形颜色信息已保存到: %s\n", faceId, filePath.c_str());
}
// 保存汇总统计信息
std::string summaryPath = outputDir + "image_comparison_summary.csv";
std::string summaryPath = outputDir + "triangle_comparison_summary.csv";
FILE* summaryFp = fopen(summaryPath.c_str(), "w");
if (summaryFp) {
@ -404,14 +415,14 @@ void ColorComparisonFace::saveColorInfoToFile() { @@ -404,14 +415,14 @@ void ColorComparisonFace::saveColorInfoToFile() {
float sumDist = 0.0f;
for (const auto& viewEntry : viewMap) {
const std::vector<ColorInfo>& infos = viewEntry.second;
const std::vector<FaceColorInfo>& infos = viewEntry.second;
totalRecords += infos.size();
for (const auto& info : infos) {
if (info.distance > info.threshold) needFixCount++;
minDist = std::min(minDist, info.distance);
maxDist = std::max(maxDist, info.distance);
sumDist += info.distance;
if (info.colorDistance > info.threshold) needFixCount++;
minDist = std::min(minDist, info.colorDistance);
maxDist = std::max(maxDist, info.colorDistance);
sumDist += info.colorDistance;
}
}
@ -430,6 +441,6 @@ void ColorComparisonFace::saveColorInfoToFile() { @@ -430,6 +441,6 @@ void ColorComparisonFace::saveColorInfoToFile() {
}
fclose(summaryFp);
printf("✅ 汇总统计信息已保存到: %s\n", summaryPath.c_str());
printf("三角形汇总统计信息已保存到: %s\n", summaryPath.c_str());
}
}

39
libs/MVS/ColorComparisonFace.h

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
#include <string>
#include <vector>
#include <map>
#include <opencv2/opencv.hpp>
// 不使用前向声明,直接定义简单的颜色结构
struct MeshColor {
@ -24,18 +24,19 @@ struct MeshColor { @@ -24,18 +24,19 @@ struct MeshColor {
class ColorComparisonFace {
private:
struct ColorInfo {
int faceId;
MeshColor gaussianColor;
MeshColor originalColor;
cv::Mat imageRegion; // 存储实际图像区域
float distance;
float threshold;
std::string filename;
struct FaceColorInfo {
int faceId; // 面的ID
MeshColor gaussianColor; // 高斯颜色
MeshColor originalColor; // 原始颜色
cv::Mat triangleRegion; // 带透明通道的三角形区域
cv::Mat visualization; // 三角形可视化图像
float colorDistance; // 颜色距离
float threshold; // 阈值
std::string filename; // 文件名
};
// 使用嵌套map: faceid -> filename -> ColorInfo列表
std::map<int, std::map<std::string, std::vector<ColorInfo>>> faceViewColorMap;
// 使用嵌套map: faceid -> filename -> FaceColorInfo列表
std::map<int, std::map<std::string, std::vector<FaceColorInfo>>> faceViewColorMap;
std::string outputDir;
public:
@ -45,15 +46,17 @@ public: @@ -45,15 +46,17 @@ public:
// 析构函数
virtual ~ColorComparisonFace() {}
// 添加颜色信息(带图像区域)
void addColorInfo(int faceId,
const MeshColor& gaussianColor,
const MeshColor& originColor,
const cv::Mat& imageRegion,
float distance, float threshold,
// 添加精确三角形信息(替代原来的addColorInfo)
void addExactTriangleInfo(int faceId,
MeshColor gaussianColor,
MeshColor originalColor,
const cv::Mat& triangleRegionWithAlpha, // 带透明通道
const cv::Mat& visualization, // 可视化图像
float colorDistance,
float threshold,
const std::string& filename);
// 创建实际图像区域对比图
// 创建三角形区域对比图
void createBatchComparison(int maxBlocksPerRow = 6, int maxFacesPerImage = 20);
// 保存颜色信息到CSV文件

373
libs/MVS/SceneTexture.cpp

@ -924,6 +924,67 @@ public: @@ -924,6 +924,67 @@ public:
return false;
}
// 提取文件名(不带路径和扩展名)
static std::string extractFilename(const std::string& fullpath) {
size_t lastSlash = fullpath.find_last_of("/\\");
if (lastSlash == std::string::npos) lastSlash = 0;
else lastSlash++;
size_t lastDot = fullpath.find_last_of('.');
if (lastDot == std::string::npos) lastDot = fullpath.size();
return fullpath.substr(lastSlash, lastDot - lastSlash);
}
// 绘制三角形区域的可视化
static void drawTriangleRegionVisualization(cv::Mat& image,
const std::vector<cv::Point>& trianglePixels,
const cv::Rect& roi,
const std::vector<cv::Point2f>& triangleProjection) {
// 创建原始图像的副本
cv::Mat visualization = image.clone();
// 绘制三角形像素点
for (const auto& pt : trianglePixels) {
if (pt.x >= 0 && pt.x < image.cols && pt.y >= 0 && pt.y < image.rows) {
cv::circle(visualization, pt, 1, cv::Scalar(0, 0, 255), -1);
}
}
// 绘制三角形轮廓
if (triangleProjection.size() >= 3) {
std::vector<cv::Point> polyPoints(triangleProjection.size());
for (size_t i = 0; i < triangleProjection.size(); ++i) {
polyPoints[i] = cv::Point(
static_cast<int>(std::round(triangleProjection[i].x)),
static_cast<int>(std::round(triangleProjection[i].y))
);
}
// 连接三角形顶点
for (size_t i = 0; i < polyPoints.size(); ++i) {
size_t j = (i + 1) % polyPoints.size();
cv::line(visualization, polyPoints[i], polyPoints[j], cv::Scalar(0, 255, 0), 2);
}
// 在顶点处画圆
for (size_t i = 0; i < polyPoints.size(); ++i) {
cv::circle(visualization, polyPoints[i], 4, cv::Scalar(255, 0, 0), -1);
}
}
// 绘制ROI矩形
cv::rectangle(visualization, roi, cv::Scalar(255, 255, 0), 1);
// 添加文本信息
std::string text = cv::format("Triangle Pixels: %zu", trianglePixels.size());
cv::putText(visualization, text, cv::Point(10, 30),
cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(255, 255, 255), 2);
// 返回可视化结果
image = visualization;
}
//*/
/*
// 采用ITU-R BT.601标准系数,增加数值稳定性处理
@ -1671,121 +1732,110 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr @@ -1671,121 +1732,110 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
if (itView != testFacePixelsByView.end()) {
const auto& facePixelsMap = itView->second;
// 打印视图信息
printf("=== 处理视图 %d: %s ===\n", idxView, strName.c_str());
printf("这个视图有 %zu 个测试面\n", facePixelsMap.size());
// 遍历这个视图中的所有测试面
for (const auto& faceEntry : facePixelsMap) {
FIndex idxFace = faceEntry.first;
const std::vector<cv::Point>& pixels = faceEntry.second;
const std::vector<cv::Point>& trianglePixels = faceEntry.second;
printf(" 处理面 %d: 有 %zu 个像素\n", idxFace, pixels.size());
printf(" 处理面 %d: 有 %zu 个像素(三角形精确区域)\n", idxFace, trianglePixels.size());
// 检查像素是否为空
if (pixels.empty()) {
if (trianglePixels.empty()) {
printf(" 面 %d 没有像素,跳过\n", idxFace);
continue;
}
// 计算面片区域的包围盒
// 方法2:从faceMap中获取三角形的精确像素
// 这些像素已经是三角形在图像上的准确投影
// 计算三角形区域的边界
int minX = INT_MAX, minY = INT_MAX;
int maxX = 0, maxY = 0;
// 打印前几个像素的位置
int printLimit = std::min(3, (int)pixels.size());
for (int i = 0; i < printLimit; ++i) {
printf(" 像素 %d: (%d, %d)\n", i, pixels[i].x, pixels[i].y);
}
if (pixels.size() > 3) {
printf(" 还有 %zu 个像素...\n", pixels.size() - 3);
}
// 计算包围盒
for (const auto& pt : pixels) {
// 计算三角形区域的边界
for (const auto& pt : trianglePixels) {
if (pt.x < minX) minX = pt.x;
if (pt.x > maxX) maxX = pt.x;
if (pt.y < minY) minY = pt.y;
if (pt.y > maxY) maxY = pt.y;
}
printf(" 包围盒: minX=%d, maxX=%d, minY=%d, maxY=%d\n", minX, maxX, minY, maxY);
// 扩展一些边界
int padding = 2;
int imageWidth = static_cast<int>(imageData.width);
int imageHeight = static_cast<int>(imageData.height);
// 扩展前检查边界
minX = std::max(0, minX - padding);
maxX = std::min(imageWidth - 1, maxX + padding);
minY = std::max(0, minY - padding);
maxY = std::min(imageHeight - 1, maxY + padding);
// 确保扩展后 min <= max
if (minX > maxX) {
printf(" 扩展后 minX > maxX,交换\n");
std::swap(minX, maxX);
}
if (minY > maxY) {
printf(" 扩展后 minY > maxY,交换\n");
std::swap(minY, maxY);
}
printf(" 三角形区域边界: (%d,%d) 到 (%d,%d)\n", minX, minY, maxX, maxY);
// 创建精确的三角形掩码
int width = maxX - minX + 1;
int height = maxY - minY + 1;
printf(" 扩展后: 左上(%d,%d) 宽高(%d,%d)\n", minX, minY, width, height);
// 检查尺寸是否有效
if (width <= 0 || height <= 0) {
printf(" 面 %d 无效尺寸,跳过\n", idxFace);
continue;
}
// 检查是否在图像范围内
if (minX < 0 || minX >= imageWidth ||
maxX < 0 || maxX >= imageWidth ||
minY < 0 || minY >= imageHeight ||
maxY < 0 || maxY >= imageHeight) {
printf(" 面 %d 超出图像范围,跳过\n", idxFace);
continue;
// 创建掩码
cv::Mat exactMask = cv::Mat::zeros(height, width, CV_8UC1);
// 填充三角形像素
for (const auto& pt : trianglePixels) {
int x = pt.x - minX;
int y = pt.y - minY;
if (x >= 0 && x < width && y >= 0 && y < height) {
exactMask.at<uchar>(y, x) = 255;
}
}
// 提取图像区域
cv::Rect roi(minX, minY, width, height);
printf(" 提取ROI: x=%d, y=%d, width=%d, height=%d\n",
roi.x, roi.y, roi.width, roi.height);
// 验证ROI
if (roi.x < 0 || roi.y < 0 ||
roi.x + roi.width > imageWidth ||
roi.y + roi.height > imageHeight) {
printf(" 面 %d ROI验证失败,跳过\n", idxFace);
continue;
}
cv::Mat imageRegion = imageData.image(roi).clone();
if (imageRegion.empty()) {
printf(" 面 %d 图像区域为空,跳过\n", idxFace);
continue;
// 创建带透明通道的图像
cv::Mat exactTriangleRegionWithAlpha = cv::Mat::zeros(height, width, CV_8UC4);
// 计算三角形区域的平均颜色
cv::Scalar meanColor(0, 0, 0);
int pixelCount = 0;
// 先计算平均颜色
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
uchar maskVal = exactMask.at<uchar>(y, x);
if (maskVal > 0) {
cv::Vec3b pixel = imageRegion.at<cv::Vec3b>(y, x);
// 注意:OpenCV是BGR顺序
meanColor[0] += pixel[0]; // B
meanColor[1] += pixel[1]; // G
meanColor[2] += pixel[2]; // R
pixelCount++;
// 填充带透明通道的图像
exactTriangleRegionWithAlpha.at<cv::Vec4b>(y, x) =
cv::Vec4b(pixel[0], pixel[1], pixel[2], 255);
} else {
// 在三角形区域外:完全透明
exactTriangleRegionWithAlpha.at<cv::Vec4b>(y, x) =
cv::Vec4b(0, 0, 0, 0);
}
}
}
printf(" 提取图像区域成功: %dx%d\n", imageRegion.cols, imageRegion.rows);
// 计算图像区域的平均颜色
cv::Scalar meanColor = cv::mean(imageRegion);
MeshColor originalColor(meanColor[2], meanColor[1], meanColor[0]); // OpenCV是BGR格式
if (pixelCount > 0) {
meanColor[0] /= pixelCount; // B
meanColor[1] /= pixelCount; // G
meanColor[2] /= pixelCount; // R
}
// 获取高斯颜色
if (idxFace < faceColorsGaussian.size()) {
Mesh::Color gaussianColor = faceColorsGaussian[idxFace];
MeshColor gaussianMeshColor(gaussianColor.r, gaussianColor.g, gaussianColor.b);
// 注意:meanColor是BGR顺序,需要转换为RGB
MeshColor originalColor(meanColor[2], meanColor[1], meanColor[0]);
// 计算颜色距离
float colorDistance = computeColorDifferenceHSV(gaussianMeshColor, originalColor);
float threshold = 0.31f; // 基础阈值
float threshold = 0.31f;
bool bFilter = (colorDistance > threshold);
std::string full_path = imageData.name;
@ -1798,19 +1848,188 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr @@ -1798,19 +1848,188 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
filename = filename.substr(0, dot_pos);
}
printf("Test face(%d) Color: gaussian(%d,%d,%d), image(%s) color(%d,%d,%d), colorDistance(%.4f), threshold(%.4f), filter=%s\n",
idxFace, gaussianColor.r, gaussianColor.g, gaussianColor.b,
filename.c_str(), originalColor.r, originalColor.g, originalColor.b,
colorDistance, threshold, bFilter ? "true" : "false");
printf("三角形颜色信息 - Face %d:\n", idxFace);
printf(" 高斯颜色: R=%d, G=%d, B=%d\n", gaussianColor.r, gaussianColor.g, gaussianColor.b);
printf(" 原始颜色: B=%.0f, G=%.0f, R=%.0f\n", meanColor[0], meanColor[1], meanColor[2]);
printf(" 原始颜色(RGB): R=%.0f, G=%.0f, B=%.0f\n", meanColor[2], meanColor[1], meanColor[0]);
printf(" 像素数量: %d\n", pixelCount);
printf(" 颜色距离: %.4f, 阈值: %.4f, 过滤: %s\n",
colorDistance, threshold, bFilter ? "" : "");
// 添加到批处理器
if (g_colorComparisonFace) {
g_colorComparisonFace->addColorInfo(idxFace,
// 创建可视化图像(转换为RGB用于显示)
cv::Mat visualization = cv::Mat::zeros(height, width, CV_8UC3);
// 创建RGB版本的图像区域用于显示
cv::Mat imageRegionRGB;
cv::cvtColor(imageRegion, imageRegionRGB, cv::COLOR_BGR2RGB);
bool b = false;
if (filename=="106_8")
b = true;
// 将三角形区域绘制到可视化图像上
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
uchar maskVal = exactMask.at<uchar>(y, x);
if (maskVal > 0) {
// 在三角形区域内:使用RGB颜色
cv::Vec3b pixel = imageRegionRGB.at<cv::Vec3b>(y, x);
visualization.at<cv::Vec3b>(y, x) = pixel;
} else {
// 在三角形区域外:使用浅灰色背景
visualization.at<cv::Vec3b>(y, x) = cv::Vec3b(200, 200, 200);
}
}
}
{
// 立即保存visualization用于调试
std::string debugDir = "debug_visualization/";
std::filesystem::create_directories(debugDir);
std::string debugPath = debugDir + "face_" + std::to_string(idxFace) +
"_view" + std::to_string(idxView) + "_" + filename + "_raw_visualization.png";
cv::imwrite(debugPath, visualization);
printf(" ✅ 保存原始visualization: %s\n", debugPath.c_str());
// 同时保存掩码和原始图像用于对比
cv::imwrite(debugDir + "face_" + std::to_string(idxFace) + "_mask.png", exactMask);
cv::imwrite(debugDir + "face_" + std::to_string(idxFace) + "_original.png", imageRegion);
}
// 增强三角形轮廓可见性
cv::Mat visualizationWithContour = visualization.clone();
// 创建三角形轮廓
std::vector<cv::Point> hullPoints;
if (trianglePixels.size() >= 3) {
// 计算凸包以获得三角形轮廓
std::vector<cv::Point> allPoints = trianglePixels;
// 调整坐标到ROI
for (auto& pt : allPoints) {
pt.x -= minX;
pt.y -= minY;
}
// 计算凸包
std::vector<cv::Point> hull;
cv::convexHull(allPoints, hull);
// 绘制三角形轮廓 - 增强版本
if (!hull.empty()) {
// 首先绘制一个粗的蓝色轮廓
std::vector<std::vector<cv::Point>> contours = {hull};
cv::drawContours(visualizationWithContour, contours, 0, cv::Scalar(255, 0, 0), 3);
// 再绘制一个细的白色轮廓,增强对比
cv::drawContours(visualizationWithContour, contours, 0, cv::Scalar(255, 255, 255), 1);
// 标记顶点
for (size_t i = 0; i < hull.size(); i++) {
// 绘制大圆点
cv::circle(visualizationWithContour, hull[i], 6, cv::Scalar(0, 255, 0), -1);
// 添加顶点编号
cv::putText(visualizationWithContour, std::to_string(i),
cv::Point(hull[i].x + 8, hull[i].y - 8),
cv::FONT_HERSHEY_SIMPLEX, 0.7,
cv::Scalar(0, 0, 0), 2);
// 在顶点周围添加白色边框
cv::circle(visualizationWithContour, hull[i], 6, cv::Scalar(255, 255, 255), 1);
}
// 计算三角形中心点
cv::Point center(0, 0);
for (const auto& p : hull) {
center.x += p.x;
center.y += p.y;
}
center.x /= hull.size();
center.y /= hull.size();
// 在中心添加面编号
std::string faceLabel = "Face:" + std::to_string(idxFace);
cv::putText(visualizationWithContour, faceLabel,
cv::Point(center.x - 30, center.y),
cv::FONT_HERSHEY_SIMPLEX, 0.5,
cv::Scalar(0, 0, 0), 2);
// 在三角形周围添加边框
cv::Rect boundingRect = cv::boundingRect(hull);
cv::rectangle(visualizationWithContour, boundingRect, cv::Scalar(0, 0, 255), 2);
}
}
// 创建增强版本的带透明通道的图像,包含轮廓
cv::Mat exactTriangleRegionWithContour = exactTriangleRegionWithAlpha.clone();
// 在透明图像上也绘制轮廓
if (trianglePixels.size() >= 3) {
std::vector<cv::Point> allPoints = trianglePixels;
for (auto& pt : allPoints) {
pt.x -= minX;
pt.y -= minY;
}
std::vector<cv::Point> hull;
cv::convexHull(allPoints, hull);
if (!hull.empty()) {
std::vector<std::vector<cv::Point>> contours = {hull};
// 在BGRA图像上绘制轮廓
cv::drawContours(exactTriangleRegionWithContour, contours, 0,
cv::Scalar(255, 0, 0, 255), 3); // 蓝色轮廓,不透明
}
}
// 修复3:传递带透明通道的三角形区域
g_colorComparisonFace->addExactTriangleInfo(idxFace,
gaussianMeshColor,
originalColor,
imageRegion,
exactTriangleRegionWithContour, // 传递带轮廓的透明通道图像
visualization, // 传递带轮廓的可视化图像
colorDistance, threshold, filename);
printf(" ✅ 面 %d 已添加到批处理器\n", idxFace);
printf(" ✅ 面 %d 已添加到批处理器(增强轮廓可见性)\n", idxFace);
// 调试:保存带透明通道的图像
#ifdef DEBUG_SAVE_TRIANGLES
static int saveCount = 0;
std::string saveDir = "debug_triangles/";
std::filesystem::create_directories(saveDir);
std::string trianglePath = saveDir + "face_" + std::to_string(idxFace) +
"_view" + std::to_string(idxView) + "_" + filename + ".png";
std::string maskPath = saveDir + "face_" + std::to_string(idxFace) +
"_view" + std::to_string(idxView) + "_" + filename + "_mask.png";
std::string visPath = saveDir + "face_" + std::to_string(idxFace) +
"_view" + std::to_string(idxView) + "_" + filename + "_vis.png";
std::string rgbPath = saveDir + "face_" + std::to_string(idxFace) +
"_view" + std::to_string(idxView) + "_" + filename + "_rgb.png";
std::string contourPath = saveDir + "face_" + std::to_string(idxFace) +
"_view" + std::to_string(idxView) + "_" + filename + "_contour.png";
// 保存带透明通道的三角形区域
cv::imwrite(trianglePath, exactTriangleRegionWithContour);
// 保存掩码
cv::imwrite(maskPath, exactMask);
// 保存可视化图像
cv::imwrite(visPath, visualizationWithContour);
// 保存RGB版本的图像区域
cv::imwrite(rgbPath, imageRegionRGB);
printf(" 已保存三角形图像到: %s\n", trianglePath.c_str());
printf(" 已保存掩码到: %s\n", maskPath.c_str());
printf(" 已保存可视化到: %s\n", visPath.c_str());
#endif
}
}
}

Loading…
Cancel
Save