色块比较工具更新
This commit is contained in:
1 parent
ebc1cfdf64
commit
de24080606
3 files changed
+411
-178
No files matched your search
@@ -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,
|
||||
const std::string& filename) {
|
||||
ColorInfo info = {faceId, gaussianColor, originalColor, imageRegion.clone(), distance, threshold, filename};
|
||||
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) {
|
||||
// 存储信息
|
||||
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 {
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
// 遍历这个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
|
||||
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::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0), 1);
|
||||
// 添加三角形标签
|
||||
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
|
||||
|
||||
// 添加距离和阈值
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
// 保存图片
|
||||
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() {
|
||||
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() {
|
||||
|
||||
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() {
|
||||
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() {
|
||||
}
|
||||
|
||||
fclose(summaryFp);
|
||||
printf("✅ 汇总统计信息已保存到: %s\n", summaryPath.c_str());
|
||||
printf("✅ 三角形汇总统计信息已保存到: %s\n", summaryPath.c_str());
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
// 不使用前向声明,直接定义简单的颜色结构
|
||||
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:
|
||||
// 析构函数
|
||||
virtual ~ColorComparisonFace() {}
|
||||
|
||||
// 添加颜色信息(带图像区域)
|
||||
void addColorInfo(int faceId,
|
||||
const MeshColor& gaussianColor,
|
||||
const MeshColor& originColor,
|
||||
const cv::Mat& imageRegion,
|
||||
float distance, float threshold,
|
||||
const std::string& filename);
|
||||
// 添加精确三角形信息(替代原来的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文件
|
||||
|
||||
+319
-100
@@ -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,146 +1732,304 @@ 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
|
||||
}
|
||||
|
||||
// 获取高斯颜色
|
||||
Mesh::Color gaussianColor = faceColorsGaussian[idxFace];
|
||||
MeshColor gaussianMeshColor(gaussianColor.r, gaussianColor.g, gaussianColor.b);
|
||||
|
||||
// 计算颜色距离
|
||||
float colorDistance = computeColorDifferenceHSV(gaussianMeshColor, originalColor);
|
||||
|
||||
float threshold = 0.31f; // 基础阈值
|
||||
bool bFilter = (colorDistance > threshold);
|
||||
|
||||
std::string full_path = imageData.name;
|
||||
size_t slash_pos = full_path.find_last_of("/\\");
|
||||
std::string filename = (slash_pos != std::string::npos)
|
||||
? full_path.substr(slash_pos + 1)
|
||||
: full_path;
|
||||
size_t dot_pos = filename.find_last_of(".");
|
||||
if (dot_pos != std::string::npos) {
|
||||
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");
|
||||
|
||||
// 添加到批处理器
|
||||
if (g_colorComparisonFace) {
|
||||
g_colorComparisonFace->addColorInfo(idxFace,
|
||||
gaussianMeshColor,
|
||||
originalColor,
|
||||
imageRegion,
|
||||
colorDistance, threshold, filename);
|
||||
printf(" ✅ 面 %d 已添加到批处理器\n", idxFace);
|
||||
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;
|
||||
bool bFilter = (colorDistance > threshold);
|
||||
|
||||
std::string full_path = imageData.name;
|
||||
size_t slash_pos = full_path.find_last_of("/\\");
|
||||
std::string filename = (slash_pos != std::string::npos)
|
||||
? full_path.substr(slash_pos + 1)
|
||||
: full_path;
|
||||
size_t dot_pos = filename.find_last_of(".");
|
||||
if (dot_pos != std::string::npos) {
|
||||
filename = filename.substr(0, dot_pos);
|
||||
}
|
||||
|
||||
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) {
|
||||
// 创建可视化图像(转换为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,
|
||||
exactTriangleRegionWithContour, // 传递带轮廓的透明通道图像
|
||||
visualization, // 传递带轮廓的可视化图像
|
||||
colorDistance, threshold, filename);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user