From eba47cae188bfba351cccc8e444e1b797ad87c20 Mon Sep 17 00:00:00 2001 From: hesuicong Date: Tue, 13 Oct 2026 16:07:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96UV=E5=8C=85=E5=9B=B4=E7=9B=92?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/MVS/SceneTexture.cpp | 78 ++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index 2452ef8..4974aa9 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -16364,7 +16364,7 @@ bool MeshTexture::RasterizeVirtualFaces( float currentScore = virtualFaceViewWeights[i].empty() ? -1.0f : virtualFaceViewWeights[i][0]; - int pad = 4; + int pad = 8; int minX = std::max(0, (int)floor(geom.uvBounds.ptMin.x() * textureSize - pad)); int maxX = std::min(textureSize - 1, (int)ceil(geom.uvBounds.ptMax.x() * textureSize + pad)); int minY = std::max(0, (int)floor(geom.uvBounds.ptMin.y() * textureSize - pad)); @@ -16454,13 +16454,16 @@ bool MeshTexture::RasterizeVirtualFaces( mainPatch.convertTo(mainFloat, CV_32FC3, 1.0f / 255.0f); cv::Mat mainLowFreq; - cv::GaussianBlur(mainFloat, mainLowFreq, cv::Size(31, 31), 2.0); // σ=10 + cv::GaussianBlur(mainFloat, mainLowFreq, cv::Size(31, 31), 10.0); // σ=10 cv::Mat highFreq = mainFloat - mainLowFreq; // 高频 = 原图 - 低频 + // 在合成之前,对 lowFreqPatch 再做一次轻微平滑 + cv::GaussianBlur(lowFreqPatch, lowFreqPatch, cv::Size(5, 5), 1.0); + // ========== 合成:低频用多视图融合,高频用主视图细节 ========== cv::Mat finalPatch = lowFreqPatch + highFreq; - // cv::Mat finalPatch = lowFreqPatch.clone(); + // cv::Mat finalPatch = highFreq.clone(); // finalPatch = cv::Mat::zeros(finalPatch.size(), finalPatch.type()); // 钳制到 [0, 1] @@ -16472,33 +16475,50 @@ bool MeshTexture::RasterizeVirtualFaces( cv::Mat finalPatch8U; clampedPatch.convertTo(finalPatch8U, CV_8UC3, 255.0f); - // ========== 写入 atlas ========== - #pragma omp critical (atlas_write) - { - for (int y = 0; y < patchH; ++y) { - for (int x = 0; x < patchW; ++x) { - cv::Vec3b color = finalPatch8U.at(y, x); - - if (color[0] == 0 && color[1] == 0 && color[2] == 0) continue; + // 在写入 atlas 时,对边界像素做衰减混合 + #pragma omp critical (atlas_write) + { + for (int y = 0; y < patchH; ++y) { + for (int x = 0; x < patchW; ++x) { + cv::Vec3b color = finalPatch8U.at(y, x); + + if (color[0] == 0 && color[1] == 0 && color[2] == 0) continue; - int atlasX = x + minX, atlasY = y + minY; - if (atlasX<0||atlasX>=textureSize||atlasY<0||atlasY>=textureSize) continue; - size_t idx = atlasY * textureSize + atlasX; + int atlasX = x + minX, atlasY = y + minY; + if (atlasX<0||atlasX>=textureSize||atlasY<0||atlasY>=textureSize) continue; + size_t idx = atlasY * textureSize + atlasX; - if (currentScore > m_texelScores[idx].score) { - if (atlasY >= 0 && atlasY < atlas.rows && atlasX >= 0 && atlasX < atlas.cols) { - cv::Vec3b& pixel = atlas.at(atlasY, atlasX); - pixel[0] = color[0]; - pixel[1] = color[1]; - pixel[2] = color[2]; - } - m_texelScores[idx].score = currentScore; - m_texelScores[idx].viewID = mainView; - m_texelPatchID[idx] = i; - } - } - } - } + // ===== 新增:边界衰减权重 ===== + float weight = 1.0f; + float distToEdgeX = std::min((float)x, (float)(patchW - 1 - x)); + float distToEdgeY = std::min((float)y, (float)(patchH - 1 - y)); + float minDist = std::min(distToEdgeX, distToEdgeY); + + if (minDist < pad) { + // 边界 8 像素内做线性衰减 + weight = minDist / (float)pad; + weight = weight * weight; // 平方衰减更平滑 + } + + // 如果已有更高分的 texel,跳过(保持高分优先) + if (currentScore > m_texelScores[idx].score) { + // 如果有旧值,做加权混合 + if (m_texelScores[idx].score > 0 && weight < 1.0f) { + cv::Vec3b oldColor = atlas.at(atlasY, atlasX); + float oldWeight = 1.0f - weight; + color[0] = (uchar)(color[0] * weight + oldColor[0] * oldWeight); + color[1] = (uchar)(color[1] * weight + oldColor[1] * oldWeight); + color[2] = (uchar)(color[2] * weight + oldColor[2] * oldWeight); + } + + atlas.at(atlasY, atlasX) = color; + m_texelScores[idx].score = currentScore; + m_texelScores[idx].viewID = mainView; + m_texelPatchID[idx] = i; + } + } + } + } } VERBOSE("[Raster] Step 3: rasterization done, building RC patches..."); @@ -16566,7 +16586,7 @@ bool MeshTexture::RasterizeVirtualFaces( if (m_texelPatchID[i] != NO_ID) validPixels++; DEBUG_EXTRA("m_texelPatchID: %d valid pixels out of %zu", validPixels, m_texelPatchID.size()); - // cv::imwrite("/home/algo/Documents/openMVS/data/546893/out.546893/debug_atlas_before_return.png", atlas); + cv::imwrite("/home/algo/Documents/openMVS/data/546893/out.546893/debug_atlas_before_return.png", atlas); return true; }