最新优化结果
This commit is contained in:
1 parent
974095dafa
commit
e555b9c804
1 file changed
+120
-152
+120
-152
@@ -9213,8 +9213,6 @@ void MeshTexture::GlobalSeamLeveling4()
|
|||||||
i, components[i], texturePatches.size());
|
i, components[i], texturePatches.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUG_EXTRA("Input validation done. seamVertices=%zu, faces=%u, vertices=%zu",
|
|
||||||
seamVertices.GetSize(), faces.GetSize(), vertices.size());
|
|
||||||
|
|
||||||
// ========== 标记无效顶点 ==========
|
// ========== 标记无效顶点 ==========
|
||||||
BoolArr vertexInvalid(vertices.size());
|
BoolArr vertexInvalid(vertices.size());
|
||||||
@@ -9234,7 +9232,7 @@ void MeshTexture::GlobalSeamLeveling4()
|
|||||||
if (components[f] == NO_ID) {
|
if (components[f] == NO_ID) {
|
||||||
const Face& face = faces[f];
|
const Face& face = faces[f];
|
||||||
for (int v = 0; v < 3; ++v)
|
for (int v = 0; v < 3; ++v)
|
||||||
patchIndices[face[v]].idxPatch = numPatches; // dummy,后面跳过
|
patchIndices[face[v]].idxPatch = numPatches;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint32_t idxPatch(mapIdxPatch[components[f]]);
|
const uint32_t idxPatch(mapIdxPatch[components[f]]);
|
||||||
@@ -9246,13 +9244,13 @@ void MeshTexture::GlobalSeamLeveling4()
|
|||||||
FOREACH(i, seamVertices) {
|
FOREACH(i, seamVertices) {
|
||||||
const SeamVertex& seamVertex = seamVertices[i];
|
const SeamVertex& seamVertex = seamVertices[i];
|
||||||
ASSERT(!seamVertex.patches.empty());
|
ASSERT(!seamVertex.patches.empty());
|
||||||
ASSERT(seamVertex.idxVertex < vertices.size());
|
ASSERT(seamVertex.idxVertex < vertices.size());
|
||||||
PatchIndex& patchIndex = patchIndices[seamVertex.idxVertex];
|
PatchIndex& patchIndex = patchIndices[seamVertex.idxVertex];
|
||||||
patchIndex.bIndex = true;
|
patchIndex.bIndex = true;
|
||||||
patchIndex.idxSeamVertex = i;
|
patchIndex.idxSeamVertex = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 构建 vertpatch2rows(块列号 → 连续行)==========
|
// ========== 构建 vertpatch2rows ==========
|
||||||
ASSERT(vertices.size() < static_cast<VIndex>(std::numeric_limits<MatIdx>::max()));
|
ASSERT(vertices.size() < static_cast<VIndex>(std::numeric_limits<MatIdx>::max()));
|
||||||
MatIdx rowsX(0);
|
MatIdx rowsX(0);
|
||||||
typedef std::unordered_map<uint32_t, MatIdx> VertexPatch2RowMap;
|
typedef std::unordered_map<uint32_t, MatIdx> VertexPatch2RowMap;
|
||||||
@@ -9268,18 +9266,18 @@ void MeshTexture::GlobalSeamLeveling4()
|
|||||||
ASSERT(patch.idxPatch != numPatches);
|
ASSERT(patch.idxPatch != numPatches);
|
||||||
ASSERT(patch.idxPatch < numPatches);
|
ASSERT(patch.idxPatch < numPatches);
|
||||||
if (vertpatch2row.find(patch.idxPatch) != vertpatch2row.end())
|
if (vertpatch2row.find(patch.idxPatch) != vertpatch2row.end())
|
||||||
continue; // 去重
|
continue;
|
||||||
vertpatch2row[patch.idxPatch] = rowsX++;
|
vertpatch2row[patch.idxPatch] = rowsX++;
|
||||||
}
|
}
|
||||||
} else if (patchIndex.idxPatch < numPatches) {
|
} else if (patchIndex.idxPatch < numPatches) {
|
||||||
vertpatch2row[patchIndex.idxPatch] = rowsX++;
|
vertpatch2row[patchIndex.idxPatch] = rowsX++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const Eigen::Index scalarCols = (Eigen::Index)rowsX * 3; // 每块 3 个标量列 (RGB)
|
const Eigen::Index scalarCols = (Eigen::Index)rowsX * 3;
|
||||||
DEBUG_EXTRA("vertpatch2rows built: rowsX(blocks)=%u, scalarCols=%lld", rowsX, (long long)scalarCols);
|
DEBUG_EXTRA("vertpatch2rows built: rowsX=%u, scalarCols=%lld", rowsX, (long long)scalarCols);
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// ========== 构建 Gamma(Tikhonov 正则)========== [修复1: 去重]
|
// ========== 构建 Gamma(Tikhonov 正则)==========
|
||||||
// ============================================================
|
// ============================================================
|
||||||
std::vector<GSLTriplet> gammaTriplets;
|
std::vector<GSLTriplet> gammaTriplets;
|
||||||
gammaTriplets.reserve((size_t)vertices.size() * 8);
|
gammaTriplets.reserve((size_t)vertices.size() * 8);
|
||||||
@@ -9293,7 +9291,7 @@ void MeshTexture::GlobalSeamLeveling4()
|
|||||||
adjVerts.Empty();
|
adjVerts.Empty();
|
||||||
scene.mesh.GetAdjVertices(v, adjVerts);
|
scene.mesh.GetAdjVertices(v, adjVerts);
|
||||||
|
|
||||||
const size_t MAX_ADJ = 8; // ★ 限制邻接度数,控制规模
|
const size_t MAX_ADJ = 8;
|
||||||
if (adjVerts.GetSize() > MAX_ADJ) adjVerts.Resize(MAX_ADJ);
|
if (adjVerts.GetSize() > MAX_ADJ) adjVerts.Resize(MAX_ADJ);
|
||||||
|
|
||||||
VertexPatchIterator itV(patchIndices[v], seamVertices);
|
VertexPatchIterator itV(patchIndices[v], seamVertices);
|
||||||
@@ -9305,11 +9303,11 @@ void MeshTexture::GlobalSeamLeveling4()
|
|||||||
const Eigen::Index colA = it_row->second;
|
const Eigen::Index colA = it_row->second;
|
||||||
|
|
||||||
for (const VIndex vAdj : adjVerts) {
|
for (const VIndex vAdj : adjVerts) {
|
||||||
if (v >= vAdj) continue; // ★ 无向边只处理一次(去重关键)
|
if (v >= vAdj) continue;
|
||||||
VertexPatchIterator itVAdj(patchIndices[vAdj], seamVertices);
|
VertexPatchIterator itVAdj(patchIndices[vAdj], seamVertices);
|
||||||
while (itVAdj.Next()) {
|
while (itVAdj.Next()) {
|
||||||
const uint32_t idxPatchAdj(itVAdj);
|
const uint32_t idxPatchAdj(itVAdj);
|
||||||
if (idxPatch != idxPatchAdj) continue; // 同一 patch 才正则化
|
if (idxPatch != idxPatchAdj) continue;
|
||||||
auto it_rowAdj = vertpatch2rows[vAdj].find(idxPatchAdj);
|
auto it_rowAdj = vertpatch2rows[vAdj].find(idxPatchAdj);
|
||||||
if (it_rowAdj == vertpatch2rows[vAdj].end()) continue;
|
if (it_rowAdj == vertpatch2rows[vAdj].end()) continue;
|
||||||
const Eigen::Index colB = it_rowAdj->second;
|
const Eigen::Index colB = it_rowAdj->second;
|
||||||
@@ -9321,7 +9319,6 @@ void MeshTexture::GlobalSeamLeveling4()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ★ 排序 + 去重合并(消除重复邻接 → 保证矩阵性质良好)
|
|
||||||
std::sort(rawGamma.begin(), rawGamma.end(),
|
std::sort(rawGamma.begin(), rawGamma.end(),
|
||||||
[](const GammaRaw& a, const GammaRaw& b) {
|
[](const GammaRaw& a, const GammaRaw& b) {
|
||||||
return a.colA < b.colA || (a.colA == b.colA && a.colB < b.colB);
|
return a.colA < b.colA || (a.colA == b.colA && a.colB < b.colB);
|
||||||
@@ -9339,16 +9336,12 @@ void MeshTexture::GlobalSeamLeveling4()
|
|||||||
i = j;
|
i = j;
|
||||||
}
|
}
|
||||||
const Eigen::Index rowsGamma = rowG;
|
const Eigen::Index rowsGamma = rowG;
|
||||||
DEBUG_EXTRA("Gamma after dedup: triplets=%zu, rowsGamma=%lld, scalarCols=%lld",
|
|
||||||
gammaTriplets.size(), (long long)rowsGamma, (long long)scalarCols);
|
|
||||||
|
|
||||||
SparseMat Gamma(rowsGamma, scalarCols);
|
SparseMat Gamma(rowsGamma, scalarCols);
|
||||||
Gamma.setFromTriplets(gammaTriplets.begin(), gammaTriplets.end());
|
Gamma.setFromTriplets(gammaTriplets.begin(), gammaTriplets.end());
|
||||||
Gamma.makeCompressed();
|
Gamma.makeCompressed();
|
||||||
gammaTriplets.clear(); gammaTriplets.shrink_to_fit();
|
gammaTriplets.clear(); gammaTriplets.shrink_to_fit();
|
||||||
rawGamma.clear(); rawGamma.shrink_to_fit();
|
rawGamma.clear(); rawGamma.shrink_to_fit();
|
||||||
DEBUG_EXTRA("Gamma built: %lld x %lld, nnz=%lld", (long long)Gamma.rows(),
|
|
||||||
(long long)Gamma.cols(), (long long)Gamma.nonZeros());
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// ========== 构建矩阵 A 和 b(颜色一致性约束)==========
|
// ========== 构建矩阵 A 和 b(颜色一致性约束)==========
|
||||||
@@ -9373,13 +9366,26 @@ void MeshTexture::GlobalSeamLeveling4()
|
|||||||
const TexturePatch& tpRef = texturePatches[patch0.idxPatch];
|
const TexturePatch& tpRef = texturePatches[patch0.idxPatch];
|
||||||
if (tpRef.label < 0 || tpRef.label >= (IIndex)images.size()) continue;
|
if (tpRef.label < 0 || tpRef.label >= (IIndex)images.size()) continue;
|
||||||
|
|
||||||
|
// ★FIX: 检查 patch0.proj 是否为 NaN/Inf(崩溃根源)
|
||||||
|
if (std::isnan(patch0.proj.x) || std::isnan(patch0.proj.y) ||
|
||||||
|
std::isinf(patch0.proj.x) || std::isinf(patch0.proj.y)) {
|
||||||
|
vertexColors[i] = Color::ZERO;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
SampleImage sampler(images[tpRef.label].image);
|
SampleImage sampler(images[tpRef.label].image);
|
||||||
for (const SeamVertex::Patch::Edge& edge : patch0.edges) {
|
for (const SeamVertex::Patch::Edge& edge : patch0.edges) {
|
||||||
if (edge.idxSeamVertex >= seamVertices.GetSize()) continue; // 越界保护
|
if (edge.idxSeamVertex >= seamVertices.GetSize()) continue;
|
||||||
const SeamVertex& seamVertex1 = seamVertices[edge.idxSeamVertex];
|
const SeamVertex& seamVertex1 = seamVertices[edge.idxSeamVertex];
|
||||||
const auto idxPatch1 = seamVertex1.patches.Find(patch0.idxPatch);
|
const auto idxPatch1 = seamVertex1.patches.Find(patch0.idxPatch);
|
||||||
if (idxPatch1 == SeamVertex::Patches::NO_INDEX) continue;
|
if (idxPatch1 == SeamVertex::Patches::NO_INDEX) continue;
|
||||||
const SeamVertex::Patch& patch1 = seamVertex1.patches[idxPatch1];
|
const SeamVertex::Patch& patch1 = seamVertex1.patches[idxPatch1];
|
||||||
|
|
||||||
|
// ★FIX: 检查 patch1.proj 是否为 NaN/Inf,防止 AddEdge 崩溃
|
||||||
|
if (std::isnan(patch1.proj.x) || std::isnan(patch1.proj.y) ||
|
||||||
|
std::isinf(patch1.proj.x) || std::isinf(patch1.proj.y))
|
||||||
|
continue;
|
||||||
|
|
||||||
sampler.AddEdge(patch0.proj, patch1.proj);
|
sampler.AddEdge(patch0.proj, patch1.proj);
|
||||||
}
|
}
|
||||||
vertexColors[i] = sampler.GetColor();
|
vertexColors[i] = sampler.GetColor();
|
||||||
@@ -9398,185 +9404,147 @@ void MeshTexture::GlobalSeamLeveling4()
|
|||||||
const Color& ca = vertexColors[i];
|
const Color& ca = vertexColors[i];
|
||||||
const Color& cb = vertexColors[j];
|
const Color& cb = vertexColors[j];
|
||||||
for (int c = 0; c < 3; ++c) {
|
for (int c = 0; c < 3; ++c) {
|
||||||
const Eigen::Index colA = baseA * 3 + c; // ★ 标量列 = base*3 + c
|
const Eigen::Index colA = baseA * 3 + c;
|
||||||
const Eigen::Index colB = baseB * 3 + c;
|
const Eigen::Index colB = baseB * 3 + c;
|
||||||
ATriplets.emplace_back(rowA, colA, 1.0f);
|
ATriplets.emplace_back(rowA, colA, 1.0f);
|
||||||
ATriplets.emplace_back(rowA, colB, -1.0f);
|
ATriplets.emplace_back(rowA, colB, -1.0f);
|
||||||
if ((size_t)rowA >= b_coeff.size()) b_coeff.push_back(0);
|
if ((size_t)rowA >= b_coeff.size()) b_coeff.push_back(0);
|
||||||
b_coeff[rowA] = cb[c] - ca[c]; // 差值方程
|
b_coeff[rowA] = cb[c] - ca[c];
|
||||||
++rowA;
|
++rowA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const Eigen::Index rowsA = rowA;
|
const Eigen::Index rowsA = rowA;
|
||||||
ASSERT(rowsA <= (Eigen::Index)b_coeff.size());
|
|
||||||
SparseMat A(rowsA, scalarCols);
|
SparseMat A(rowsA, scalarCols);
|
||||||
A.setFromTriplets(ATriplets.begin(), ATriplets.end());
|
A.setFromTriplets(ATriplets.begin(), ATriplets.end());
|
||||||
A.makeCompressed();
|
A.makeCompressed();
|
||||||
ATriplets.clear(); ATriplets.shrink_to_fit();
|
ATriplets.clear(); ATriplets.shrink_to_fit();
|
||||||
DEBUG_EXTRA("Matrix A built: %lld constraints, scalarCols=%lld, nnz=%lld",
|
|
||||||
(long long)rowsA, (long long)scalarCols, (long long)A.nonZeros());
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// ========== 求解:Lhs = AᵀA + λ²ΓᵀΓ,对角扰动保证正定 [修复2]
|
// ========== 求解 ==========
|
||||||
// ============================================================
|
// ============================================================
|
||||||
std::vector<Color> colorAdjustments;
|
std::vector<Color> colorAdjustments;
|
||||||
colorAdjustments.assign(rowsX, Color::ZERO);
|
colorAdjustments.assign(rowsX, Color::ZERO);
|
||||||
|
|
||||||
if (rowsA > 0 && rowsX > 0) {
|
if (rowsA > 0 && rowsX > 0) {
|
||||||
// ★ Lhs = AᵀA + λ² ΓᵀΓ
|
|
||||||
SparseMat ATA = A.transpose() * A;
|
SparseMat ATA = A.transpose() * A;
|
||||||
SparseMat GTG = Gamma.transpose() * Gamma;
|
SparseMat GTG = Gamma.transpose() * Gamma;
|
||||||
const float lambda = 0.5f; // ★ 正则化强度(可调)
|
const float lambda = 0.1f;
|
||||||
GTG *= lambda * lambda;
|
GTG *= lambda * lambda;
|
||||||
ASSERT(ATA.rows() == GTG.rows() && ATA.cols() == GTG.cols()); // 尺寸一致性检查
|
|
||||||
ATA += GTG;
|
ATA += GTG;
|
||||||
SparseMat& Lhs = ATA;
|
SparseMat& Lhs = ATA;
|
||||||
|
|
||||||
// ★★★ 对角加扰动,严格保证正定 ★★★
|
const float eps = 1e-3f;
|
||||||
const float eps = 1e-3f; // 足够小不影响结果,保证正定
|
|
||||||
for (Eigen::Index i = 0; i < (Eigen::Index)Lhs.rows(); ++i) {
|
for (Eigen::Index i = 0; i < (Eigen::Index)Lhs.rows(); ++i) {
|
||||||
Lhs.coeffRef(i, i) += eps;
|
Lhs.coeffRef(i, i) += eps;
|
||||||
}
|
}
|
||||||
DEBUG_EXTRA("Lhs built: %lld x %lld, nnz=%lld (diag += %g)",
|
|
||||||
(long long)Lhs.rows(), (long long)Lhs.cols(),
|
|
||||||
(long long)Lhs.nonZeros(), eps);
|
|
||||||
|
|
||||||
// ★ 用 ConjugateGradient(只需对称,不要求严格 SPD)
|
|
||||||
Eigen::ConjugateGradient<SparseMat, Eigen::Lower> solver;
|
Eigen::ConjugateGradient<SparseMat, Eigen::Lower> solver;
|
||||||
solver.setMaxIterations(2000);
|
solver.setMaxIterations(2000);
|
||||||
solver.setTolerance(0.001f);
|
solver.setTolerance(0.001f);
|
||||||
solver.compute(Lhs);
|
solver.compute(Lhs);
|
||||||
if (solver.info() != Eigen::Success) {
|
if (solver.info() == Eigen::Success) {
|
||||||
DEBUG_EXTRA("WARN: Lhs compute failed (info=%d), skipping solve", (int)solver.info());
|
|
||||||
} else {
|
|
||||||
// ★ b 与通道无关 → 一次求解,结果按 InnerStride<3> 分通道
|
|
||||||
Eigen::VectorXf b(rowsA);
|
Eigen::VectorXf b(rowsA);
|
||||||
for (Eigen::Index k = 0; k < rowsA; ++k) b(k) = b_coeff[k];
|
for (Eigen::Index k = 0; k < rowsA; ++k) b(k) = b_coeff[k];
|
||||||
const Eigen::VectorXf rhs = A.transpose() * b;
|
const Eigen::VectorXf rhs = A.transpose() * b;
|
||||||
const Eigen::VectorXf x = solver.solve(rhs);
|
const Eigen::VectorXf x = solver.solve(rhs);
|
||||||
DEBUG_EXTRA("solve: %d iterations, residual=%g", solver.iterations(), solver.error());
|
|
||||||
|
|
||||||
// ★ 从 x 提取 colorAdjustments(每块一个 Color,显式循环避免对齐问题)
|
if (solver.info() == Eigen::Success && (Eigen::Index)(x.size()) >= scalarCols) {
|
||||||
if (solver.info() == Eigen::Success && (Eigen::Index)(x.size()) >= scalarCols) {
|
colorAdjustments.assign(rowsX, Color::ZERO);
|
||||||
colorAdjustments.assign(rowsX, Color::ZERO);
|
for (Eigen::Index v = 0; v < (Eigen::Index)rowsX; ++v) {
|
||||||
for (Eigen::Index v = 0; v < (Eigen::Index)rowsX; ++v) {
|
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, g, b_ch);
|
colorAdjustments[v] = Color(r - mean, g - mean, b_ch - mean);
|
||||||
colorAdjustments[v] = Color(r - mean, g - mean, b_ch - mean);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b_coeff.clear(); b_coeff.shrink_to_fit();
|
||||||
|
|
||||||
|
// ========== 应用颜色修正 ==========
|
||||||
|
correctedPatchImages.resize(numPatches);
|
||||||
|
|
||||||
|
#ifdef TEXOPT_USE_OPENMP
|
||||||
|
#pragma omp parallel for schedule(dynamic)
|
||||||
|
#endif
|
||||||
|
for (int i = 0; i < (int)numPatches; ++i) {
|
||||||
|
const uint32_t idxPatch = (uint32_t)i;
|
||||||
|
const TexturePatch& texturePatch = texturePatches[idxPatch];
|
||||||
|
|
||||||
|
if (texturePatch.label < 0 || texturePatch.label >= (int)images.size()) continue;
|
||||||
|
if (texturePatch.rect.width <= 0 || texturePatch.rect.height <= 0) continue;
|
||||||
|
|
||||||
|
const cv::Mat& srcROI = images[texturePatch.label].image(texturePatch.rect);
|
||||||
|
if (srcROI.empty()) continue;
|
||||||
|
|
||||||
|
cv::Mat& outPatch = correctedPatchImages[idxPatch];
|
||||||
|
outPatch = cv::Mat::zeros(texturePatch.rect.size(), CV_8UC3);
|
||||||
|
|
||||||
|
ColorMap imageAdj(texturePatch.rect.size());
|
||||||
|
imageAdj.memset(0);
|
||||||
|
|
||||||
|
struct RasterPatch {
|
||||||
|
const TexCoord* tri;
|
||||||
|
Color colors[3];
|
||||||
|
ColorMap& image;
|
||||||
|
RasterPatch(ColorMap& _image) : image(_image) {}
|
||||||
|
inline cv::Size Size() const { return image.size(); }
|
||||||
|
void operator()(const ImageRef& pt, const Point3f& bary) {
|
||||||
|
Color c = colors[0]*bary.x + colors[1]*bary.y + colors[2]*bary.z;
|
||||||
|
// ★ 过滤 NaN/Inf 调整值
|
||||||
|
if (std::isnan(c[0]) || std::isnan(c[1]) || std::isnan(c[2]) ||
|
||||||
|
std::isinf(c[0]) || std::isinf(c[1]) || std::isinf(c[2])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
image(pt) = c;
|
||||||
|
}
|
||||||
|
} data(imageAdj);
|
||||||
|
|
||||||
|
for (const FIndex idxFace : texturePatch.faces) {
|
||||||
|
if (idxFace >= faces.GetSize()) continue;
|
||||||
|
const Face& face = faces[idxFace];
|
||||||
|
data.tri = faceTexcoords.Begin() + idxFace * 3;
|
||||||
|
|
||||||
|
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());
|
||||||
|
data.colors[v] = colorAdjustments[search->second];
|
||||||
|
} else {
|
||||||
|
data.colors[v] = Color::ZERO;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
DEBUG_EXTRA("WARN: solve not successful, using zero adjustments");
|
ColorMap::RasterizeTriangleBary(data.tri[0], data.tri[1], data.tri[2], data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ★FIX: 改回 DilateMean<1>(和原版一致,之前 <5> 过度模糊)
|
||||||
|
imageAdj.DilateMean<1>(imageAdj, Color::ZERO);
|
||||||
|
|
||||||
|
// ★FIX: 去掉 GAIN=10,Y/Cb/Cr 全部 1:1 微调(和原版 GSL3 一致)
|
||||||
|
for (int r = 0; r < srcROI.rows; ++r) {
|
||||||
|
for (int c = 0; c < srcROI.cols; ++c) {
|
||||||
|
const Color& a = imageAdj(r, c);
|
||||||
|
if (a == Color::ZERO) {
|
||||||
|
outPatch.at<cv::Vec3b>(r, c) = srcROI.at<cv::Vec3b>(r, c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const Pixel8U& v = srcROI.at<Pixel8U>(r, c);
|
||||||
|
const Color col(RGB2YCBCR(Color(v)));
|
||||||
|
// ★ 直接加,不放大任何通道
|
||||||
|
const Color acol(YCBCR2RGB(Color(col + a)));
|
||||||
|
outPatch.at<cv::Vec3b>(r, c) = cv::Vec3b(
|
||||||
|
(uint8_t)CLAMP(ROUND2INT(acol[0]), 0, 255),
|
||||||
|
(uint8_t)CLAMP(ROUND2INT(acol[1]), 0, 255),
|
||||||
|
(uint8_t)CLAMP(ROUND2INT(acol[2]), 0, 255));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
DEBUG_EXTRA("WARN: no constraints (rowsA=%lld), skip solve", (long long)rowsA);
|
|
||||||
}
|
}
|
||||||
DEBUG_EXTRA("solve done. colorAdjustments: %zux3", rowsX);
|
|
||||||
|
|
||||||
// ========== 应用颜色修正(输出到 correctedPatchImages,不碰 images)==========
|
|
||||||
correctedPatchImages.resize(numPatches);
|
|
||||||
|
|
||||||
#ifdef TEXOPT_USE_OPENMP
|
|
||||||
#pragma omp parallel for schedule(dynamic)
|
|
||||||
#endif
|
|
||||||
for (int i = 0; i < (int)numPatches; ++i) {
|
|
||||||
const uint32_t idxPatch = (uint32_t)i;
|
|
||||||
const TexturePatch& texturePatch = texturePatches[idxPatch];
|
|
||||||
|
|
||||||
if (texturePatch.label < 0 || texturePatch.label >= (int)images.size()) continue;
|
|
||||||
if (texturePatch.rect.width <= 0 || texturePatch.rect.height <= 0) continue;
|
|
||||||
|
|
||||||
// ★ 从原始 images 读(只读,不修改)
|
|
||||||
const cv::Mat& srcROI = images[texturePatch.label].image(texturePatch.rect);
|
|
||||||
if (srcROI.empty()) continue;
|
|
||||||
|
|
||||||
// ★ 创建独立输出 buffer
|
|
||||||
cv::Mat& outPatch = correctedPatchImages[idxPatch];
|
|
||||||
outPatch = cv::Mat::zeros(texturePatch.rect.size(), CV_8UC3);
|
|
||||||
|
|
||||||
ColorMap imageAdj(texturePatch.rect.size());
|
|
||||||
imageAdj.memset(0);
|
|
||||||
|
|
||||||
struct RasterPatch {
|
|
||||||
const TexCoord* tri;
|
|
||||||
Color colors[3];
|
|
||||||
ColorMap& image;
|
|
||||||
RasterPatch(ColorMap& _image) : image(_image) {}
|
|
||||||
inline cv::Size Size() const { return image.size(); }
|
|
||||||
void operator()(const ImageRef& pt, const Point3f& bary) {
|
|
||||||
image(pt) = colors[0]*bary.x + colors[1]*bary.y + colors[2]*bary.z;
|
|
||||||
}
|
|
||||||
} data(imageAdj);
|
|
||||||
ASSERT(texturePatch.faces.size() < 1000000); // 合理范围
|
|
||||||
for (const FIndex idxFace : texturePatch.faces) {
|
|
||||||
if (idxFace >= faces.GetSize()) continue;
|
|
||||||
const Face& face = faces[idxFace];
|
|
||||||
|
|
||||||
ASSERT(idxFace * 3 + 2 < faceTexcoords.GetSize());
|
|
||||||
for (int v = 0; v < 3; ++v) {
|
|
||||||
ASSERT(face[v] < vertices.size());
|
|
||||||
ASSERT(face[v] < vertpatch2rows.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// // ★ 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;
|
|
||||||
// 改回直接用,不乘
|
|
||||||
data.tri = faceTexcoords.Begin() + idxFace * 3;
|
|
||||||
|
|
||||||
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());
|
|
||||||
data.colors[v] = colorAdjustments[search->second];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
data.colors[v] = Color::ZERO;
|
|
||||||
}
|
|
||||||
ColorMap::RasterizeTriangleBary(data.tri[0], data.tri[1], data.tri[2], data);
|
|
||||||
}
|
|
||||||
imageAdj.DilateMean<5>(imageAdj, Color::ZERO);
|
|
||||||
|
|
||||||
// ★ 把修正叠加到 outPatch(从 srcROI 读原始颜色)
|
|
||||||
for (int r = 0; r < srcROI.rows; ++r) {
|
|
||||||
for (int c = 0; c < srcROI.cols; ++c) {
|
|
||||||
const Color& a = imageAdj(r, c);
|
|
||||||
if (a == Color::ZERO) {
|
|
||||||
outPatch.at<cv::Vec3b>(r, c) = srcROI.at<cv::Vec3b>(r, c);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const Pixel8U& v = srcROI.at<Pixel8U>(r, c);
|
|
||||||
const Color col(RGB2YCBCR(Color(v)));
|
|
||||||
|
|
||||||
// const Color acol(YCBCR2RGB(Color(col + a)));
|
|
||||||
const float GAIN = 10.0f; // ★ 增益,可调(5~20)
|
|
||||||
const Color acol(YCBCR2RGB(Color(
|
|
||||||
col[0] + a[0] * 1.0f, // Y 微调
|
|
||||||
col[1] + a[1] * GAIN, // Cb 大幅调
|
|
||||||
col[2] + a[2] * GAIN // Cr 大幅调
|
|
||||||
)));
|
|
||||||
|
|
||||||
outPatch.at<cv::Vec3b>(r, c) = cv::Vec3b(
|
|
||||||
(uint8_t)CLAMP(ROUND2INT(acol[0]), 0, 255),
|
|
||||||
(uint8_t)CLAMP(ROUND2INT(acol[1]), 0, 255),
|
|
||||||
(uint8_t)CLAMP(ROUND2INT(acol[2]), 0, 255));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DEBUG_EXTRA("All patch adjustments applied (to local buffers)");
|
|
||||||
|
|
||||||
DEBUG_EXTRA("GlobalSeamLeveling4 finished successfully.");
|
DEBUG_EXTRA("GlobalSeamLeveling4 finished successfully.");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user