最新优化结果
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());
|
||||
}
|
||||
}
|
||||
DEBUG_EXTRA("Input validation done. seamVertices=%zu, faces=%u, vertices=%zu",
|
||||
seamVertices.GetSize(), faces.GetSize(), vertices.size());
|
||||
|
||||
// ========== 标记无效顶点 ==========
|
||||
BoolArr vertexInvalid(vertices.size());
|
||||
@@ -9234,7 +9232,7 @@ void MeshTexture::GlobalSeamLeveling4()
|
||||
if (components[f] == NO_ID) {
|
||||
const Face& face = faces[f];
|
||||
for (int v = 0; v < 3; ++v)
|
||||
patchIndices[face[v]].idxPatch = numPatches; // dummy,后面跳过
|
||||
patchIndices[face[v]].idxPatch = numPatches;
|
||||
continue;
|
||||
}
|
||||
const uint32_t idxPatch(mapIdxPatch[components[f]]);
|
||||
@@ -9246,13 +9244,13 @@ void MeshTexture::GlobalSeamLeveling4()
|
||||
FOREACH(i, seamVertices) {
|
||||
const SeamVertex& seamVertex = seamVertices[i];
|
||||
ASSERT(!seamVertex.patches.empty());
|
||||
ASSERT(seamVertex.idxVertex < vertices.size());
|
||||
ASSERT(seamVertex.idxVertex < vertices.size());
|
||||
PatchIndex& patchIndex = patchIndices[seamVertex.idxVertex];
|
||||
patchIndex.bIndex = true;
|
||||
patchIndex.idxSeamVertex = i;
|
||||
}
|
||||
|
||||
// ========== 构建 vertpatch2rows(块列号 → 连续行)==========
|
||||
// ========== 构建 vertpatch2rows ==========
|
||||
ASSERT(vertices.size() < static_cast<VIndex>(std::numeric_limits<MatIdx>::max()));
|
||||
MatIdx rowsX(0);
|
||||
typedef std::unordered_map<uint32_t, MatIdx> VertexPatch2RowMap;
|
||||
@@ -9268,18 +9266,18 @@ void MeshTexture::GlobalSeamLeveling4()
|
||||
ASSERT(patch.idxPatch != numPatches);
|
||||
ASSERT(patch.idxPatch < numPatches);
|
||||
if (vertpatch2row.find(patch.idxPatch) != vertpatch2row.end())
|
||||
continue; // 去重
|
||||
continue;
|
||||
vertpatch2row[patch.idxPatch] = rowsX++;
|
||||
}
|
||||
} else if (patchIndex.idxPatch < numPatches) {
|
||||
vertpatch2row[patchIndex.idxPatch] = rowsX++;
|
||||
}
|
||||
}
|
||||
const Eigen::Index scalarCols = (Eigen::Index)rowsX * 3; // 每块 3 个标量列 (RGB)
|
||||
DEBUG_EXTRA("vertpatch2rows built: rowsX(blocks)=%u, scalarCols=%lld", rowsX, (long long)scalarCols);
|
||||
const Eigen::Index scalarCols = (Eigen::Index)rowsX * 3;
|
||||
DEBUG_EXTRA("vertpatch2rows built: rowsX=%u, scalarCols=%lld", rowsX, (long long)scalarCols);
|
||||
|
||||
// ============================================================
|
||||
// ========== 构建 Gamma(Tikhonov 正则)========== [修复1: 去重]
|
||||
// ========== 构建 Gamma(Tikhonov 正则)==========
|
||||
// ============================================================
|
||||
std::vector<GSLTriplet> gammaTriplets;
|
||||
gammaTriplets.reserve((size_t)vertices.size() * 8);
|
||||
@@ -9293,7 +9291,7 @@ void MeshTexture::GlobalSeamLeveling4()
|
||||
adjVerts.Empty();
|
||||
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);
|
||||
|
||||
VertexPatchIterator itV(patchIndices[v], seamVertices);
|
||||
@@ -9305,11 +9303,11 @@ void MeshTexture::GlobalSeamLeveling4()
|
||||
const Eigen::Index colA = it_row->second;
|
||||
|
||||
for (const VIndex vAdj : adjVerts) {
|
||||
if (v >= vAdj) continue; // ★ 无向边只处理一次(去重关键)
|
||||
if (v >= vAdj) continue;
|
||||
VertexPatchIterator itVAdj(patchIndices[vAdj], seamVertices);
|
||||
while (itVAdj.Next()) {
|
||||
const uint32_t idxPatchAdj(itVAdj);
|
||||
if (idxPatch != idxPatchAdj) continue; // 同一 patch 才正则化
|
||||
if (idxPatch != idxPatchAdj) continue;
|
||||
auto it_rowAdj = vertpatch2rows[vAdj].find(idxPatchAdj);
|
||||
if (it_rowAdj == vertpatch2rows[vAdj].end()) continue;
|
||||
const Eigen::Index colB = it_rowAdj->second;
|
||||
@@ -9321,7 +9319,6 @@ void MeshTexture::GlobalSeamLeveling4()
|
||||
}
|
||||
}
|
||||
|
||||
// ★ 排序 + 去重合并(消除重复邻接 → 保证矩阵性质良好)
|
||||
std::sort(rawGamma.begin(), rawGamma.end(),
|
||||
[](const GammaRaw& a, const GammaRaw& b) {
|
||||
return a.colA < b.colA || (a.colA == b.colA && a.colB < b.colB);
|
||||
@@ -9339,16 +9336,12 @@ void MeshTexture::GlobalSeamLeveling4()
|
||||
i = j;
|
||||
}
|
||||
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);
|
||||
Gamma.setFromTriplets(gammaTriplets.begin(), gammaTriplets.end());
|
||||
Gamma.makeCompressed();
|
||||
gammaTriplets.clear(); gammaTriplets.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(颜色一致性约束)==========
|
||||
@@ -9373,13 +9366,26 @@ void MeshTexture::GlobalSeamLeveling4()
|
||||
const TexturePatch& tpRef = texturePatches[patch0.idxPatch];
|
||||
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);
|
||||
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 auto idxPatch1 = seamVertex1.patches.Find(patch0.idxPatch);
|
||||
if (idxPatch1 == SeamVertex::Patches::NO_INDEX) continue;
|
||||
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);
|
||||
}
|
||||
vertexColors[i] = sampler.GetColor();
|
||||
@@ -9398,185 +9404,147 @@ void MeshTexture::GlobalSeamLeveling4()
|
||||
const Color& ca = vertexColors[i];
|
||||
const Color& cb = vertexColors[j];
|
||||
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;
|
||||
ATriplets.emplace_back(rowA, colA, 1.0f);
|
||||
ATriplets.emplace_back(rowA, colB, -1.0f);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const Eigen::Index rowsA = rowA;
|
||||
ASSERT(rowsA <= (Eigen::Index)b_coeff.size());
|
||||
SparseMat A(rowsA, scalarCols);
|
||||
A.setFromTriplets(ATriplets.begin(), ATriplets.end());
|
||||
A.makeCompressed();
|
||||
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;
|
||||
colorAdjustments.assign(rowsX, Color::ZERO);
|
||||
|
||||
if (rowsA > 0 && rowsX > 0) {
|
||||
// ★ Lhs = AᵀA + λ² ΓᵀΓ
|
||||
SparseMat ATA = A.transpose() * A;
|
||||
SparseMat GTG = Gamma.transpose() * Gamma;
|
||||
const float lambda = 0.5f; // ★ 正则化强度(可调)
|
||||
const float lambda = 0.1f;
|
||||
GTG *= lambda * lambda;
|
||||
ASSERT(ATA.rows() == GTG.rows() && ATA.cols() == GTG.cols()); // 尺寸一致性检查
|
||||
ATA += GTG;
|
||||
SparseMat& Lhs = ATA;
|
||||
|
||||
// ★★★ 对角加扰动,严格保证正定 ★★★
|
||||
const float eps = 1e-3f; // 足够小不影响结果,保证正定
|
||||
const float eps = 1e-3f;
|
||||
for (Eigen::Index i = 0; i < (Eigen::Index)Lhs.rows(); ++i) {
|
||||
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;
|
||||
solver.setMaxIterations(2000);
|
||||
solver.setTolerance(0.001f);
|
||||
solver.compute(Lhs);
|
||||
if (solver.info() != Eigen::Success) {
|
||||
DEBUG_EXTRA("WARN: Lhs compute failed (info=%d), skipping solve", (int)solver.info());
|
||||
} else {
|
||||
// ★ b 与通道无关 → 一次求解,结果按 InnerStride<3> 分通道
|
||||
if (solver.info() == Eigen::Success) {
|
||||
Eigen::VectorXf b(rowsA);
|
||||
for (Eigen::Index k = 0; k < rowsA; ++k) b(k) = b_coeff[k];
|
||||
const Eigen::VectorXf rhs = A.transpose() * b;
|
||||
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) {
|
||||
colorAdjustments.assign(rowsX, Color::ZERO);
|
||||
for (Eigen::Index v = 0; v < (Eigen::Index)rowsX; ++v) {
|
||||
const float r = x(v * 3 + 0);
|
||||
const float g = x(v * 3 + 1);
|
||||
const float b_ch = x(v * 3 + 2);
|
||||
if (solver.info() == Eigen::Success && (Eigen::Index)(x.size()) >= scalarCols) {
|
||||
colorAdjustments.assign(rowsX, Color::ZERO);
|
||||
for (Eigen::Index v = 0; v < (Eigen::Index)rowsX; ++v) {
|
||||
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, 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.");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user