diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index b0bb1a0..1cbda9b 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -672,21 +672,6 @@ public: 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 m_viewStats; - cv::Mat m_atlasViewMap; // CV_32SC1: 记录 atlas 每个像素的视图ID - bool m_colorCorrectionReady = false; - - // ===== 替换/添加这些函数声明 ===== - bool ComputeViewColorStatsDuringRasterization(); - void ApplyColorCorrectionToAtlas(Image8U3& atlas); - void FeatherSeams( const std::vector& seams, int textureSize, @@ -14312,16 +14297,6 @@ bool MeshTexture::RasterizeVirtualFaces( Image8U3& atlas = outTextures.back(); 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{}); @@ -14397,10 +14372,14 @@ bool MeshTexture::RasterizeVirtualFaces( cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0)); + // ✅ 拷贝到 atlas(OpenMP critical 区) #pragma omp critical { for (int y = 0; y < patchH; ++y) { for (int x = 0; x < patchW; ++x) { + // 在 RasterizeVirtualFaces 的像素写入循环中 + // ✅ 只保留最核心的逻辑,不做任何衰减 + cv::Vec3b color = patch.at(y, x); if (color[0] == 0 && color[1] == 0 && color[2] == 0) continue; @@ -14418,32 +14397,12 @@ bool MeshTexture::RasterizeVirtualFaces( ? -1.0f : 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) { - atlas(atlasY, atlasX) = Pixel8U{color[2], color[1], color[0]}; + atlas(atlasY, atlasX) = + Pixel8U{color[2], color[1], color[0]}; ts.score = currentScore; 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(atlasY, atlasX) = viewID; - } } } } @@ -14453,201 +14412,37 @@ bool MeshTexture::RasterizeVirtualFaces( m_texelScores.clear(); DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str()); - - // ============================================================ - // ✅ 视图级颜色校正(核心新增) - // ============================================================ - { - 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(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) - // ============================================================ - { + + // ✅ 新增:接缝融合后处理 + if (true) { // 可配置开关 TD_TIMER_START(); - DEBUG_EXTRA("Applying local color blending on seams..."); - - const int blendRadius = 3; - - // 1. 计算接缝 mask(用 m_atlasViewMap) - cv::Mat seamMask = cv::Mat::zeros(textureSize, textureSize, CV_8UC1); - for (int y = 1; y < textureSize - 1; ++y) { - for (int x = 1; x < textureSize - 1; ++x) { - int vid = m_atlasViewMap.at(y, x); - if (vid <= 0) continue; - - int nb[4] = { - m_atlasViewMap.at(y-1, x), - m_atlasViewMap.at(y+1, x), - m_atlasViewMap.at(y, x-1), - m_atlasViewMap.at(y, x+1) - }; - - for (int k = 0; k < 4; ++k) { - if (nb[k] > 0 && nb[k] != vid) { - seamMask.at(y, x) = 255; - break; - } - } - } + + // 1. 检测需要融合的接缝 + std::vector seams; + if (!DetectSeamsForBlending(virtualFaceMap, virtualFaceViews, seams)) { + DEBUG_EXTRA("Seam detection failed"); + return true; // 不影响主流程 } + // // 2. 方向性高斯羽化 + // FeatherSeams(seams, textureSize, atlas); - int seamCount = cv::countNonZero(seamMask); - DEBUG_EXTRA("Detected %d seam pixels", seamCount); - - if (seamCount > 0) { - // 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; + // 2. 对每个接缝进行融合 + for (const SeamInfo& seam : seams) { + const VirtualFaceGeometry& geomA = m_virtualFaceGeometries[seam.faceA]; + const VirtualFaceGeometry& geomB = m_virtualFaceGeometries[seam.faceB]; - // ✅ 关键修复:确保 ny, nx 在有效范围内 - for (int y = blendRadius; y < textureSize - blendRadius; ++y) { - for (int x = blendRadius; x < textureSize - blendRadius; ++x) { - if (seamMask.at(y, x) == 0) continue; - - int vidCenter = m_atlasViewMap.at(y, x); - if (vidCenter <= 0) continue; - - // 使用 cv::Vec3f 进行计算,避免类型混乱 - cv::Vec3f centerColor( - atlas.at(y, x)[2], - atlas.at(y, x)[1], - atlas.at(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(ny, nx); - if (vidNb <= 0 || vidNb == vidCenter) continue; - - float w = 1.0f / (dx*dx + dy*dy + 1.0f); - - cv::Vec3f nbColor( - atlas.at(ny, nx)[2], - atlas.at(ny, nx)[1], - atlas.at(ny, nx)[0] - ); - - mixedColor += w * nbColor; - totalWeight += w; - } - } - - if (totalWeight > 0) { - mixedColor /= (1.0f + totalWeight); - - // ✅ 写回时确保类型正确 - atlas.at(y, x) = cv::Vec3b( - cv::saturate_cast(mixedColor[2]), // B - cv::saturate_cast(mixedColor[1]), // G - cv::saturate_cast(mixedColor[0]) // R - ); - blended++; - } - } + // 提取接缝两侧像素 + std::vector pixelsA, pixelsB; + ExtractSeamPixels(seam, geomA, geomB, textureSize, pixelsA, pixelsB); + + if (!pixelsA.empty() || !pixelsB.empty()) { + // 执行融合 + BlendSeamPixels(seam, pixelsA, pixelsB, geomA, geomB, textureSize, atlas); } - - 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());