From 93dbc93c728ccf5b188799eef65f3aaf20d5dc7a Mon Sep 17 00:00:00 2001 From: hesuicong Date: Sun, 30 Aug 2026 14:54:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E7=BC=9D=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/MVS/SceneTexture.cpp | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index 99eb2d2..a82a452 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -772,6 +772,9 @@ public: const std::vector& texelPatchID, int textureSize, int featherRadius=3); + void AlignPatchColors(Image8U3& atlas, + const std::vector& texelPatchID, + int textureSize); void GlobalPatchColorAlignment(Image8U3& atlas, int textureSize); void LocalSeamBlending(Image8U3& atlas, int textureSize); std::vector patchAvgColor; // ← 直接声明 vector,不要加括号! @@ -14607,6 +14610,83 @@ void MeshTexture::GlobalPatchColorAlignment(Image8U3& atlas, int textureSize) DEBUG_EXTRA("Global alignment done: %d constraints (%s)", rows, TD_TIMER_GET_FMT().c_str()); } + +// ========== Patch Color Alignment(改进版,不依赖 GlobalPatchColorAlignment)========== +void MeshTexture::AlignPatchColors(Image8U3& atlas, + const std::vector& texelPatchID, + int textureSize) +{ + if (atlas.empty() || texelPatchID.empty()) return; + + // ---------- 一次遍历:记录每个 patch 的"向外边界颜色" ---------- + // 边界像素的定义:它自己和某个邻居属于不同 patch。 + // 对于这条边,颜色贡献到"我的 patch",同时也贡献到"邻居的 patch"。 + struct Acc { cv::Vec3d sum = {0,0,0}; int count = 0; }; + std::map myBorder; // patch -> 自己这侧的边界颜色累加 + std::map neighborBorder; // patch -> 所有邻居边界颜色的累加 + + const int dx4[] = { -1, 1, 0, 0 }; + 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 + + 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++; + } + } + } + + // ---------- 计算增益(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); + 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])); + } + patchGain[pid] = gain; + } + + // ---------- 应用增益 ---------- + 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; + 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]); + } + } +} + // 对每个 texel,如果它的 patchID 和邻居不同,说明是接缝 // 在接缝处做 3x3 或 5x5 的高斯模糊/均值模糊 void MeshTexture::FeatherTextureSeams(Image8U3& texture, @@ -14855,6 +14935,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); // FeatherTextureSeams(atlas, m_texelPatchID, textureSize, 3); return true; }