From dbbcb4d557e49c6dc5f73546831279cf26cc1f82 Mon Sep 17 00:00:00 2001 From: hesuicong Date: Fri, 11 Sep 2026 10:15:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BE=AE=E8=B0=83=E8=89=B2=E5=B7=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/MVS/SceneTexture.cpp | 146 ++++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 55 deletions(-) diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index 99f80c9..7edbf94 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -8911,50 +8911,50 @@ void MeshTexture::CreateSeamVertices() DEBUG_EXTRA(" patch stats: single(patches<2)=%zu, multi(>=2)=%zu, maxPatches=%zu", svSingle, svMulti, svMaxPatches); - // ★★★ 截断 seamVertices 到合理规模(原版 OpenMVS 通常 < 50000)★★★ - // 按 patches 数量排序,保留最重要的(patches 多的 = 色差严重的接缝) - const size_t MAX_SEAM_VERTICES = 40000; // ← 可调,先试 40000 - if (seamVertices.GetSize() > MAX_SEAM_VERTICES) { - DEBUG_EXTRA(" Truncating seamVertices: %u -> %zu (keeping highest patch-count)", - seamVertices.GetSize(), MAX_SEAM_VERTICES); - - // 建 (索引, patch数量) 对,按 patch 数量降序 - std::vector> idxAndCount(seamVertices.GetSize()); - for (uint32_t i = 0; i < seamVertices.GetSize(); ++i) - idxAndCount[i] = {i, seamVertices[i].patches.size()}; - std::sort(idxAndCount.begin(), idxAndCount.end(), - [](const auto& a, const auto& b) { return a.second > b.second; }); - - // 选前 MAX_SEAM_VERTICES 个索引,排序回原始顺序以保持稳定性 - std::vector keep(idxAndCount.size()); - for (size_t i = 0; i < MAX_SEAM_VERTICES; ++i) keep[i] = idxAndCount[i].first; - std::sort(keep.begin(), keep.begin() + MAX_SEAM_VERTICES); - - // 重建 seamVertices(只保留选中的) - decltype(seamVertices) newSV; - newSV.Reserve(MAX_SEAM_VERTICES); - std::unordered_map old2new; // 旧索引 → 新索引 - for (size_t i = 0; i < MAX_SEAM_VERTICES; ++i) { - const uint32_t oldIdx = keep[i]; - old2new[oldIdx] = (uint32_t)newSV.GetSize(); - newSV.push_back(std::move(seamVertices[oldIdx])); - } - - // ★★★ 关键:更新所有 Patch::edges 里的 idxSeamVertex 引用 ★★★ - for (uint32_t i = 0; i < newSV.GetSize(); ++i) { - for (auto& patch : newSV[i].patches) { - for (auto& edge : patch.edges) { - auto it = old2new.find(edge.idxSeamVertex); - if (it != old2new.end()) - edge.idxSeamVertex = it->second; - else - edge.idxSeamVertex = i; // 指向自己(会被忽略) - } - } - } - seamVertices = std::move(newSV); - DEBUG_EXTRA(" Truncated seamVertices: %u final", seamVertices.GetSize()); - } + // // ★★★ 截断 seamVertices 到合理规模(原版 OpenMVS 通常 < 50000)★★★ + // // 按 patches 数量排序,保留最重要的(patches 多的 = 色差严重的接缝) + // const size_t MAX_SEAM_VERTICES = 40000; // ← 可调,先试 40000 + // if (seamVertices.GetSize() > MAX_SEAM_VERTICES) { + // DEBUG_EXTRA(" Truncating seamVertices: %u -> %zu (keeping highest patch-count)", + // seamVertices.GetSize(), MAX_SEAM_VERTICES); + + // // 建 (索引, patch数量) 对,按 patch 数量降序 + // std::vector> idxAndCount(seamVertices.GetSize()); + // for (uint32_t i = 0; i < seamVertices.GetSize(); ++i) + // idxAndCount[i] = {i, seamVertices[i].patches.size()}; + // std::sort(idxAndCount.begin(), idxAndCount.end(), + // [](const auto& a, const auto& b) { return a.second > b.second; }); + + // // 选前 MAX_SEAM_VERTICES 个索引,排序回原始顺序以保持稳定性 + // std::vector keep(idxAndCount.size()); + // for (size_t i = 0; i < MAX_SEAM_VERTICES; ++i) keep[i] = idxAndCount[i].first; + // std::sort(keep.begin(), keep.begin() + MAX_SEAM_VERTICES); + + // // 重建 seamVertices(只保留选中的) + // decltype(seamVertices) newSV; + // newSV.Reserve(MAX_SEAM_VERTICES); + // std::unordered_map old2new; // 旧索引 → 新索引 + // for (size_t i = 0; i < MAX_SEAM_VERTICES; ++i) { + // const uint32_t oldIdx = keep[i]; + // old2new[oldIdx] = (uint32_t)newSV.GetSize(); + // newSV.push_back(std::move(seamVertices[oldIdx])); + // } + + // // ★★★ 关键:更新所有 Patch::edges 里的 idxSeamVertex 引用 ★★★ + // for (uint32_t i = 0; i < newSV.GetSize(); ++i) { + // for (auto& patch : newSV[i].patches) { + // for (auto& edge : patch.edges) { + // auto it = old2new.find(edge.idxSeamVertex); + // if (it != old2new.end()) + // edge.idxSeamVertex = it->second; + // else + // edge.idxSeamVertex = i; // 指向自己(会被忽略) + // } + // } + // } + // seamVertices = std::move(newSV); + // DEBUG_EXTRA(" Truncated seamVertices: %u final", seamVertices.GetSize()); + // } } // Native @@ -9462,8 +9462,9 @@ void MeshTexture::GlobalSeamLeveling4() const float r = x(v * 3 + 0); const float g = x(v * 3 + 1); const float b_ch = x(v * 3 + 2); - const float mean = (r + g + b_ch) / 3.0f; // 去均值 - colorAdjustments[v] = Color(r - mean, g - mean, b_ch - mean); + const float mean = (r + g + b_ch) / 3.0f; + // colorAdjustments[v] = Color(r, g, b_ch); + colorAdjustments[v] = Color(r - mean, g - mean, b_ch - mean); } } else { DEBUG_EXTRA("WARN: solve not successful, using zero adjustments"); @@ -9513,22 +9514,28 @@ void MeshTexture::GlobalSeamLeveling4() if (idxFace >= faces.GetSize()) continue; const Face& face = faces[idxFace]; - // ★ 检查 faceTexcoords 访问 - ASSERT(idxFace * 3 + 2 < faceTexcoords.GetSize()); - - // ★ 检查 face[v] 不越界 + ASSERT(idxFace * 3 + 2 < faceTexcoords.GetSize()); for (int v = 0; v < 3; ++v) { ASSERT(face[v] < vertices.size()); ASSERT(face[v] < vertpatch2rows.size()); } - data.tri = faceTexcoords.Begin() + idxFace * 3; + // ★ UV [0,1] → patch 局部像素坐标 + const cv::Size patchSize = texturePatch.rect.size(); + TexCoord localTri[3]; + const TexCoord* uvTri = faceTexcoords.Begin() + idxFace * 3; for (int v = 0; v < 3; ++v) { - ASSERT(face[v] < vertices.size()); // ★ 加这行 + localTri[v] = TexCoord(uvTri[v].x * patchSize.width, + uvTri[v].y * patchSize.height); + } + data.tri = localTri; + + for (int v = 0; v < 3; ++v) { + ASSERT(face[v] < vertices.size()); auto search = vertpatch2rows[face[v]].find(idxPatch); if (search != vertpatch2rows[face[v]].end()) { - ASSERT(search->second < (Eigen::Index)colorAdjustments.size()); // ★ 关键 + ASSERT(search->second < (Eigen::Index)colorAdjustments.size()); data.colors[v] = colorAdjustments[search->second]; } else @@ -9536,8 +9543,7 @@ void MeshTexture::GlobalSeamLeveling4() } ColorMap::RasterizeTriangleBary(data.tri[0], data.tri[1], data.tri[2], data); } - - imageAdj.DilateMean<1>(imageAdj, Color::ZERO); + imageAdj.DilateMean<5>(imageAdj, Color::ZERO); // ★ 把修正叠加到 outPatch(从 srcROI 读原始颜色) for (int r = 0; r < srcROI.rows; ++r) { @@ -15568,6 +15574,14 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches( (int)(atlas.rows * atlas.step)); DEBUG_EXTRA("expected: %d x %d x 3 = %d bytes", textureSize, textureSize, textureSize * textureSize * 3); + + for (int i = 0; i < std::min(3, (int)images.size()); ++i) { + char dbgName[256]; + sprintf(dbgName, "debug_image_%d_after_gsl4.png", i); + cv::imwrite(dbgName, images[i].image); // ← 用 .image + } + DEBUG_EXTRA("Exported debug images after GSL4"); + // ========== 3. 重光栅化(从已被 GSL4 修正的 images 读)========== ASSERT(atlas.rows == textureSize && atlas.cols == textureSize); for (int pi = 0; pi < (int)rcPatches.size(); ++pi) { @@ -15583,6 +15597,20 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches( // cv::Mat correctedPatch = srcImg.image(tp.rect).clone(); cv::Mat correctedPatch = correctedPatchImages[rcToTexPatch[pi]].clone(); // 局部拷贝 + // 加上严格检查 + static int cnt = 0; + if (cnt < 5) { + DEBUG_EXTRA("Patch %d: rcToTexPatch=%d, correctedPatch empty=%d, size=(%dx%d), type=%d", + cnt, rcToTexPatch[pi], correctedPatch.empty(), + correctedPatch.cols, correctedPatch.rows, correctedPatch.type()); + + if (!correctedPatch.empty()) { + char nm[256]; sprintf(nm, "debug_corrected_patch_%d.png", cnt); + cv::imwrite(nm, correctedPatch); + } + cnt++; + } + if (correctedPatch.empty()) continue; const RCPatch& rp = rcPatches[pi]; @@ -15616,6 +15644,7 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches( cv::remap(correctedPatch, remapped, mapX, mapY, cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0,0,0)); for (int y = 0; y < patchH; ++y) + { for (int x = 0; x < patchW; ++x) { cv::Vec3b color = remapped.at(y, x); if (color[0] < 5 && color[1] < 5 && color[2] < 5) continue; @@ -15630,8 +15659,15 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches( pixel[2] = color[2]; } } + } atlas = localAtlas; + // // 调试用:导出调整后的 atlas + // static int dbgCount = 0; + // char dbgName[256]; + // sprintf(dbgName, "debug_atlas_after_gsl4_%d.png", dbgCount++); + // cv::imwrite(dbgName, atlas); + // DEBUG_EXTRA("Exported %s", dbgName); } } DEBUG_EXTRA("Re-rasterization done.");