diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index f015ca2..ebb8f76 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -16416,6 +16416,10 @@ bool MeshTexture::RasterizeVirtualFaces( outTextures.emplace_back(textureSize, textureSize); Image8U3& atlas = outTextures.back(); atlas.setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r)); + + // Pixel8U emptyMarker(255, 0, 255); // BGR: (255, 0, 255) → 品红 + // atlas.setTo(cv::Scalar(emptyMarker.b, emptyMarker.g, emptyMarker.r)); + m_texelScores.assign(textureSize * textureSize, TexelScore{}); m_texelPatchID.assign(textureSize * textureSize, NO_ID); @@ -16543,11 +16547,16 @@ bool MeshTexture::RasterizeVirtualFaces( float u = (float)px / (float)textureSize; float v_coord = (float)py / (float)textureSize; - // 计算重心坐标 - float b0, b1, b2; - if (!ComputeBarycentric(u, v_coord, uv[0], uv[1], uv[2], b0, b1, b2)) { - continue; - } + // 计算重心坐标 + float b0, b1, b2; + bool inside = ComputeBarycentric(u, v_coord, uv[0], uv[1], uv[2], b0, b1, b2); + + // // 统一用宽松容差判断 + // const float EPS_BARY = 1e-2f; + // if (b0 < -EPS_BARY || b1 < -EPS_BARY || b2 < -EPS_BARY) { + // continue; // 真正不在三角形内 + // } + // // 否则继续执行(即使 ComputeBarycentric 返回 false,但坐标只是略微越界) // 3D 插值点 Point3f P = v[0] * b0 + v[1] * b1 + v[2] * b2; @@ -16611,10 +16620,15 @@ bool MeshTexture::RasterizeVirtualFaces( float u = (float)px / (float)textureSize; float v_coord = (float)py / (float)textureSize; + // 计算重心坐标 float b0, b1, b2; - if (!ComputeBarycentric(u, v_coord, uv[0], uv[1], uv[2], b0, b1, b2)) { - continue; - } + bool inside = ComputeBarycentric(u, v_coord, uv[0], uv[1], uv[2], b0, b1, b2); + + // // 统一用宽松容差判断 + // const float EPS_BARY = 1e-2f; + // if (b0 < -EPS_BARY || b1 < -EPS_BARY || b2 < -EPS_BARY) { + // continue; // 真正不在三角形内 + // } Point3f P = v[0] * b0 + v[1] * b1 + v[2] * b2; @@ -16719,8 +16733,18 @@ bool MeshTexture::RasterizeVirtualFaces( } // 再与 mainFloat 混合(低频占主导,主视图补充细节) - cv::Mat finalPatch = filledLowFreq * 0.7f + mainFloat * 0.3f; + // cv::Mat finalPatch = filledLowFreq * 0.7f + mainFloat * 0.3f; + // cv::Mat finalPatch = filledLowFreq * 0.85f + highFreq * 0.15f; + // 对高频做 soft clamp,防止个别极端值拉白发白 + cv::Mat highFreqClamped; + cv::max(highFreq, -0.2f, highFreqClamped); + cv::min(highFreqClamped, 0.2f, highFreqClamped); + + cv::Mat finalPatch = filledLowFreq * 0.8f + highFreqClamped * 0.2f; + // cv::Mat finalPatch = mainFloat; + // cv::Mat finalPatch = lowFreqPatch; + // 钳制到 [0, 1] cv::Mat clampedPatch; cv::max(finalPatch, 0.0f, clampedPatch); @@ -16737,7 +16761,9 @@ bool MeshTexture::RasterizeVirtualFaces( 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; + float mx = mapX.at(y, x); + float my = mapY.at(y, x); + if (mx < 0 || my < 0) continue; // 真正的空洞才跳过 int atlasX = x + minX, atlasY = y + minY; if (atlasX<0||atlasX>=textureSize||atlasY<0||atlasY>=textureSize) continue; @@ -16757,14 +16783,14 @@ bool MeshTexture::RasterizeVirtualFaces( // 如果已有更高分的 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); - } + // // 如果有旧值,做加权混合 + // 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; @@ -16843,6 +16869,11 @@ bool MeshTexture::RasterizeVirtualFaces( // cv::imwrite("/home/algo/Documents/openMVS/data/546893/out.546893/debug_atlas_before_return.png", atlas); + cv::Mat mask; + cv::compare(atlas, cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r), mask, cv::CMP_EQ); + cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(9, 9)); + // cv::morphologyEx(atlas, atlas, cv::MORPH_CLOSE, kernel); + return true; }