Browse Source

添加视图综合评分函数

ManualUV
hesuicong 5 days ago
parent
commit
73b8d77980
  1. 164
      libs/MVS/SceneTexture.cpp

164
libs/MVS/SceneTexture.cpp

@ -630,6 +630,17 @@ public:
unsigned minCommonCameras, float fOutlierThreshold, unsigned minCommonCameras, float fOutlierThreshold,
float fRatioDataSmoothness, int nIgnoreMaskLabel, float fRatioDataSmoothness, int nIgnoreMaskLabel,
const IIndexArr& views); const IIndexArr& views);
float ComputeViewNormalScore(const Mesh::Normal& faceNormal, const Camera& camera, const Point3f& faceCenter);
float ComputeResolutionScore(
const Camera& camera,
const Point3f& v0,
const Point3f& v1,
const Point3f& v2,
int imageWidth,
int imageHeight
);
float ComputeOcclusionPenalty(const cv::Point2f& p0, const cv::Point2f& p1, const cv::Point2f& p2,
int imageWidth, int imageHeight, int border = 8);
bool ComputeVirtualFaceGeometry(const VirtualFaceMap& virtualFaceMap); bool ComputeVirtualFaceGeometry(const VirtualFaceMap& virtualFaceMap);
@ -14606,6 +14617,90 @@ bool MeshTexture::GenerateTextureWithVirtualFaces(bool bGlobalSeamLeveling, bool
} }
} }
float MeshTexture::ComputeViewNormalScore(
const Mesh::Normal& faceNormal,
const Camera& camera,
const Point3f& faceCenter)
{
// ✅ 转换为 double 避免 float/double 混用
Point3d C(camera.C);
Point3d FC(faceCenter);
// 视线方向:相机 → 面中心(手动计算)
Point3d viewDir(
C.x - FC.x,
C.y - FC.y,
C.z - FC.z
);
float vlen = std::sqrt(viewDir.x*viewDir.x +
viewDir.y*viewDir.y +
viewDir.z*viewDir.z);
if (vlen < 1e-8f) return 0.0f;
viewDir /= vlen;
// 面法线
Point3f normal = faceNormal;
float nlen = std::sqrt(normal.x*normal.x +
normal.y*normal.y +
normal.z*normal.z);
if (nlen < 1e-8f) return 0.0f;
normal /= nlen;
float cosTheta = viewDir.x*normal.x +
viewDir.y*normal.y +
viewDir.z*normal.z;
return (cosTheta > 0.0f) ? cosTheta : 0.0f;
}
float MeshTexture::ComputeResolutionScore(
const Camera& camera,
const Point3f& v0,
const Point3f& v1,
const Point3f& v2,
int imageWidth,
int imageHeight)
{
Point2d p0 = camera.ProjectPoint(Point3d(v0));
Point2d p1 = camera.ProjectPoint(Point3d(v1));
Point2d p2 = camera.ProjectPoint(Point3d(v2));
auto inImage = [&](const Point2f& p) {
return p.x >= 0 && p.x < imageWidth &&
p.y >= 0 && p.y < imageHeight;
};
if (!inImage(p0) || !inImage(p1) || !inImage(p2))
return 0.0f;
float area =
std::abs((p1.x - p0.x) * (p2.y - p0.y) -
(p2.x - p0.x) * (p1.y - p0.y)) * 0.5f;
if (area < 1.0f) return 0.0f;
return std::log2(area + 1.0f);
}
float MeshTexture::ComputeOcclusionPenalty(
const cv::Point2f& p0,
const cv::Point2f& p1,
const cv::Point2f& p2,
int imageWidth,
int imageHeight,
int border)
{
auto inside = [&](const cv::Point2f& p) {
return p.x >= border && p.x < imageWidth - border &&
p.y >= border && p.y < imageHeight - border;
};
int count = 0;
if (!inside(p0)) count++;
if (!inside(p1)) count++;
if (!inside(p2)) count++;
return float(count) / 3.0f; // [0, 1]
}
// ============================================================ // ============================================================
// 5. SelectBestViewsForVirtualFaces(带 patch 一致性传播) // 5. SelectBestViewsForVirtualFaces(带 patch 一致性传播)
// ============================================================ // ============================================================
@ -14674,8 +14769,75 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(
continue; continue;
} }
// ✅ 获取面的顶点(必须在循环内定义!)
const Mesh::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 faceCenter = (v0 + v1 + v2) / 3.0f;
Point3f faceNormal = scene.mesh.faceNormals[faceID];
// 归一化
float norm = std::sqrt(faceNormal.x * faceNormal.x +
faceNormal.y * faceNormal.y +
faceNormal.z * faceNormal.z);
if (norm > FLT_EPSILON) {
faceNormal.x /= norm;
faceNormal.y /= norm;
faceNormal.z /= norm;
} else {
// 退化三角形,使用默认法线
faceNormal = Point3f(0, 0, 1);
}
// 选第一个候选(简单策略,后续可优化为角度最优) // 选第一个候选(简单策略,后续可优化为角度最优)
IIndex bestView = *candidateViews.begin(); // IIndex bestView = *candidateViews.begin();
IIndex bestView = NO_ID;
float bestScore = -FLT_MAX;
for (IIndex vid : candidateViews) {
if (vid >= (IIndex)images.size()) continue;
const Image& img = images[vid];
if (img.image.empty() || img.image.cols < 2 || img.image.rows < 2)
continue;
const Camera& cam = img.camera;
// 1. 正面度评分
float s_normal = ComputeViewNormalScore(faceNormal, cam, faceCenter);
if (s_normal <= 0.0f) continue;
// 2. 分辨率评分
float s_resolution = ComputeResolutionScore(
cam, v0, v1, v2,
img.image.cols, img.image.rows
);
// 3. 遮挡惩罚
Point2f p0 = cam.ProjectPoint(Point3d(v0));
Point2f p1 = cam.ProjectPoint(Point3d(v1));
Point2f p2 = cam.ProjectPoint(Point3d(v2));
float s_occlusion = ComputeOcclusionPenalty(
p0, p1, p2,
img.image.cols, img.image.rows,
8 // border pixels
);
// 综合评分
float score = 1.0f * s_normal
+ 0.7f * s_resolution
- 0.3f * s_occlusion;
if (score > bestScore) {
bestScore = score;
bestView = vid;
}
}
faceViews[i].push_back(bestView); faceViews[i].push_back(bestView);
faceViewWeights[i].push_back(1.0f); faceViewWeights[i].push_back(1.0f);

Loading…
Cancel
Save