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()
DEBUG_EXTRA(" patch stats: single(patches<2)=%zu, multi(>=2)=%zu, maxPatches=%zu", DEBUG_EXTRA(" patch stats: single(patches<2)=%zu, multi(>=2)=%zu, maxPatches=%zu",
svSingle, svMulti, svMaxPatches); svSingle, svMulti, svMaxPatches);
// ★★★ 截断 seamVertices 到合理规模(原版 OpenMVS 通常 < 50000)★★★ // // ★★★ 截断 seamVertices 到合理规模(原版 OpenMVS 通常 < 50000)★★★
// 按 patches 数量排序,保留最重要的(patches 多的 = 色差严重的接缝) // // 按 patches 数量排序,保留最重要的(patches 多的 = 色差严重的接缝)
const size_t MAX_SEAM_VERTICES = 40000; // ← 可调,先试 40000 // const size_t MAX_SEAM_VERTICES = 40000; // ← 可调,先试 40000
if (seamVertices.GetSize() > MAX_SEAM_VERTICES) { // if (seamVertices.GetSize() > MAX_SEAM_VERTICES) {
DEBUG_EXTRA(" Truncating seamVertices: %u -> %zu (keeping highest patch-count)", // DEBUG_EXTRA(" Truncating seamVertices: %u -> %zu (keeping highest patch-count)",
seamVertices.GetSize(), MAX_SEAM_VERTICES); // seamVertices.GetSize(), MAX_SEAM_VERTICES);
// 建 (索引, patch数量) 对,按 patch 数量降序 // // 建 (索引, patch数量) 对,按 patch 数量降序
std::vector<std::pair<uint32_t, size_t>> idxAndCount(seamVertices.GetSize()); // std::vector<std::pair<uint32_t, size_t>> idxAndCount(seamVertices.GetSize());
for (uint32_t i = 0; i < seamVertices.GetSize(); ++i) // for (uint32_t i = 0; i < seamVertices.GetSize(); ++i)
idxAndCount[i] = {i, seamVertices[i].patches.size()}; // idxAndCount[i] = {i, seamVertices[i].patches.size()};
std::sort(idxAndCount.begin(), idxAndCount.end(), // std::sort(idxAndCount.begin(), idxAndCount.end(),
[](const auto& a, const auto& b) { return a.second > b.second; }); // [](const auto& a, const auto& b) { return a.second > b.second; });
// 选前 MAX_SEAM_VERTICES 个索引,排序回原始顺序以保持稳定性 // // 选前 MAX_SEAM_VERTICES 个索引,排序回原始顺序以保持稳定性
std::vector<uint32_t> keep(idxAndCount.size()); // std::vector<uint32_t> keep(idxAndCount.size());
for (size_t i = 0; i < MAX_SEAM_VERTICES; ++i) keep[i] = idxAndCount[i].first; // for (size_t i = 0; i < MAX_SEAM_VERTICES; ++i) keep[i] = idxAndCount[i].first;
std::sort(keep.begin(), keep.begin() + MAX_SEAM_VERTICES); // std::sort(keep.begin(), keep.begin() + MAX_SEAM_VERTICES);
// 重建 seamVertices(只保留选中的) // // 重建 seamVertices(只保留选中的)
decltype(seamVertices) newSV; // decltype(seamVertices) newSV;
newSV.Reserve(MAX_SEAM_VERTICES); // newSV.Reserve(MAX_SEAM_VERTICES);
std::unordered_map<uint32_t, uint32_t> old2new; // 旧索引 → 新索引 // std::unordered_map<uint32_t, uint32_t> old2new; // 旧索引 → 新索引
for (size_t i = 0; i < MAX_SEAM_VERTICES; ++i) { // for (size_t i = 0; i < MAX_SEAM_VERTICES; ++i) {
const uint32_t oldIdx = keep[i]; // const uint32_t oldIdx = keep[i];
old2new[oldIdx] = (uint32_t)newSV.GetSize(); // old2new[oldIdx] = (uint32_t)newSV.GetSize();
newSV.push_back(std::move(seamVertices[oldIdx])); // newSV.push_back(std::move(seamVertices[oldIdx]));
} // }
// ★★★ 关键:更新所有 Patch::edges 里的 idxSeamVertex 引用 ★★★ // // ★★★ 关键:更新所有 Patch::edges 里的 idxSeamVertex 引用 ★★★
for (uint32_t i = 0; i < newSV.GetSize(); ++i) { // for (uint32_t i = 0; i < newSV.GetSize(); ++i) {
for (auto& patch : newSV[i].patches) { // for (auto& patch : newSV[i].patches) {
for (auto& edge : patch.edges) { // for (auto& edge : patch.edges) {
auto it = old2new.find(edge.idxSeamVertex); // auto it = old2new.find(edge.idxSeamVertex);
if (it != old2new.end()) // if (it != old2new.end())
edge.idxSeamVertex = it->second; // edge.idxSeamVertex = it->second;
else // else
edge.idxSeamVertex = i; // 指向自己(会被忽略) // edge.idxSeamVertex = i; // 指向自己(会被忽略)
} // }
} // }
} // }
seamVertices = std::move(newSV); // seamVertices = std::move(newSV);
DEBUG_EXTRA(" Truncated seamVertices: %u final", seamVertices.GetSize()); // DEBUG_EXTRA(" Truncated seamVertices: %u final", seamVertices.GetSize());
} // }
} }
// Native // Native
@ -9462,8 +9462,9 @@ void MeshTexture::GlobalSeamLeveling4()
const float r = x(v * 3 + 0); const float r = x(v * 3 + 0);
const float g = x(v * 3 + 1); const float g = x(v * 3 + 1);
const float b_ch = x(v * 3 + 2); const float b_ch = x(v * 3 + 2);
const float mean = (r + g + b_ch) / 3.0f; // 去均值 const float mean = (r + g + b_ch) / 3.0f;
colorAdjustments[v] = Color(r - mean, g - mean, b_ch - mean); // colorAdjustments[v] = Color(r, g, b_ch);
colorAdjustments[v] = Color(r - mean, g - mean, b_ch - mean);
} }
} else { } else {
DEBUG_EXTRA("WARN: solve not successful, using zero adjustments"); DEBUG_EXTRA("WARN: solve not successful, using zero adjustments");
@ -9513,22 +9514,28 @@ void MeshTexture::GlobalSeamLeveling4()
if (idxFace >= faces.GetSize()) continue; if (idxFace >= faces.GetSize()) continue;
const Face& face = faces[idxFace]; const Face& face = faces[idxFace];
// ★ 检查 faceTexcoords 访问 ASSERT(idxFace * 3 + 2 < faceTexcoords.GetSize());
ASSERT(idxFace * 3 + 2 < faceTexcoords.GetSize());
// ★ 检查 face[v] 不越界
for (int v = 0; v < 3; ++v) { for (int v = 0; v < 3; ++v) {
ASSERT(face[v] < vertices.size()); ASSERT(face[v] < vertices.size());
ASSERT(face[v] < vertpatch2rows.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) { for (int v = 0; v < 3; ++v) {
ASSERT(face[v] < vertices.size()); // ★ 加这行 ASSERT(face[v] < vertices.size());
auto search = vertpatch2rows[face[v]].find(idxPatch); auto search = vertpatch2rows[face[v]].find(idxPatch);
if (search != vertpatch2rows[face[v]].end()) 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]; data.colors[v] = colorAdjustments[search->second];
} }
else else
@ -9536,8 +9543,7 @@ void MeshTexture::GlobalSeamLeveling4()
} }
ColorMap::RasterizeTriangleBary(data.tri[0], data.tri[1], data.tri[2], data); ColorMap::RasterizeTriangleBary(data.tri[0], data.tri[1], data.tri[2], data);
} }
imageAdj.DilateMean<5>(imageAdj, Color::ZERO);
imageAdj.DilateMean<1>(imageAdj, Color::ZERO);
// ★ 把修正叠加到 outPatch(从 srcROI 读原始颜色) // ★ 把修正叠加到 outPatch(从 srcROI 读原始颜色)
for (int r = 0; r < srcROI.rows; ++r) { for (int r = 0; r < srcROI.rows; ++r) {
@ -15568,6 +15574,14 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches(
(int)(atlas.rows * atlas.step)); (int)(atlas.rows * atlas.step));
DEBUG_EXTRA("expected: %d x %d x 3 = %d bytes", DEBUG_EXTRA("expected: %d x %d x 3 = %d bytes",
textureSize, textureSize, textureSize * textureSize * 3); 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 读)========== // ========== 3. 重光栅化(从已被 GSL4 修正的 images 读)==========
ASSERT(atlas.rows == textureSize && atlas.cols == textureSize); ASSERT(atlas.rows == textureSize && atlas.cols == textureSize);
for (int pi = 0; pi < (int)rcPatches.size(); ++pi) { 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 = srcImg.image(tp.rect).clone();
cv::Mat correctedPatch = correctedPatchImages[rcToTexPatch[pi]].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; if (correctedPatch.empty()) continue;
const RCPatch& rp = rcPatches[pi]; 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)); 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 y = 0; y < patchH; ++y)
{
for (int x = 0; x < patchW; ++x) { for (int x = 0; x < patchW; ++x) {
cv::Vec3b color = remapped.at<cv::Vec3b>(y, x); cv::Vec3b color = remapped.at<cv::Vec3b>(y, x);
if (color[0] < 5 && color[1] < 5 && color[2] < 5) continue; if (color[0] < 5 && color[1] < 5 && color[2] < 5) continue;
@ -15630,8 +15659,15 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches(
pixel[2] = color[2]; pixel[2] = color[2];
} }
} }
}
atlas = localAtlas; 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."); DEBUG_EXTRA("Re-rasterization done.");

Loading…
Cancel
Save