Browse Source

回退

ManualUV
hesuicong 9 hours ago
parent
commit
04495f3426
  1. 269
      libs/MVS/SceneTexture.cpp

269
libs/MVS/SceneTexture.cpp

@ -672,21 +672,6 @@ public:
return x + 1; return x + 1;
} }
struct ViewColorStats {
double sumR = 0, sumG = 0, sumB = 0;
int pixelCount = 0;
bool valid = false;
double gainR = 1.0, gainG = 1.0, gainB = 1.0;
};
std::vector<ViewColorStats> m_viewStats;
cv::Mat m_atlasViewMap; // CV_32SC1: 记录 atlas 每个像素的视图ID
bool m_colorCorrectionReady = false;
// ===== 替换/添加这些函数声明 =====
bool ComputeViewColorStatsDuringRasterization();
void ApplyColorCorrectionToAtlas(Image8U3& atlas);
void FeatherSeams( void FeatherSeams(
const std::vector<SeamInfo>& seams, const std::vector<SeamInfo>& seams,
int textureSize, int textureSize,
@ -14312,16 +14297,6 @@ bool MeshTexture::RasterizeVirtualFaces(
Image8U3& atlas = outTextures.back(); Image8U3& atlas = outTextures.back();
atlas.setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r)); atlas.setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r));
// ✅ 初始化视图颜色统计
m_viewStats.resize(images.size());
for (auto& s : m_viewStats) {
s.sumR = s.sumG = s.sumB = 0;
s.pixelCount = 0;
s.valid = false;
s.gainR = s.gainG = s.gainB = 1.0;
}
m_colorCorrectionReady = false;
// ✅ 初始化评分缓冲 // ✅ 初始化评分缓冲
m_texelScores.assign(textureSize * textureSize, TexelScore{}); m_texelScores.assign(textureSize * textureSize, TexelScore{});
@ -14397,10 +14372,14 @@ bool MeshTexture::RasterizeVirtualFaces(
cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::INTER_LINEAR, cv::BORDER_CONSTANT,
cv::Scalar(0, 0, 0)); cv::Scalar(0, 0, 0));
// ✅ 拷贝到 atlas(OpenMP critical 区)
#pragma omp critical #pragma omp critical
{ {
for (int y = 0; y < patchH; ++y) { for (int y = 0; y < patchH; ++y) {
for (int x = 0; x < patchW; ++x) { for (int x = 0; x < patchW; ++x) {
// 在 RasterizeVirtualFaces 的像素写入循环中
// ✅ 只保留最核心的逻辑,不做任何衰减
cv::Vec3b color = patch.at<cv::Vec3b>(y, x); cv::Vec3b color = patch.at<cv::Vec3b>(y, x);
if (color[0] == 0 && color[1] == 0 && color[2] == 0) if (color[0] == 0 && color[1] == 0 && color[2] == 0)
continue; continue;
@ -14418,32 +14397,12 @@ bool MeshTexture::RasterizeVirtualFaces(
? -1.0f ? -1.0f
: virtualFaceViewWeights[i][0]; : virtualFaceViewWeights[i][0];
// ✅ 统计:这个视图贡献了什么颜色(无论是否最终写入) // ✅ 正常写入,不衰减,不修改
if (viewID >= 0 && viewID < (IIndex)m_viewStats.size()) {
ViewColorStats& vs = m_viewStats[viewID];
vs.sumR += color[2]; // OpenMVS 内部是 BGR 顺序
vs.sumG += color[1];
vs.sumB += color[0];
vs.pixelCount++;
}
// ✅ 写入 atlas(评分高的赢)
if (currentScore > ts.score) { if (currentScore > ts.score) {
atlas(atlasY, atlasX) = Pixel8U{color[2], color[1], color[0]}; atlas(atlasY, atlasX) =
Pixel8U{color[2], color[1], color[0]};
ts.score = currentScore; ts.score = currentScore;
ts.viewID = viewID; ts.viewID = viewID;
// ✅ 关键修复:如果 view map 为空,立即创建
if (m_atlasViewMap.empty()) {
DEBUG_EXTRA("Creating m_atlasViewMap on demand: %d x %d", textureSize, textureSize);
m_atlasViewMap = cv::Mat::zeros(textureSize, textureSize, CV_32SC1);
}
// ✅ 再次检查边界(防御性编程)
if (atlasY >= 0 && atlasY < m_atlasViewMap.rows &&
atlasX >= 0 && atlasX < m_atlasViewMap.cols) {
m_atlasViewMap.at<int>(atlasY, atlasX) = viewID;
}
} }
} }
} }
@ -14453,201 +14412,37 @@ bool MeshTexture::RasterizeVirtualFaces(
m_texelScores.clear(); m_texelScores.clear();
DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str()); DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str());
// ============================================================ // ✅ 新增:接缝融合后处理
// ✅ 视图级颜色校正(核心新增) if (true) { // 可配置开关
// ============================================================
{
TD_TIMER_START();
DEBUG_EXTRA("Computing view-level color statistics...");
// ---- 1. 计算每个视图的平均颜色 ----
int totalValidViews = 0;
double globalR = 0, globalG = 0, globalB = 0;
int totalPixels = 0;
for (size_t vid = 0; vid < m_viewStats.size(); ++vid) {
ViewColorStats& vs = m_viewStats[vid];
if (vs.pixelCount > 50) { // 至少50个像素就认为有效
vs.sumR /= vs.pixelCount;
vs.sumG /= vs.pixelCount;
vs.sumB /= vs.pixelCount;
vs.valid = true;
globalR += vs.sumR * vs.pixelCount;
globalG += vs.sumG * vs.pixelCount;
globalB += vs.sumB * vs.pixelCount;
totalPixels += vs.pixelCount;
totalValidViews++;
DEBUG_EXTRA("View %zu: %d pixels, avgRGB=(%.1f,%.1f,%.1f)",
vid, vs.pixelCount, vs.sumR, vs.sumG, vs.sumB);
}
}
if (totalValidViews < 2) {
DEBUG_EXTRA("Only %d valid views, skipping color correction", totalValidViews);
} else {
// ---- 2. 计算全局平均颜色 ----
globalR /= totalPixels;
globalG /= totalPixels;
globalB /= totalPixels;
DEBUG_EXTRA("Global avgRGB=(%.1f,%.1f,%.1f) from %d views, %d pixels",
globalR, globalG, globalB, totalValidViews, totalPixels);
// ---- 3. 计算每个视图的增益 ----
for (auto& vs : m_viewStats) {
if (!vs.valid) continue;
vs.gainR = globalR / (vs.sumR + 1e-6);
vs.gainG = globalG / (vs.sumG + 1e-6);
vs.gainB = globalB / (vs.sumB + 1e-6);
// 限制增益范围,防止极端值
vs.gainR = std::max(0.5, std::min(2.0, vs.gainR));
vs.gainG = std::max(0.5, std::min(2.0, vs.gainG));
vs.gainB = std::max(0.5, std::min(2.0, vs.gainB));
}
m_colorCorrectionReady = true;
// ---- 4. 应用颜色校正到 atlas ----
DEBUG_EXTRA("Applying color correction to atlas...");
for (int y = 0; y < textureSize; ++y) {
for (int x = 0; x < textureSize; ++x) {
cv::Vec3b& p = atlas.at<cv::Vec3b>(y, x);
if (p[0] == 0 && p[1] == 0 && p[2] == 0) continue;
// 我们需要每个像素的视图ID → 用 ts.viewID
// 但 m_texelScores 已经 clear 了
// 所以这里用另一种方式:根据颜色反推增益
// 更简单:重新遍历,用 m_texelScores 之前的值
// → 改为:不 clear m_texelScores,或者另外存一份 viewID map
}
}
DEBUG_EXTRA("Color correction completed: %s", TD_TIMER_GET_FMT().c_str());
}
// 清理
for (auto& s : m_viewStats) {
s.sumR = s.sumG = s.sumB = 0;
s.pixelCount = 0;
}
}
DEBUG_EXTRA("Atlas size: %d x %d", atlas.rows, atlas.cols);
DEBUG_EXTRA("View map size: %d x %d", m_atlasViewMap.rows, m_atlasViewMap.cols);
if (atlas.rows != m_atlasViewMap.rows || atlas.cols != m_atlasViewMap.cols) {
DEBUG_EXTRA("FATAL: Size mismatch!");
return false;
}
// ============================================================
// ✅ 接缝局部颜色混合(Local Color Blending)
// ============================================================
{
TD_TIMER_START(); TD_TIMER_START();
DEBUG_EXTRA("Applying local color blending on seams...");
// 1. 检测需要融合的接缝
const int blendRadius = 3; std::vector<SeamInfo> seams;
if (!DetectSeamsForBlending(virtualFaceMap, virtualFaceViews, seams)) {
// 1. 计算接缝 mask(用 m_atlasViewMap) DEBUG_EXTRA("Seam detection failed");
cv::Mat seamMask = cv::Mat::zeros(textureSize, textureSize, CV_8UC1); return true; // 不影响主流程
for (int y = 1; y < textureSize - 1; ++y) {
for (int x = 1; x < textureSize - 1; ++x) {
int vid = m_atlasViewMap.at<int>(y, x);
if (vid <= 0) continue;
int nb[4] = {
m_atlasViewMap.at<int>(y-1, x),
m_atlasViewMap.at<int>(y+1, x),
m_atlasViewMap.at<int>(y, x-1),
m_atlasViewMap.at<int>(y, x+1)
};
for (int k = 0; k < 4; ++k) {
if (nb[k] > 0 && nb[k] != vid) {
seamMask.at<uchar>(y, x) = 255;
break;
}
}
}
} }
// // 2. 方向性高斯羽化
// FeatherSeams(seams, textureSize, atlas);
int seamCount = cv::countNonZero(seamMask); // 2. 对每个接缝进行融合
DEBUG_EXTRA("Detected %d seam pixels", seamCount); for (const SeamInfo& seam : seams) {
const VirtualFaceGeometry& geomA = m_virtualFaceGeometries[seam.faceA];
if (seamCount > 0) { const VirtualFaceGeometry& geomB = m_virtualFaceGeometries[seam.faceB];
// 2. 膨胀形成过渡带
cv::Mat kernel = cv::getStructuringElement(
cv::MORPH_ELLIPSE, cv::Size(blendRadius * 2 + 1, blendRadius * 2 + 1));
cv::dilate(seamMask, seamMask, kernel);
// 3. 对每条接缝做邻域混合
int blended = 0;
// ✅ 关键修复:确保 ny, nx 在有效范围内 // 提取接缝两侧像素
for (int y = blendRadius; y < textureSize - blendRadius; ++y) { std::vector<Point2i> pixelsA, pixelsB;
for (int x = blendRadius; x < textureSize - blendRadius; ++x) { ExtractSeamPixels(seam, geomA, geomB, textureSize, pixelsA, pixelsB);
if (seamMask.at<uchar>(y, x) == 0) continue;
if (!pixelsA.empty() || !pixelsB.empty()) {
int vidCenter = m_atlasViewMap.at<int>(y, x); // 执行融合
if (vidCenter <= 0) continue; BlendSeamPixels(seam, pixelsA, pixelsB, geomA, geomB, textureSize, atlas);
// 使用 cv::Vec3f 进行计算,避免类型混乱
cv::Vec3f centerColor(
atlas.at<cv::Vec3b>(y, x)[2],
atlas.at<cv::Vec3b>(y, x)[1],
atlas.at<cv::Vec3b>(y, x)[0]
);
cv::Vec3f mixedColor = centerColor;
float totalWeight = 0;
// ✅ 关键修复:添加严格的边界检查
for (int dy = -blendRadius; dy <= blendRadius; ++dy) {
int ny = y + dy;
if (ny < 0 || ny >= textureSize) continue; // ✅ 边界检查
for (int dx = -blendRadius; dx <= blendRadius; ++dx) {
if (dx == 0 && dy == 0) continue;
int nx = x + dx;
if (nx < 0 || nx >= textureSize) continue; // ✅ 边界检查
int vidNb = m_atlasViewMap.at<int>(ny, nx);
if (vidNb <= 0 || vidNb == vidCenter) continue;
float w = 1.0f / (dx*dx + dy*dy + 1.0f);
cv::Vec3f nbColor(
atlas.at<cv::Vec3b>(ny, nx)[2],
atlas.at<cv::Vec3b>(ny, nx)[1],
atlas.at<cv::Vec3b>(ny, nx)[0]
);
mixedColor += w * nbColor;
totalWeight += w;
}
}
if (totalWeight > 0) {
mixedColor /= (1.0f + totalWeight);
// ✅ 写回时确保类型正确
atlas.at<cv::Vec3b>(y, x) = cv::Vec3b(
cv::saturate_cast<uchar>(mixedColor[2]), // B
cv::saturate_cast<uchar>(mixedColor[1]), // G
cv::saturate_cast<uchar>(mixedColor[0]) // R
);
blended++;
}
}
} }
DEBUG_EXTRA("Local color blending applied to %d seam pixels (%s)",
blended, TD_TIMER_GET_FMT().c_str());
} }
DEBUG_EXTRA("Seam blending completed: %zu seams processed (%s)",
seams.size(), TD_TIMER_GET_FMT().c_str());
} }
DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str()); DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str());

Loading…
Cancel
Save