Browse Source

合并小三角形

ManualUV
hesuicong 1 week ago
parent
commit
e208883638
  1. 786
      libs/MVS/SceneTexture.cpp

786
libs/MVS/SceneTexture.cpp

@ -539,6 +539,14 @@ struct MeshTexture {
} }
}; };
struct VirtualFaceGeometry {
Point3f center; // 面片中心(世界坐标)
Point3f normal; // 面片法线
AABB2f uvBounds; // UV 包围盒
cv::Mat1f homography; // 3x3 单应矩阵(从 UV 到视图)
bool isValid = false;
};
// used to interpolate adjustments color over the whole texture patch // used to interpolate adjustments color over the whole texture patch
typedef TImage<Color> ColorMap; typedef TImage<Color> ColorMap;
@ -550,6 +558,7 @@ struct MeshTexture {
: r(_r), g(_g), b(_b), a(_a) {} : r(_r), g(_g), b(_b), a(_a) {}
}; };
*/ */
std::vector<VirtualFaceGeometry> m_virtualFaceGeometries;
public: public:
MeshTexture(Scene& _scene, unsigned _nResolutionLevel=0, unsigned _nMinResolution=640); MeshTexture(Scene& _scene, unsigned _nResolutionLevel=0, unsigned _nMinResolution=640);
@ -621,12 +630,20 @@ public:
unsigned minCommonCameras, float fOutlierThreshold, unsigned minCommonCameras, float fOutlierThreshold,
float fRatioDataSmoothness, int nIgnoreMaskLabel, float fRatioDataSmoothness, int nIgnoreMaskLabel,
const IIndexArr& views); const IIndexArr& views);
bool ComputeVirtualFaceGeometry(const VirtualFaceMap& virtualFaceMap);
bool ComputeHomographyForVirtualFace(
const VirtualFace& vf,
IIndex viewID,
VirtualFaceGeometry& geom);
std::vector<std::vector<IIndex>> faceViews; std::vector<std::vector<IIndex>> faceViews;
std::vector<std::vector<float>> faceViewWeights; std::vector<std::vector<float>> faceViewWeights;
std::vector<VirtualFaceData> virtualFaceDatas; std::vector<VirtualFaceData> virtualFaceDatas;
std::vector<std::vector<IIndex>> faceNeighbors; std::vector<std::vector<IIndex>> faceNeighbors;
VirtualFaceGeometryArr m_virtualFaceGeometries; // VirtualFaceGeometryArr m_virtualFaceGeometries;
inline Point3f NormalizePoint3(Point3f& p) inline Point3f NormalizePoint3(Point3f& p)
{ {
@ -14161,6 +14178,9 @@ void MeshTexture::FillTextureHoles(std::vector<Image8U3>& textures, Pixel8U colE
DEBUG_EXTRA("Hole filling completed"); DEBUG_EXTRA("Hole filling completed");
} }
// ============================================================
// 3. RC 风格光栅化主函数
// ============================================================
bool MeshTexture::RasterizeVirtualFaces( bool MeshTexture::RasterizeVirtualFaces(
const VirtualFaceMap& virtualFaceMap, const VirtualFaceMap& virtualFaceMap,
const std::vector<std::vector<IIndex>>& virtualFaceViews, const std::vector<std::vector<IIndex>>& virtualFaceViews,
@ -14169,7 +14189,7 @@ bool MeshTexture::RasterizeVirtualFaces(
Pixel8U colEmpty, Pixel8U colEmpty,
Mesh::Image8U3Arr& outTextures) Mesh::Image8U3Arr& outTextures)
{ {
DEBUG_EXTRA("Forward Rasterization Engine: Starting..."); DEBUG_EXTRA("RC-style Rasterization Engine: Starting...");
TD_TIMER_START(); TD_TIMER_START();
if (virtualFaceMap.empty() || virtualFaceViews.size() != virtualFaceMap.size()) if (virtualFaceMap.empty() || virtualFaceViews.size() != virtualFaceMap.size())
@ -14190,162 +14210,109 @@ bool MeshTexture::RasterizeVirtualFaces(
int textureSize = ComputeOptimalTextureSize(uvWidth, uvHeight, nTextureSizeMultiple); int textureSize = ComputeOptimalTextureSize(uvWidth, uvHeight, nTextureSizeMultiple);
// -------------------------------------------------- // --------------------------------------------------
// 2. 创建纹理与缓冲器 // 2. 创建纹理
// -------------------------------------------------- // --------------------------------------------------
outTextures.emplace_back(textureSize, textureSize); outTextures.emplace_back(textureSize, textureSize);
Image8U3& atlas = outTextures.back(); Image8U3& atlas = outTextures.back();
atlas.setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r)); atlas.setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r));
// ✅ 深度缓冲器初始化为正无穷(越小越近) // ✅ 计算所有虚拟面的几何和映射矩阵
cv::Mat1f depthBuffer(textureSize, textureSize, FLT_MAX); if (!ComputeVirtualFaceGeometry(virtualFaceMap)) {
cv::Mat3f colorBuffer(textureSize, textureSize, cv::Vec3f(0.f, 0.f, 0.f)); DEBUG_EXTRA("Failed to compute virtual face geometries");
cv::Mat1b validBuffer(textureSize, textureSize, (uchar)0); return false;
}
// -------------------------------------------------- // --------------------------------------------------
// 3. 正向光栅化主循环 // 3. RC 风格光栅化:按虚拟面批量处理
// -------------------------------------------------- // --------------------------------------------------
#ifdef _USE_OPENMP #ifdef _USE_OPENMP
#pragma omp parallel for schedule(dynamic) #pragma omp parallel for schedule(dynamic)
#endif #endif
for (int_t idxVF = 0; idxVF < (int_t)virtualFaceMap.size(); ++idxVF) { for (int i = 0; i < (int)virtualFaceMap.size(); ++i) {
if (virtualFaceViews[idxVF].empty()) const VirtualFace& vf = virtualFaceMap[i];
const VirtualFaceGeometry& geom = m_virtualFaceGeometries[i];
if (!geom.isValid || vf.faces.empty() || virtualFaceViews[i].empty())
continue; continue;
const IIndex viewID = virtualFaceViews[idxVF][0]; IIndex viewID = virtualFaceViews[i][0];
if (viewID >= (IIndex)images.size()) continue; if (viewID >= (IIndex)images.size()) continue;
const Image& srcImg = images[viewID]; const Image& srcImg = images[viewID];
if (srcImg.image.empty() || srcImg.image.cols < 2 || srcImg.image.rows < 2) if (srcImg.image.empty() || srcImg.image.cols < 2 || srcImg.image.rows < 2)
continue; continue;
const Camera& cam = srcImg.camera; // ✅ UV 包围盒 → 纹理像素范围
const int srcW = srcImg.image.cols; int minX = std::max(0, (int)floor(geom.uvBounds.ptMin.x() * textureSize));
const int srcH = srcImg.image.rows; 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));
for (FIndex faceID : virtualFaceMap[idxVF].faces) { int maxY = std::min(textureSize - 1, (int)ceil(geom.uvBounds.ptMax.y() * textureSize));
if (faceID >= (FIndex)scene.mesh.faces.size()) continue;
const Face& face = scene.mesh.faces[faceID]; if (minX > maxX || minY > maxY) continue;
const TexCoord* uv = &scene.mesh.faceTexcoords[faceID * 3];
// 验证顶点索引 int patchW = maxX - minX + 1;
bool validIndices = true; int patchH = maxY - minY + 1;
for (int i = 0; i < 3; ++i) {
if (face[i] >= scene.mesh.vertices.size()) {
validIndices = false;
break;
}
}
if (!validIndices) continue;
const Point3f* verts[3] = { // ✅ 映射矩阵
&scene.mesh.vertices[face[0]], cv::Mat mapX(patchH, patchW, CV_32FC1);
&scene.mesh.vertices[face[1]], cv::Mat mapY(patchH, patchW, CV_32FC1);
&scene.mesh.vertices[face[2]]
};
// 计算包围盒 // ✅ 直接展开 H 系数(无临时 Mat,RC 标准写法)
float minU = std::min({uv[0].x, uv[1].x, uv[2].x}); const float* H = geom.homography.ptr<float>();
float maxU = std::max({uv[0].x, uv[1].x, uv[2].x});
float minV = std::min({uv[0].y, uv[1].y, uv[2].y});
float maxV = std::max({uv[0].y, uv[1].y, uv[2].y});
int minX = std::max(0, (int)floor(minU * textureSize)); for (int y = minY; y <= maxY; ++y) {
int maxX = std::min(textureSize - 1, (int)ceil(maxU * textureSize)); for (int x = minX; x <= maxX; ++x) {
int minY = std::max(0, (int)floor(minV * textureSize)); float u = (float)x / (float)textureSize;
int maxY = std::min(textureSize - 1, (int)ceil(maxV * textureSize)); float v = (float)y / (float)textureSize;
if (minX > maxX || minY > maxY) continue; float w = H[6] * u + H[7] * v + H[8];
// ✅ 预计算顶点深度(用于透视校正) // ✅ 数值保护(防止除零)
float vertexDepths[3]; if (std::abs(w) < 1e-12f) {
for (int i = 0; i < 3; ++i) { mapX.at<float>(y - minY, x - minX) = -1.0f;
vertexDepths[i] = cam.PointDepth(*verts[i]); mapY.at<float>(y - minY, x - minX) = -1.0f;
if (vertexDepths[i] <= 0.0f) { continue;
validIndices = false;
break;
} }
}
if (!validIndices) continue;
for (int y = minY; y <= maxY; ++y) { float imgX = (H[0] * u + H[1] * v + H[2]) / w;
for (int x = minX; x <= maxX; ++x) { float imgY = (H[3] * u + H[4] * v + H[5]) / w;
Point2f texCoord(
(x + 0.5f) / textureSize,
(y + 0.5f) / textureSize
);
Point3f bary; mapX.at<float>(y - minY, x - minX) = imgX;
if (!PointInTriangle(texCoord, uv[0], uv[1], uv[2], bary)) mapY.at<float>(y - minY, x - minX) = imgY;
continue; }
}
// ✅ 透视校正插值(double 精度) // ✅ 一次性 remap 整个 patch
double invZ = bary.x / vertexDepths[0] + cv::Mat patch;
bary.y / vertexDepths[1] + cv::remap(srcImg.image, patch, mapX, mapY,
bary.z / vertexDepths[2]; cv::INTER_LINEAR, cv::BORDER_CONSTANT,
if (invZ <= 0.0) continue; cv::Scalar(0, 0, 0));
// ✅ 校正后的重心坐标
double u0 = (bary.x / vertexDepths[0]) / invZ;
double u1 = (bary.y / vertexDepths[1]) / invZ;
double u2 = (bary.z / vertexDepths[2]) / invZ;
// ✅ 透视校正的世界坐标(double)
Point3d P_double(
verts[0]->x * u0 + verts[1]->x * u1 + verts[2]->x * u2,
verts[0]->y * u0 + verts[1]->y * u1 + verts[2]->y * u2,
verts[0]->z * u0 + verts[1]->z * u1 + verts[2]->z * u2
);
// ✅ 正确的投影(double → float)
Point2d imgPtDouble = cam.ProjectPoint(P_double);
Point2f imgPt(static_cast<float>(imgPtDouble.x),
static_cast<float>(imgPtDouble.y));
// ✅ 边界检查
if (imgPt.x < 0.5f || imgPt.y < 0.5f ||
imgPt.x >= srcW - 0.5f || imgPt.y >= srcH - 0.5f)
continue;
// ✅ 双线性采样 // ✅ 拷贝到 atlas(OpenMP critical 区)
Color color = BilinearSample(srcImg.image, imgPt); #pragma omp critical
if (color[0] < 0 || color[1] < 0 || color[2] < 0) continue; {
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;
// ✅ 深度测试(float 缓冲,double 比较) int atlasX = x + minX;
float depthFloat = static_cast<float>(1.0 / invZ); int atlasY = y + minY;
#pragma omp critical // ✅ 边界保护
{ if (atlasX < 0 || atlasX >= textureSize ||
if (depthFloat < depthBuffer(y, x)) { atlasY < 0 || atlasY >= textureSize)
depthBuffer(y, x) = depthFloat; continue;
colorBuffer(y, x) = cv::Vec3f(
color[0], color[1], color[2]
);
validBuffer(y, x) = 1;
}
}
}
}
}
}
// -------------------------------------------------- atlas(atlasY, atlasX) = Pixel8U{color[2], color[1], color[0]};
// 4. 最终写入纹理 }
// --------------------------------------------------
for (int y = 0; y < textureSize; ++y) {
for (int x = 0; x < textureSize; ++x) {
if (validBuffer(y, x)) {
cv::Vec3f c = colorBuffer(y, x);
atlas(y, x) = Pixel8U{
(unsigned char)cv::saturate_cast<uchar>(c[0]),
(unsigned char)cv::saturate_cast<uchar>(c[1]),
(unsigned char)cv::saturate_cast<uchar>(c[2])
};
} }
} }
} }
DEBUG_EXTRA("Forward Rasterization completed: %s", TD_TIMER_GET_FMT().c_str()); DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str());
return true; return true;
} }
@ -14639,92 +14606,76 @@ bool MeshTexture::GenerateTextureWithVirtualFaces(bool bGlobalSeamLeveling, bool
} }
} }
bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap, // ============================================================
unsigned minCommonCameras, float fOutlierThreshold, // 5. SelectBestViewsForVirtualFaces(带 patch 一致性传播)
float fRatioDataSmoothness, int nIgnoreMaskLabel, // ============================================================
const IIndexArr& views) bool MeshTexture::SelectBestViewsForVirtualFaces(
VirtualFaceMap& virtualFaceMap,
unsigned minCommonCameras, float fOutlierThreshold,
float fRatioDataSmoothness, int nIgnoreMaskLabel,
const IIndexArr& views)
{ {
DEBUG_EXTRA("Selecting best views for %zu virtual faces", virtualFaceMap.size()); DEBUG_EXTRA("Selecting best views for %zu virtual faces", virtualFaceMap.size());
faceViews.resize(virtualFaceMap.size()); faceViews.resize(virtualFaceMap.size());
faceViewWeights.resize(virtualFaceMap.size()); faceViewWeights.resize(virtualFaceMap.size());
if (m_virtualFaceGeometries.empty() || for (auto& v : faceViews) v.clear();
m_virtualFaceGeometries.size() < virtualFaceMap.size()) { for (auto& w : faceViewWeights) w.clear();
m_virtualFaceGeometries.Resize(virtualFaceMap.size());
// 确保 faceNeighbors 已填充
if (faceNeighbors.empty()) {
DEBUG_EXTRA("faceNeighbors empty, running ComputePureFaceVisibility first");
if (!ComputePureFaceVisibility(fOutlierThreshold, nIgnoreMaskLabel, views)) {
return false;
}
} }
for (auto& viewList : faceViews) viewList.clear(); // faceToView 映射
for (auto& weightList : faceViewWeights) weightList.clear(); std::vector<IIndex> faceToView(scene.mesh.faces.size(), NO_ID);
// ===== Debug 统计 ===== // ---------- 1. 初始视图分配 ----------
size_t emptyCandidateViews = 0; size_t emptyCandidateViews = 0;
size_t emptyCommonViews = 0;
size_t fallbackByCenterFace = 0; size_t fallbackByCenterFace = 0;
size_t successVF = 0; size_t successVF = 0;
// ✅ 面片 → 视图 映射表
std::vector<IIndex> faceToView(scene.mesh.faces.size(), NO_ID);
// ----------------------------------------------------------------
// 1. 初始视图分配
// ----------------------------------------------------------------
for (size_t i = 0; i < virtualFaceMap.size(); ++i) { for (size_t i = 0; i < virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i]; const VirtualFace& vf = virtualFaceMap[i];
if (vf.faces.empty()) continue; if (vf.faces.empty()) continue;
FIndex faceID2 = vf.faces[0]; FIndex faceID = vf.faces[0];
if (faceID2 >= faceNeighbors.size()) { if (faceID >= faceNeighbors.size()) continue;
DEBUG_EXTRA("FATAL: faceID %u out of range!", faceID2);
continue;
}
// 收集候选视图 // 收集候选视图
std::unordered_set<IIndex> candidateViews; std::unordered_set<IIndex> candidateViews;
for (FIndex faceID : vf.faces) { for (FIndex fid : vf.faces) {
if (faceID >= faceNeighbors.size()) continue; if (fid >= faceNeighbors.size()) continue;
for (IIndex viewID : faceNeighbors[faceID]) { for (IIndex vid : faceNeighbors[fid]) {
if (views.empty() || views.FindFirst(viewID) != NO_ID) { if (views.empty() || views.FindFirst(vid) != NO_ID) {
candidateViews.insert(viewID); candidateViews.insert(vid);
} }
} }
} }
// ------------------------------------------------------------
// 2. 兜底:候选视图为空
// ------------------------------------------------------------
if (candidateViews.empty()) { if (candidateViews.empty()) {
++emptyCandidateViews; ++emptyCandidateViews;
// 兜底:用第一个可用视图
IIndex forcedView = NO_ID; IIndex forcedView = (!views.empty()) ? views[0] :
if (!views.empty()) { (!images.empty()) ? 0 : NO_ID;
forcedView = views[0];
} else if (!images.empty()) {
forcedView = 0;
}
if (forcedView != NO_ID) { if (forcedView != NO_ID) {
faceViews[i].push_back(forcedView); faceViews[i].push_back(forcedView);
faceViewWeights[i].push_back(1.0f); faceViewWeights[i].push_back(1.0f);
for (FIndex fid : vf.faces) { for (FIndex fid : vf.faces) {
if (fid < faceToView.size()) if (fid < faceToView.size())
faceToView[fid] = forcedView; faceToView[fid] = forcedView;
} }
++fallbackByCenterFace; ++fallbackByCenterFace;
continue;
} }
DEBUG_EXTRA("VF[%zu] truly hopeless: no images available", i);
continue; continue;
} }
// ------------------------------------------------------------ // 选第一个候选(简单策略,后续可优化为角度最优)
// 3. 选择最佳视图(简单策略:第一个候选)
// ------------------------------------------------------------
IIndex bestView = *candidateViews.begin(); IIndex bestView = *candidateViews.begin();
faceViews[i].push_back(bestView); faceViews[i].push_back(bestView);
faceViewWeights[i].push_back(1.0f); faceViewWeights[i].push_back(1.0f);
@ -14732,13 +14683,10 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
if (fid < faceToView.size()) if (fid < faceToView.size())
faceToView[fid] = bestView; faceToView[fid] = bestView;
} }
++successVF; ++successVF;
} }
// ---------------------------------------------------------------- // ---------- 2. Patch 一致性传播 ----------
// 4. 【轻量 Patch 一致性传播】
// ----------------------------------------------------------------
if (scene.mesh.faceFaces.empty()) { if (scene.mesh.faceFaces.empty()) {
scene.mesh.ListIncidenteFaceFaces(); scene.mesh.ListIncidenteFaceFaces();
} }
@ -14777,13 +14725,10 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
newFaceToView[fid] = majorityView; newFaceToView[fid] = majorityView;
} }
} }
faceToView.swap(newFaceToView); faceToView.swap(newFaceToView);
} }
// ---------------------------------------------------------------- // ---------- 3. 写回 ----------
// 5. 根据传播后的结果,更新 virtual face 的视图
// ----------------------------------------------------------------
for (size_t i = 0; i < virtualFaceMap.size(); ++i) { for (size_t i = 0; i < virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i]; const VirtualFace& vf = virtualFaceMap[i];
if (vf.faces.empty() || faceViews[i].empty()) continue; if (vf.faces.empty() || faceViews[i].empty()) continue;
@ -14796,22 +14741,150 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
} }
} }
// ----------------------------------------------------------------
// 6. Debug 汇总
// ----------------------------------------------------------------
DEBUG_EXTRA("====== Virtual Face View Selection Summary ======"); DEBUG_EXTRA("====== Virtual Face View Selection Summary ======");
DEBUG_EXTRA("Total virtual faces : %zu", virtualFaceMap.size()); DEBUG_EXTRA("Total virtual faces : %zu", virtualFaceMap.size());
DEBUG_EXTRA("Successfully assigned : %zu", successVF); DEBUG_EXTRA("Successfully assigned : %zu", successVF);
DEBUG_EXTRA("Empty candidates : %zu", emptyCandidateViews); DEBUG_EXTRA("Empty candidates : %zu", emptyCandidateViews);
DEBUG_EXTRA("Fallback by center face : %zu", fallbackByCenterFace); DEBUG_EXTRA("Fallback by center face : %zu", fallbackByCenterFace);
DEBUG_EXTRA("Empty after relaxation : %zu", emptyCommonViews);
DEBUG_EXTRA("Expected empty ratio : %.2f%%",
100.0 * (emptyCandidateViews - fallbackByCenterFace) / virtualFaceMap.size());
DEBUG_EXTRA("================================================="); DEBUG_EXTRA("=================================================");
return true; return true;
} }
// ============================================================
// 1. 计算虚拟面几何(Affine for triangle, Homography for patch)
// ============================================================
bool MeshTexture::ComputeVirtualFaceGeometry(const VirtualFaceMap& virtualFaceMap) {
// ✅ std::vector 用 resize
m_virtualFaceGeometries.resize(virtualFaceMap.size());
#ifdef _USE_OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for (int i = 0; i < (int)virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i];
VirtualFaceGeometry& geom = m_virtualFaceGeometries[i];
if (vf.faces.empty() || faceViews[i].empty()) {
geom.isValid = false;
continue;
}
IIndex viewID = faceViews[i][0];
geom.isValid = ComputeHomographyForVirtualFace(vf, viewID, geom);
}
return true;
}
// ============================================================
// 2. 核心:计算单应矩阵 / 仿射矩阵
// - 3 个点 → Affine(getAffineTransform)
// - ≥ 4 个点 → Homography(findHomography)
// ============================================================
bool MeshTexture::ComputeHomographyForVirtualFace(
const VirtualFace& vf,
IIndex viewID,
VirtualFaceGeometry& geom)
{
if (viewID >= (IIndex)images.size()) return false;
const Camera& cam = images[viewID].camera;
// ---------- 1. 收集顶点和 UV ----------
std::vector<Point3f> points3D;
std::vector<Point2f> pointsUV;
points3D.reserve(vf.faces.size() * 3);
pointsUV.reserve(vf.faces.size() * 3);
for (FIndex faceID : vf.faces) {
if (faceID >= (FIndex)scene.mesh.faces.size()) continue;
const Face& face = scene.mesh.faces[faceID];
const TexCoord* uv = &scene.mesh.faceTexcoords[faceID * 3];
for (int i = 0; i < 3; ++i) {
if (face[i] >= scene.mesh.vertices.size()) continue;
points3D.push_back(scene.mesh.vertices[face[i]]);
pointsUV.push_back(Point2f(uv[i].x, uv[i].y));
}
}
if (points3D.size() < 3) return false;
// ---------- 2. 计算中心(OpenCV 风格)----------
geom.center = Point3f(0, 0, 0);
for (const auto& p : points3D) geom.center += p;
geom.center *= 1.0f / (float)points3D.size();
// ---------- 3. 计算法线(OpenCV 风格)----------
if (!vf.faces.empty()) {
FIndex faceID = vf.faces[0];
const Face& face = scene.mesh.faces[faceID];
const Point3f& v0 = scene.mesh.vertices[face[0]];
const Point3f& v1 = scene.mesh.vertices[face[1]];
const Point3f& v2 = scene.mesh.vertices[face[2]];
Point3f edge1 = v1 - v0;
Point3f edge2 = v2 - v0;
Point3f normal = edge1.cross(edge2);
float length = cv::norm(normal);
if (length > 1e-8f) {
normal *= 1.0f / length;
} else {
normal = Point3f(0, 0, 1);
}
geom.normal = normal;
}
// ---------- 4. UV 包围盒 ----------
geom.uvBounds.Reset();
for (const auto& uv : pointsUV) {
geom.uvBounds.InsertFull(uv);
}
// ---------- 5. 投影到图像空间(double → float)----------
std::vector<Point2f> pointsImage;
pointsImage.reserve(points3D.size());
for (const auto& p3D : points3D) {
Point3d p64(p3D.x, p3D.y, p3D.z);
Point2d proj = cam.ProjectPoint(p64);
pointsImage.emplace_back((float)proj.x, (float)proj.y);
}
// ---------- 6. 核心分支:Affine vs Homography ----------
if (pointsUV.size() == 3) {
// ✅ 三角形:用仿射变换(Affine = 精确映射)
cv::Point2f src[3] = {pointsUV[0], pointsUV[1], pointsUV[2]};
cv::Point2f dst[3] = {pointsImage[0], pointsImage[1], pointsImage[2]};
cv::Mat affine = cv::getAffineTransform(src, dst);
if (affine.empty()) return false;
// 转成 3x3 齐次矩阵(与 Homography 统一格式)
geom.homography = cv::Mat1f(3, 3, 0.0f);
for (int r = 0; r < 2; ++r) {
for (int c = 0; c < 3; ++c) {
geom.homography(r, c) = affine.at<double>(r, c);
}
}
geom.homography(2, 2) = 1.0f;
}
else if (pointsUV.size() >= 4) {
// ✅ Patch:用 RANSAC 单应矩阵
geom.homography = cv::findHomography(
pointsUV, pointsImage, cv::RANSAC, 2.0);
}
else {
return false;
}
geom.isValid = !geom.homography.empty();
return geom.isValid;
}
bool MeshTexture::GenerateTextureWithVirtualFacesInternal(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, bool MeshTexture::GenerateTextureWithVirtualFacesInternal(bool bGlobalSeamLeveling, bool bLocalSeamLeveling,
unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic,
Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize,
@ -14918,282 +14991,34 @@ bool MeshTexture::ConvertVectorToVirtualFaceDataArr(const std::vector<VirtualFac
return true; return true;
} }
bool MeshTexture::CreateVirtualFacesForExistingUV(VirtualFaceMap& virtualFaceMap) {
DEBUG_EXTRA("Creating virtual faces for existing UV texture mapping");
// 0. 详细的输入验证 // ============================================================
DEBUG_EXTRA("=== Detailed Input Validation ==="); // 4. CreateVirtualFacesForExistingUV(简化版)
DEBUG_EXTRA("Scene pointer: %p", &scene); // ============================================================
DEBUG_EXTRA("Mesh pointer: %p", &scene.mesh); bool MeshTexture::CreateVirtualFacesForExistingUV(VirtualFaceMap& virtualFaceMap) {
DEBUG_EXTRA("Creating virtual faces for existing UV (RC style)");
// 检查基本数据结构 // 输入验证
if (scene.mesh.faces.empty()) { if (scene.mesh.faces.empty()) {
DEBUG_EXTRA("ERROR: Mesh has no faces!"); DEBUG_EXTRA("ERROR: Mesh has no faces!");
return false; return false;
} }
if (scene.mesh.vertices.empty()) { if (scene.mesh.vertices.empty()) {
DEBUG_EXTRA("ERROR: Mesh has no vertices!"); DEBUG_EXTRA("ERROR: Mesh has no vertices!");
return false; return false;
} }
if (scene.mesh.faceTexcoords.empty()) {
virtualFaceMap.resize(scene.mesh.faces.size()); DEBUG_EXTRA("ERROR: Mesh has no texture coordinates!");
for (FIndex i = 0; i < (FIndex)scene.mesh.faces.size(); ++i) {
virtualFaceMap[i].faces = {i};
}
return true;
// 验证faces数组的大小
size_t numFaces = scene.mesh.faces.size();
size_t numVertices = scene.mesh.vertices.size();
size_t numFaceTexcoords = scene.mesh.faceTexcoords.size();
DEBUG_EXTRA("Number of faces: %zu", numFaces);
DEBUG_EXTRA("Number of vertices: %zu", numVertices);
DEBUG_EXTRA("Number of texture coordinates: %zu", numFaceTexcoords);
// 关键检查:必须有纹理坐标才能使用此方法
if (numFaceTexcoords == 0) {
DEBUG_EXTRA("ERROR: Mesh has no texture coordinates. Cannot create virtual faces for existing UV.");
return false;
}
if (numFaceTexcoords < numFaces * 3) {
DEBUG_EXTRA("ERROR: Not enough UV coordinates! Expected %zu (faces * 3), have %zu",
numFaces * 3, numFaceTexcoords);
return false;
}
// 验证面片索引
DEBUG_EXTRA("Validating face indices...");
for (size_t i = 0; i < std::min(numFaces, static_cast<size_t>(10)); ++i) { // 使用static_cast
const Mesh::Face& face = scene.mesh.faces[i];
bool valid = true;
for (int j = 0; j < 3; ++j) {
if (face[j] >= numVertices) {
DEBUG_EXTRA("ERROR: Face %zu has invalid vertex index %u (max: %zu)",
i, face[j], numVertices - 1);
valid = false;
}
}
if (valid) {
DEBUG_EXTRA("Face %zu: vertices [%u, %u, %u] - OK",
i, face[0], face[1], face[2]);
}
}
// 验证UV坐标索引
if (numFaceTexcoords > 0) {
DEBUG_EXTRA("Validating UV coordinate indices...");
if (numFaceTexcoords < numFaces * 3) {
DEBUG_EXTRA("ERROR: Not enough UV coordinates! Expected %zu, have %zu",
numFaces * 3, numFaceTexcoords);
return false;
}
}
// 1. 确保网格拓扑已计算
DEBUG_EXTRA("Computing mesh topology...");
if (scene.mesh.faceFaces.empty()) {
DEBUG_EXTRA(" Computing incident faces...");
try {
scene.mesh.ListIncidenteFaces();
scene.mesh.ListIncidenteFaceFaces();
DEBUG_EXTRA(" Done computing incident faces");
} catch (const std::exception& e) {
DEBUG_EXTRA(" ERROR computing incident faces: %s", e.what());
return false;
}
}
if (scene.mesh.faceNormals.empty()) {
DEBUG_EXTRA(" Computing face normals...");
try {
scene.mesh.ComputeNormalFaces();
DEBUG_EXTRA(" Done computing face normals");
} catch (const std::exception& e) {
DEBUG_EXTRA(" ERROR computing face normals: %s", e.what());
return false;
}
}
std::vector<bool> processedFaces(numFaces, false);
// 3. 基于曲率分割网格
DEBUG_EXTRA("Segmenting mesh based on curvature...");
Mesh::FaceIdxArr regionMap;
try {
scene.SegmentMeshBasedOnCurvature(regionMap, 0.2f);
DEBUG_EXTRA("Mesh segmentation completed, regionMap size: %zu", regionMap.size());
if (regionMap.size() != numFaces) {
DEBUG_EXTRA("ERROR: regionMap size (%zu) doesn't match number of faces (%u)",
regionMap.size(), numFaces);
return false;
}
} catch (const std::exception& e) {
DEBUG_EXTRA("ERROR during mesh segmentation: %s", e.what());
return false; return false;
} }
// 4. 统计每个区域的面积 // ✅ RC 风格:每个三角形一个虚拟面(1:1)
DEBUG_EXTRA("Calculating region areas..."); virtualFaceMap.resize(scene.mesh.faces.size());
std::unordered_map<int, float> regionAreas; for (FIndex i = 0; i < (FIndex)scene.mesh.faces.size(); ++i) {
virtualFaceMap[i].faces = {i};
for (FIndex fid = 0; fid < numFaces; ++fid) {
if (fid % 10000 == 0 && fid > 0) {
DEBUG_EXTRA(" Processed %u/%u faces", fid, numFaces);
}
int region = regionMap[fid];
// 验证面片索引
if (fid >= scene.mesh.faces.size()) {
DEBUG_EXTRA("ERROR: Face index %u out of bounds (mesh has %zu faces)",
fid, scene.mesh.faces.size());
continue;
}
const Mesh::Face& face = scene.mesh.faces[fid];
// 验证顶点索引
for (int i = 0; i < 3; ++i) {
if (face[i] >= scene.mesh.vertices.size()) {
DEBUG_EXTRA("ERROR: Vertex index %u out of bounds in face %u (mesh has %zu vertices)",
face[i], fid, scene.mesh.vertices.size());
continue;
}
}
const Point3f& v0 = scene.mesh.vertices[face[0]];
const Point3f& v1 = scene.mesh.vertices[face[1]];
const Point3f& v2 = scene.mesh.vertices[face[2]];
// 计算三角形面积
Point3f edge1 = v1 - v0;
Point3f edge2 = v2 - v0;
Point3f crossProd(
edge1.y * edge2.z - edge1.z * edge2.y,
edge1.z * edge2.x - edge1.x * edge2.z,
edge1.x * edge2.y - edge1.y * edge2.x
);
float area = 0.5f * std::sqrt(
crossProd.x * crossProd.x +
crossProd.y * crossProd.y +
crossProd.z * crossProd.z
);
if (area < 0) {
DEBUG_EXTRA("WARNING: Negative area calculated for face %u: %f", fid, area);
area = 0.0f;
}
regionAreas[region] += area;
}
DEBUG_EXTRA("Region area calculation completed, found %zu regions", regionAreas.size());
// 5. 为每个区域收集面片
DEBUG_EXTRA("Grouping faces by region...");
std::unordered_map<int, std::vector<FIndex>> regionFaces;
for (FIndex fid = 0; fid < numFaces; ++fid) {
int region = regionMap[fid];
regionFaces[region].push_back(fid);
}
DEBUG_EXTRA("Found %zu regions with faces", regionFaces.size());
// 6. 创建虚拟面
DEBUG_EXTRA("Creating virtual faces...");
virtualFaceMap.clear();
virtualFaceMap.reserve(regionFaces.size());
int regionCount = 0;
int smallRegionCount = 0;
int uvDiscontinuousCount = 0;
int createdVirtualFaces = 0;
for (const auto& region : regionFaces) {
regionCount++;
int regionID = region.first;
const std::vector<FIndex>& faceList = region.second;
if (regionCount % 100 == 0) {
DEBUG_EXTRA(" Processing region %d/%d (%zu faces)", regionCount, regionFaces.size(), faceList.size());
}
// 检查区域面积是否足够大
float regionArea = regionAreas[regionID];
if (regionArea < 0.001f) { // 面积阈值
DEBUG_EXTRA(" Region %d is too small (area: %f), using individual faces", regionID, regionArea);
smallRegionCount++;
// 区域太小,不创建虚拟面
for (FIndex fid : faceList) {
virtualFaceMap.push_back(VirtualFace());
virtualFaceMap.back().faces.push_back(fid);
}
continue;
}
// 检查UV连续性
if (!CheckUVContinuity(faceList)) {
DEBUG_EXTRA(" Region %d has discontinuous UV, using individual faces", regionID);
uvDiscontinuousCount++;
// UV不连续,保持原始面片
for (FIndex fid : faceList) {
virtualFaceMap.push_back(VirtualFace());
virtualFaceMap.back().faces.push_back(fid);
}
continue;
}
// 创建虚拟面
VirtualFace vf;
vf.faces = faceList;
// 计算虚拟面的中心、法线和面积
if (!CalculateVirtualFaceProperties(vf)) {
DEBUG_EXTRA(" Failed to calculate properties for virtual face in region %d", regionID);
// 计算失败,回退到原始面片
for (FIndex fid : faceList) {
virtualFaceMap.push_back(VirtualFace());
virtualFaceMap.back().faces.push_back(fid);
}
continue;
}
// 计算虚拟面的UV边界
if (!CalculateVirtualFaceUVBounds(vf)) {
DEBUG_EXTRA(" Failed to calculate UV bounds for virtual face in region %d", regionID);
// 计算失败,回退到原始面片
for (FIndex fid : faceList) {
virtualFaceMap.push_back(VirtualFace());
virtualFaceMap.back().faces.push_back(fid);
}
continue;
}
virtualFaceMap.push_back(vf);
createdVirtualFaces++;
}
DEBUG_EXTRA("Virtual face creation completed:");
DEBUG_EXTRA(" Total regions: %zu", regionFaces.size());
DEBUG_EXTRA(" Small regions (area < 0.001): %d", smallRegionCount);
DEBUG_EXTRA(" UV discontinuous regions: %d", uvDiscontinuousCount);
DEBUG_EXTRA(" Created virtual faces: %d", createdVirtualFaces);
DEBUG_EXTRA(" Total virtual faces (including individual faces): %zu", virtualFaceMap.size());
if (virtualFaceMap.empty()) {
DEBUG_EXTRA("ERROR: No virtual faces created!");
return false;
} }
DEBUG_EXTRA("Created %zu virtual faces (one per triangle)", virtualFaceMap.size());
return true; return true;
} }
@ -18813,49 +18638,48 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
return false; return false;
} }
// ✅✅✅ 关键修复:重新计算拓扑(否则 faceFaces 是坏的) // ✅ 确保拓扑信息存在
mesh.ListIncidenteFaces(); if (mesh.faceFaces.empty()) {
mesh.ListIncidenteFaceFaces(); mesh.ListIncidenteFaces();
mesh.ComputeNormalFaces(); mesh.ListIncidenteFaceFaces();
mesh.ListBoundaryVertices(); }
if (mesh.faceNormals.empty()) {
// 纯可见性计算(初始化faceNeighbors) mesh.ComputeNormalFaces();
if (!texture.ComputePureFaceVisibility(fOutlierThreshold, nIgnoreMaskLabel, views)) { }
// ❗ 兜底:如果ComputePureFaceVisibility没初始化faceNeighbors,手动填充 if (mesh.vertexBoundary.empty()) {
if (texture.faceNeighbors.empty()) { mesh.ListBoundaryVertices();
texture.faceNeighbors.resize(mesh.faces.size()); }
for (FIndex fid = 0; fid < (FIndex)mesh.faces.size(); ++fid) {
if (!views.empty()) {
texture.faceNeighbors[fid].insert(texture.faceNeighbors[fid].end(), views.begin(), views.end());
} else {
for (IIndex vid = 0; vid < (IIndex)images.size(); ++vid)
texture.faceNeighbors[fid].push_back(vid);
}
}
DEBUG_EXTRA("Forced fill faceNeighbors for %zu faces", mesh.faces.size());
}
return false;
}
// 创建虚拟面(1:1映射) // ✅ 1. 创建虚拟面(每三角形一个)
MeshTexture::VirtualFaceMap virtualFaceMap; MeshTexture::VirtualFaceMap virtualFaceMap;
if (!texture.CreateVirtualFacesForExistingUV(virtualFaceMap)) return false; if (!texture.CreateVirtualFacesForExistingUV(virtualFaceMap))
return false;
// 选最佳视图(带patch一致性) // ✅ 2. 计算可见性(填充 faceNeighbors)
if (!texture.SelectBestViewsForVirtualFaces( if (!texture.ComputePureFaceVisibility(
virtualFaceMap, 1, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views)) fOutlierThreshold, nIgnoreMaskLabel, views)) {
return false; return false;
}
// 直接光栅化(不需要生成图集) // ✅ 3. 选择最佳视图(带 patch 一致性)
Mesh::Image8U3Arr textures; if (!texture.SelectBestViewsForVirtualFaces(
if (!texture.RasterizeVirtualFaces( virtualFaceMap, 1, fOutlierThreshold,
virtualFaceMap, texture.faceViews, texture.faceViewWeights, fRatioDataSmoothness, nIgnoreMaskLabel, views))
nTextureSizeMultiple, colEmpty, textures)) return false;
return false;
// ✅ 4. RC 风格光栅化(Affine + Homography 混合)
Mesh::Image8U3Arr textures;
if (!texture.RasterizeVirtualFaces(
virtualFaceMap, texture.faceViews,
texture.faceViewWeights,
nTextureSizeMultiple, colEmpty, textures))
return false;
mesh.texturesDiffuse = std::move(textures);
DEBUG_EXTRA("Existing UV texturing completed: %u faces (%s)",
mesh.faces.size(), TD_TIMER_GET_FMT().c_str());
return true;
mesh.texturesDiffuse = std::move(textures);
DEBUG_EXTRA("Existing UV texturing completed: %u faces (%s)", mesh.faces.size(), TD_TIMER_GET_FMT().c_str());
return true; // 直接返回,不走后面的图集逻辑
} else { } else {
// 3. 通用虚拟面模式(无预计算UV) // 3. 通用虚拟面模式(无预计算UV)
if (!texture.FaceViewSelectionWithVirtualFaces( if (!texture.FaceViewSelectionWithVirtualFaces(

Loading…
Cancel
Save