diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index a224f36..adc3f59 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -677,6 +677,10 @@ public: Pixel8U colEmpty, Mesh::Image8U3Arr& outTextures); + float ComputeComprehensiveScore(const FaceData& data, const Normal& faceNormal, + const Point3f& faceCenter, const Image& image); + float EstimatePixelSize(const Point3f& faceCenter, const Normal& faceNormal, + const Image& image); bool TextureWithExistingUVVirtualFaces(const IIndexArr& views, int nIgnoreMaskLabel, float fOutlierThreshold, unsigned nTextureSizeMultiple, Pixel8U colEmpty, float fSharpnessWeight); @@ -14211,6 +14215,91 @@ bool MeshTexture::RasterizeVirtualFaces( return true; } +float MeshTexture::EstimatePixelSize(const Point3f& faceCenter, const Normal& faceNormal, + const Image& image) { + // 获取面片的近似面积(使用网格中存储的面片面积,如果有的话) + // 如果没有,我们可以通过三角形面积公式计算 + // 这里假设我们有一个方法获取面片面积,或者通过顶点计算 + + // 简化版本:使用面片到相机的距离和相机焦距来估算像素大小 + const Camera& cam = image.camera; + // ✅ 转换为 cv::Point3d 进行计算 + cv::Point3d fc_d(faceCenter.x, faceCenter.y, faceCenter.z); + cv::Point3d camC = cam.C; + + // 计算视线方向 + cv::Point3d viewDir_d = camC - fc_d; + double norm = cv::norm(viewDir_d); + if (norm > 1e-6) { + viewDir_d /= norm; // 手动归一化 + } + + // 转回 Point3f(如果需要) + Point3f viewDir( + static_cast(viewDir_d.x), + static_cast(viewDir_d.y), + static_cast(viewDir_d.z) + ); + + // 计算面片在图像平面上的投影面积 + // 使用一个近似的正方形面片模型 + float dist = (float)cv::norm(faceCenter - (Point3f)cam.C); + if (dist < 1e-6f) return 0.0f; + + // 估算面片在图像平面上的大小(像素) + // 假设面片是边长为1米的正方形(实际应根据面片真实面积调整) + float approxFaceSize = 1.0f; // 米 + + // 计算像素大小:focal_length * (object_size / distance) + float pixelSize = cam.GetFocalLength() * (approxFaceSize / dist); + + // 转换为像素单位(考虑传感器尺寸和图像分辨率) + // 这里假设相机内参已经考虑了这些因素 + return pixelSize; +} +// 综合评分函数(完全修正版) +float MeshTexture::ComputeComprehensiveScore(const FaceData& data, const Normal& faceNormal, + const Point3f& faceCenter, const Image& image) { + // ✅ 全部使用 OpenCV 的 double 类型进行计算 + cv::Point3d fc_d(faceCenter.x, faceCenter.y, faceCenter.z); + cv::Point3d camC = image.camera.C; + + // ---------- 正对程度(最重要)---------- + // 计算视线方向(从面片指向相机) + cv::Point3d viewDir = camC - fc_d; + double viewDirLen = cv::norm(viewDir); + if (viewDirLen > 1e-6) { + viewDir /= viewDirLen; + } + + // 法线转 double + cv::Point3d normal_d(faceNormal.x, faceNormal.y, faceNormal.z); + + // 计算正面度 + double dot = normal_d.dot(viewDir); + float frontalness = static_cast((dot + 1.0) * 0.5); + + // 基础质量 + float score = data.quality; + score *= frontalness * frontalness; // 平方增强正面偏好 + + // ---------- 距离因子 ---------- + double dist = cv::norm(fc_d - camC); + double focal = image.camera.GetFocalLength(); + + // ✅ 使用 RC 风格的高斯衰减(比线性衰减更好) + double idealDist = 8.0 * focal; // 经验值 + double relDist = dist / idealDist; + double distScore = std::exp(-0.5 * relDist * relDist); + score *= static_cast(distScore); + + // ---------- 分辨率因子 ---------- + float pixelSize = EstimatePixelSize(faceCenter, faceNormal, image); + float resolutionScore = std::min(1.0f, pixelSize / 50.0f); // 至少50像素 + score *= resolutionScore; + + return score; +} bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int nIgnoreMaskLabel, float fOutlierThreshold, unsigned nTextureSizeMultiple, Pixel8U colEmpty, float fSharpnessWeight) @@ -14267,50 +14356,34 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int const FIndex fid = virtualFaceMap[idxVF].faces[0]; const FaceDataArr& vfDatas = virtualFaceDatas[idxVF]; - float bestWeight = -1.0f; + float bestScore = -1.0f; IIndex bestViewID = IIndex(-1); + // 获取面片中心(用于计算距离和视角) + const Face& face = scene.mesh.faces[fid]; + Point3f faceCenter = (scene.mesh.vertices[face[0]] + + scene.mesh.vertices[face[1]] + + scene.mesh.vertices[face[2]]) / 3.0f; + + const Normal& faceNormal = scene.mesh.faceNormals[fid]; + // 遍历能看到这个面片的所有相机 for (const FaceData& data : vfDatas) { if (data.bInvalidFacesRelative) continue; - // 基础质量分数 - float weight = data.quality; - - // 加上法线夹角权重(正对相机的权重更高) const Image& image = images[data.idxView]; - Point3d camDir(0, 0, -1); - camDir = image.camera.R * camDir; - const double len = sqrt(camDir.x*camDir.x + camDir.y*camDir.y + camDir.z*camDir.z); - if (len > 0.0) { - camDir.x /= len; - camDir.y /= len; - camDir.z /= len; - } - - Point3f cameraForward(static_cast(camDir.x), - static_cast(camDir.y), - static_cast(camDir.z)); - - const Normal& faceNormal = scene.mesh.faceNormals[fid]; - float dotProduct = faceNormal.dot(cameraForward); - dotProduct = std::clamp(dotProduct, -1.f, 1.f); - float angleWeight = (dotProduct + 1.0f) * 0.5f; - - // 综合权重 - const float wQuality = 0.7f; - const float wAngle = 0.3f; - float finalWeight = weight * wQuality + angleWeight * wAngle; + // 使用综合评分函数 + float score = ComputeComprehensiveScore(data, faceNormal, faceCenter, image); - if (finalWeight > bestWeight) { - bestWeight = finalWeight; + if (score > bestScore) { + bestScore = score; bestViewID = data.idxView; } } // 如果找到了有效的视图 - if (bestViewID != IIndex(-1) && bestWeight > 0.1f) { + if (bestViewID != IIndex(-1) && bestScore > 0.1f) { virtualFaceViews[idxVF] = { bestViewID }; virtualFaceViewWeights[idxVF] = { 1.0f }; // 单视图权重设为1 } else { @@ -14355,10 +14428,15 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int scene.mesh.faceTexindices[i] = 0; } - // 6.3 可选的锐化处理 + // 6.3 可选的锐化处理(使用更强的锐化) if (fSharpnessWeight > 0) { DEBUG_EXTRA("Applying sharpness filter (weight: %.2f)", fSharpnessWeight); - // ApplySharpening(scene.mesh.texturesDiffuse[0], fSharpnessWeight); + // 使用Unsharp Mask锐化 + cv::Mat textureMat = scene.mesh.texturesDiffuse[0]; + cv::Mat blurred; + cv::GaussianBlur(textureMat, blurred, cv::Size(0, 0), 1.0); + cv::addWeighted(textureMat, 1.0 + fSharpnessWeight, + blurred, -fSharpnessWeight, 0, textureMat); } // 6.4 保存纹理