From 32a270b287791304b734c865f3eaafd5b9216560 Mon Sep 17 00:00:00 2001 From: hesuicong Date: Sun, 30 Aug 2026 15:52:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=89=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/MVS/SceneTexture.cpp | 91 ++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index a82a452..1887f4c 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -14613,76 +14613,73 @@ void MeshTexture::GlobalPatchColorAlignment(Image8U3& atlas, int textureSize) // ========== Patch Color Alignment(改进版,不依赖 GlobalPatchColorAlignment)========== void MeshTexture::AlignPatchColors(Image8U3& atlas, - const std::vector& texelPatchID, - int textureSize) + const std::vector& texelPatchID, + int textureSize) { - if (atlas.empty() || texelPatchID.empty()) return; + if (atlas.empty()) return; + const IIndex NP = (IIndex)rcPatches.size(); + if (NP == 0) return; - // ---------- 一次遍历:记录每个 patch 的"向外边界颜色" ---------- - // 边界像素的定义:它自己和某个邻居属于不同 patch。 - // 对于这条边,颜色贡献到"我的 patch",同时也贡献到"邻居的 patch"。 - struct Acc { cv::Vec3d sum = {0,0,0}; int count = 0; }; - std::map myBorder; // patch -> 自己这侧的边界颜色累加 - std::map neighborBorder; // patch -> 所有邻居边界颜色的累加 + // 每个 patch 的边界颜色累加(自己侧 + 邻居侧) + struct Acc { cv::Vec3d self = {0,0,0}, nb = {0,0,0}; int selfCnt = 0, nbCnt = 0; }; + std::vector acc(NP); const int dx4[] = { -1, 1, 0, 0 }; - const int dy4[] = { 0, 0, -1, 1 }; + const int dy4[] = { 0, 0,-1, 1 }; + // 一次遍历:只处理边界像素 for (int y = 1; y < textureSize - 1; ++y) { for (int x = 1; x < textureSize - 1; ++x) { int idx = y * textureSize + x; if (texelPatchID[idx] == NO_ID) continue; - IIndex myPatch = texelPatchID[idx]; - const Pixel8U& myPx = atlas(y, x); - cv::Vec3f myColor(myPx[2], myPx[1], myPx[0]); // BGR -> RGB + IIndex pid = texelPatchID[idx]; + if (pid >= NP) continue; + + const Pixel8U& px = atlas(y, x); + cv::Vec3d color(px[2], px[1], px[0]); for (int d = 0; d < 4; ++d) { int nx = x + dx4[d], ny = y + dy4[d]; int nidx = ny * textureSize + nx; - IIndex nbPatch = texelPatchID[nidx]; - if (nbPatch == NO_ID || nbPatch == myPatch) continue; - - // 这条边存在:两侧都记录 - myBorder[myPatch].sum += cv::Vec3d(myColor); - myBorder[myPatch].count++; - neighborBorder[myPatch].sum += cv::Vec3d(atlas(ny, nx)[2], - atlas(ny, nx)[1], - atlas(ny, nx)[0]); - neighborBorder[myPatch].count++; + if (texelPatchID[nidx] == NO_ID || texelPatchID[nidx] == pid) continue; + + IIndex npid = texelPatchID[nidx]; + if (npid >= NP) continue; + const Pixel8U& npx = atlas(ny, nx); + cv::Vec3d ncolor(npx[2], npx[1], npx[0]); + + acc[pid].self += color; acc[pid].selfCnt++; + acc[npid].nb += color; acc[npid].nbCnt++; } } } - // ---------- 计算增益(O(patch 数),不再扫全图)---------- - std::map patchGain; - for (const auto& entry : myBorder) { - IIndex pid = entry.first; - if (entry.second.count == 0 || neighborBorder[pid].count == 0) continue; - - cv::Vec3d myMean = entry.second.sum / entry.second.count; - cv::Vec3d nbMean = neighborBorder[pid].sum / neighborBorder[pid].count; - - cv::Vec3f gain(1, 1, 1); + // 计算每个 patch 的增益(向邻居对齐) + std::vector gain(NP, cv::Vec3f(1, 1, 1)); + for (IIndex i = 0; i < NP; ++i) { + if (acc[i].selfCnt == 0 || acc[i].nbCnt == 0) continue; + cv::Vec3d selfMean = acc[i].self / acc[i].selfCnt; + cv::Vec3d nbMean = acc[i].nb / acc[i].nbCnt; for (int c = 0; c < 3; ++c) { - if (myMean[c] > 1.0f) - gain[c] = (float)(nbMean[c] / myMean[c]); - gain[c] = std::max(0.5f, std::min(2.0f, gain[c])); + if (selfMean[c] > 1.0f) { + float g = (float)(nbMean[c] / selfMean[c]); + gain[i][c] = std::max(0.7f, std::min(1.4f, g)); // 保守范围 + } } - patchGain[pid] = gain; } - // ---------- 应用增益 ---------- + // 应用增益(整个 patch 统一乘) for (int y = 0; y < textureSize; ++y) { for (int x = 0; x < textureSize; ++x) { int idx = y * textureSize + x; if (texelPatchID[idx] == NO_ID) continue; - auto it = patchGain.find(texelPatchID[idx]); - if (it == patchGain.end()) continue; - const cv::Vec3f& gain = it->second; + IIndex pid = texelPatchID[idx]; + if (pid >= NP) continue; + if (gain[pid] == cv::Vec3f(1,1,1)) continue; Pixel8U& px = atlas(y, x); - px[2] = cv::saturate_cast(px[2] * gain[0]); - px[1] = cv::saturate_cast(px[1] * gain[1]); - px[0] = cv::saturate_cast(px[0] * gain[2]); + px[2] = cv::saturate_cast(px[2] * gain[pid][0]); + px[1] = cv::saturate_cast(px[1] * gain[pid][1]); + px[0] = cv::saturate_cast(px[0] * gain[pid][2]); } } } @@ -14920,6 +14917,10 @@ bool MeshTexture::RasterizeVirtualFaces( DEBUG_EXTRA("Patch avg color computed: %d patches, %d with pixels", NP, NP - std::count(pixelCount.begin(), pixelCount.end(), 0)); + for (int iter = 0; iter < 3; ++iter) { + AlignPatchColors(atlas, m_texelPatchID, textureSize); + } + // 5/6/7. 接缝 BuildSeamEdgesFromRCPatches(); if (!rcSeamEdges.empty()) { @@ -14935,7 +14936,7 @@ bool MeshTexture::RasterizeVirtualFaces( DEBUG_EXTRA("Seam blending completed: %zu edges (%s)", seamEdges.size(), TD_TIMER_GET_FMT().c_str()); } - AlignPatchColors(atlas, m_texelPatchID, textureSize); + // AlignPatchColors(atlas, m_texelPatchID, textureSize); // FeatherTextureSeams(atlas, m_texelPatchID, textureSize, 3); return true; }