Browse Source

* 提高纹素密度

* 写入 Atlas 时加优先级(Texel 级竞争)
消除接缝模糊、局部染色
每个 texel 只相信“最正面”的那个视图。
ManualUV
hesuicong 3 days ago
parent
commit
411e41e54f
  1. 130
      libs/MVS/SceneTexture.cpp

130
libs/MVS/SceneTexture.cpp

@ -641,6 +641,21 @@ public: @@ -641,6 +641,21 @@ public:
);
float ComputeOcclusionPenalty(const cv::Point2f& p0, const cv::Point2f& p1, const cv::Point2f& p2,
int imageWidth, int imageHeight, int border = 8);
int ComputeOptimalTextureSizeAdaptive(
const VirtualFaceMap& virtualFaceMap,
const std::vector<std::vector<IIndex>>& virtualFaceViews,
unsigned nTextureSizeMultiple);
// 辅助函数:向上取整到最近的2的幂
static int RoundUpPowerOfTwo(int x) {
if (x <= 0) return 1;
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x + 1;
}
bool ComputeVirtualFaceGeometry(const VirtualFaceMap& virtualFaceMap);
@ -706,6 +721,12 @@ public: @@ -706,6 +721,12 @@ public:
Pixel8U colEmpty,
Mesh::Image8U3Arr& outTextures);
struct TexelScore {
float score = -1.0f;
IIndex viewID = NO_ID;
};
std::vector<TexelScore> m_texelScores;
float ComputeComprehensiveScore(const FaceData& data, const Normal& faceNormal,
const Point3f& faceCenter, const Image& image);
float EstimatePixelSize(const Point3f& faceCenter, const Normal& faceNormal,
@ -14218,7 +14239,13 @@ bool MeshTexture::RasterizeVirtualFaces( @@ -14218,7 +14239,13 @@ bool MeshTexture::RasterizeVirtualFaces(
if (uvWidth < 0.001f) uvWidth = 1.0f;
if (uvHeight < 0.001f) uvHeight = 1.0f;
int textureSize = ComputeOptimalTextureSize(uvWidth, uvHeight, nTextureSizeMultiple);
// int textureSize = ComputeOptimalTextureSize(uvWidth, uvHeight, nTextureSizeMultiple);
int textureSize = ComputeOptimalTextureSizeAdaptive(
virtualFaceMap, virtualFaceViews, nTextureSizeMultiple);
// 兜底
if (textureSize < 1024) textureSize = 1024;
if (textureSize > 16384) textureSize = 16384;
// --------------------------------------------------
// 2. 创建纹理
@ -14227,6 +14254,9 @@ bool MeshTexture::RasterizeVirtualFaces( @@ -14227,6 +14254,9 @@ bool MeshTexture::RasterizeVirtualFaces(
Image8U3& atlas = outTextures.back();
atlas.setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r));
// ✅ 初始化评分缓冲
m_texelScores.assign(textureSize * textureSize, TexelScore{});
// ✅ 计算所有虚拟面的几何和映射矩阵
if (!ComputeVirtualFaceGeometry(virtualFaceMap)) {
DEBUG_EXTRA("Failed to compute virtual face geometries");
@ -14305,24 +14335,36 @@ bool MeshTexture::RasterizeVirtualFaces( @@ -14305,24 +14335,36 @@ bool MeshTexture::RasterizeVirtualFaces(
for (int y = 0; y < patchH; ++y) {
for (int x = 0; x < patchW; ++x) {
cv::Vec3b color = patch.at<cv::Vec3b>(y, x);
// 跳过无效像素(BORDER_CONSTANT 产生的黑色)
if (color[0] == 0 && color[1] == 0 && color[2] == 0)
continue;
int atlasX = x + minX;
int atlasY = y + minY;
// ✅ 边界保护
if (atlasX < 0 || atlasX >= textureSize ||
atlasY < 0 || atlasY >= textureSize)
continue;
atlas(atlasY, atlasX) = Pixel8U{color[2], color[1], color[0]};
size_t idx = atlasY * textureSize + atlasX;
TexelScore& ts = m_texelScores[idx];
// ✅ 获取当前虚拟面的评分
float currentScore = virtualFaceViewWeights[i].empty()
? -1.0f
: virtualFaceViewWeights[i][0];
// ✅ 只接受更高评分的写入
if (currentScore > ts.score) {
atlas(atlasY, atlasX) =
Pixel8U{color[2], color[1], color[0]};
ts.score = currentScore;
ts.viewID = viewID;
}
}
}
}
}
m_texelScores.clear();
DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str());
return true;
}
@ -14701,6 +14743,84 @@ float MeshTexture::ComputeOcclusionPenalty( @@ -14701,6 +14743,84 @@ float MeshTexture::ComputeOcclusionPenalty(
return float(count) / 3.0f; // [0, 1]
}
int MeshTexture::ComputeOptimalTextureSizeAdaptive(
const VirtualFaceMap& virtualFaceMap,
const std::vector<std::vector<IIndex>>& virtualFaceViews,
unsigned nTextureSizeMultiple)
{
if (virtualFaceMap.empty()) return 2048;
double totalPixels = 0.0;
double totalAreaUV = 0.0;
for (size_t i = 0; i < virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i];
if (vf.faces.empty() || virtualFaceViews[i].empty())
continue;
IIndex viewID = virtualFaceViews[i][0];
if (viewID >= (IIndex)images.size()) continue;
const Image& img = images[viewID];
if (img.image.empty()) continue;
// UV 面积
const AABB2f& uv = vf.uvBounds;
float uvArea = (uv.ptMax.x() - uv.ptMin.x()) *
(uv.ptMax.y() - uv.ptMin.y());
if (uvArea <= 0.0f) continue;
// 投影到图像,估算像素覆盖
const Mesh::Face& face = scene.mesh.faces[vf.faces[0]];
const Point3f& v0 = scene.mesh.vertices[face[0]];
const Point3f& v1 = scene.mesh.vertices[face[1]];
const Point3f& v2 = scene.mesh.vertices[face[2]];
Point2d p0 = img.camera.ProjectPoint(Point3d(v0));
Point2d p1 = img.camera.ProjectPoint(Point3d(v1));
Point2d p2 = img.camera.ProjectPoint(Point3d(v2));
// 图像空间三角形面积(像素)
double imgArea =
std::abs((p1.x - p0.x) * (p2.y - p0.y) -
(p2.x - p0.x) * (p1.y - p0.y)) * 0.5;
if (imgArea < 1.0) continue;
// 加权累加
totalPixels += imgArea;
totalAreaUV += uvArea;
}
if (totalAreaUV <= 0.0) return 2048;
// 核心公式:
// texelPerUV = sqrt(图像像素总面积 / UV总面积)
double texelsPerUV = std::sqrt(totalPixels / totalAreaUV);
// 用 UV 包围盒大小推算最终纹理尺寸
AABB2f globalUV(true);
for (const auto& vf : virtualFaceMap)
globalUV.Insert(vf.uvBounds);
float uvW = globalUV.ptMax.x() - globalUV.ptMin.x();
float uvH = globalUV.ptMax.y() - globalUV.ptMin.y();
int textureSize = static_cast<int>(
std::max(uvW, uvH) * texelsPerUV
);
// 对齐到 2^n,不超过最大限制
textureSize = RoundUpPowerOfTwo(textureSize);
textureSize = std::min(textureSize, (int)nTextureSizeMultiple);
DEBUG_EXTRA("Adaptive texture size: %d (texels/UV: %.1f)",
textureSize, texelsPerUV);
return textureSize;
}
// ============================================================
// 5. SelectBestViewsForVirtualFaces(带 patch 一致性传播)
// ============================================================

Loading…
Cancel
Save