Browse Source

接缝优化

ManualUV
hesuicong 1 month ago
parent
commit
56f3c93216
  1. 159
      libs/MVS/SceneTexture.cpp

159
libs/MVS/SceneTexture.cpp

@ -763,6 +763,52 @@ public: @@ -763,6 +763,52 @@ public:
unsigned nTextureSizeMultiple,
Pixel8U colEmpty,
Mesh::Image8U3Arr& outTextures);
// ========== 辅助函数 ==========
// 双线性采样(适配 SEACAVE::TImage<Pixel8U>)
static inline Pixel8U SampleBilinear(const Image8U3& img, const Point2f& pt) {
float x = pt.x * img.width() - 0.5f;
float y = pt.y * img.height() - 0.5f;
int x0 = (int)floorf(x), y0 = (int)floorf(y);
int x1 = x0 + 1, y1 = y0 + 1;
float wx = x - x0, wy = y - y0;
// 边界裁剪
x0 = std::max(0, std::min(x0, (int)img.width() - 1));
x1 = std::max(0, std::min(x1, (int)img.width() - 1));
y0 = std::max(0, std::min(y0, (int)img.height() - 1));
y1 = std::max(0, std::min(y1, (int)img.height() - 1));
const Pixel8U& p00 = img(y0, x0);
const Pixel8U& p01 = img(y0, x1);
const Pixel8U& p10 = img(y1, x0);
const Pixel8U& p11 = img(y1, x1);
auto lerp = [](uint8_t a, uint8_t b, float t) -> uint8_t {
return (uint8_t)(a * (1 - t) + b * t);
};
uint8_t r = lerp(lerp(p00.r, p01.r, wx), lerp(p10.r, p11.r, wx), wy);
uint8_t g = lerp(lerp(p00.g, p01.g, wx), lerp(p10.g, p11.g, wx), wy);
uint8_t b = lerp(lerp(p00.b, p01.b, wx), lerp(p10.b, p11.b, wx), wy);
return Pixel8U(b, g, r); // BGR 存储
}
// 重心坐标计算
static inline Point3f Barycentric(const TexCoord& p, const TexCoord& a,
const TexCoord& b, const TexCoord& c) {
float den = (b.y - c.y) * (a.x - c.x) + (c.x - b.x) * (a.y - c.y);
if (fabsf(den) < 1e-10f) return Point3f(-1, -1, -1);
float v = ((b.y - c.y) * (p.x - c.x) + (c.x - b.x) * (p.y - c.y)) / den;
float w = ((c.y - a.y) * (p.x - c.x) + (a.x - c.x) * (p.y - c.y)) / den;
float u = 1.0f - v - w;
return Point3f(u, v, w);
}
// 从重心坐标恢复 3D 点
static inline Point3f BaryTo3D(const Point3f& bary, const Point3f& v0,
const Point3f& v1, const Point3f& v2) {
return v0 * bary.x + v1 * bary.y + v2 * bary.z;
}
struct TexelScore {
float score = -1.0f;
@ -14410,6 +14456,119 @@ bool MeshTexture::RasterizeVirtualFaces( @@ -14410,6 +14456,119 @@ bool MeshTexture::RasterizeVirtualFaces(
}
}
// ========== 接缝区域多视图加权融合 ==========
// 收集需要融合的面(出现在 seamEdges 中的面)
std::set<int> seamFaceIndices;
for (const auto& edge : seamEdges) {
seamFaceIndices.insert((int)edge.i);
seamFaceIndices.insert((int)edge.j);
}
if (!seamFaceIndices.empty()) {
DEBUG_EXTRA("[Blend] Fusing %zu seam faces...", seamFaceIndices.size());
for (int i : seamFaceIndices) {
if (i < 0 || i >= (int)virtualFaceMap.size()) continue;
const VirtualFace& vf = virtualFaceMap[i];
if (vf.faces.empty() || virtualFaceViews[i].empty()) continue;
IIndex refView = virtualFaceViews[i][0];
const auto& candidateViews = virtualFaceViews[i];
const auto& candidateWeights = virtualFaceViewWeights[i];
// 获取该面的 UV 包围盒
const VirtualFaceGeometry& geom = m_virtualFaceGeometries[i];
if (!geom.isValid) continue;
int minX = std::max(0, (int)floor(geom.uvBounds.ptMin.x() * textureSize));
int maxX = std::min(textureSize - 1, (int)ceil(geom.uvBounds.ptMax.x() * textureSize));
int minY = std::max(0, (int)floor(geom.uvBounds.ptMin.y() * textureSize));
int maxY = std::max(0, (int)ceil(geom.uvBounds.ptMax.y() * textureSize));
if (minX > maxX || minY > maxY) continue;
// 逐像素多视图融合
for (int y = minY; y <= maxY; ++y) {
for (int x = minX; x <= maxX; ++x) {
size_t idx = y * textureSize + x;
if (m_texelScores[idx].viewID < 0) continue;
// 只处理当前面贡献的像素(避免覆盖其他面)
// 用 score 判断:如果当前面不是胜者,跳过
float myScore = candidateWeights.empty() ? 0.5f : candidateWeights[0];
if (m_texelScores[idx].score > myScore + 0.01f) continue;
// 计算 3D 点(从重心坐标)
// 简化:用该面第一个三角形
FIndex fid = vf.faces[0];
const Face& face = scene.mesh.faces[fid];
const TexCoord* uvs = &scene.mesh.faceTexcoords[fid * 3];
Point3f bary = Barycentric(
TexCoord((float)x / textureSize, (float)y / textureSize),
uvs[0], uvs[1], uvs[2]);
if (bary.x < 0 || bary.y < 0 || bary.z < 0) continue;
Point3f pt3D = BaryTo3D(bary,
scene.mesh.vertices[face[0]],
scene.mesh.vertices[face[1]],
scene.mesh.vertices[face[2]]);
// 多视图采样
cv::Vec3f blended(0, 0, 0);
float totalW = 0.0f;
for (size_t k = 0; k < candidateViews.size(); ++k) {
IIndex vid = candidateViews[k];
float w = candidateWeights[k];
if (w < 0.01f) continue;
const Image& img = images[vid];
Point2f pt2D = img.camera.ProjectPoint(Point3d(pt3D));
if (pt2D.x < 0 || pt2D.y < 0 ||
pt2D.x >= img.image.width() - 1 ||
pt2D.y >= img.image.height() - 1) continue;
Pixel8U c = SampleBilinear(img.image, pt2D);
cv::Vec3f color(c.r, c.g, c.b);
// 局部增益:以 refView 为参考
if (vid != refView) {
const Image& refImg = images[refView];
Point2f refPt = refImg.camera.ProjectPoint(Point3d(pt3D));
if (refPt.x >= 0 && refPt.y >= 0 &&
refPt.x < refImg.image.width() - 1 &&
refPt.y < refImg.image.height() - 1) {
Pixel8U rc = SampleBilinear(refImg.image, refPt);
cv::Vec3f refColor(rc.r, rc.g, rc.b);
// 加 1 防除零
float gr = (refColor[0] + 1.0f) / (color[0] + 1.0f);
float gg = (refColor[1] + 1.0f) / (color[1] + 1.0f);
float gb = (refColor[2] + 1.0f) / (color[2] + 1.0f);
gr = std::max(0.5f, std::min(2.0f, gr));
gg = std::max(0.5f, std::min(2.0f, gg));
gb = std::max(0.5f, std::min(2.0f, gb));
color = cv::Vec3f(color[0]*gr, color[1]*gg, color[2]*gb);
}
}
blended += color * w;
totalW += w;
}
if (totalW > 0.01f) {
blended /= totalW;
atlas(y, x) = Pixel8U(
(uint8_t)std::min(255.0f, blended[2]), // B
(uint8_t)std::min(255.0f, blended[1]), // G
(uint8_t)std::min(255.0f, blended[0]) // R
);
}
}
}
}
DEBUG_EXTRA("[Blend] Multi-view seam fusion done");
}
// ========== 接缝融合 END ==========
m_texelScores.clear();
DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str());

Loading…
Cancel
Save