Browse Source

微调色差

ManualUV
hesuicong 2 weeks ago
parent
commit
dbbcb4d557
  1. 146
      libs/MVS/SceneTexture.cpp

146
libs/MVS/SceneTexture.cpp

@ -8911,50 +8911,50 @@ void MeshTexture::CreateSeamVertices() @@ -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<std::pair<uint32_t, size_t>> 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<uint32_t> 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<uint32_t, uint32_t> 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<std::pair<uint32_t, size_t>> 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<uint32_t> 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<uint32_t, uint32_t> 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() @@ -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() @@ -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) {
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()); // ★ 加这行
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() @@ -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( @@ -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( @@ -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( @@ -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<cv::Vec3b>(y, x);
if (color[0] < 5 && color[1] < 5 && color[2] < 5) continue;
@ -15630,8 +15659,15 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches( @@ -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.");

Loading…
Cancel
Save