|
|
|
|
@ -476,6 +476,8 @@ public:
@@ -476,6 +476,8 @@ public:
|
|
|
|
|
|
|
|
|
|
bool CreateVirtualFaces7(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; |
|
|
|
|
IIndexArr SelectBestViews(const FaceDataArr& faceDatas, FIndex fid, unsigned minCommonCameras, float ratioAngleToQuality) const; |
|
|
|
|
IIndexArr SelectBestViews2(const FaceDataArr& faceDatas, FIndex fid, unsigned minCommonCameras, float ratioAngleToQuality, FaceDataViewArr& facesDatas) const; |
|
|
|
|
|
|
|
|
|
IIndexArr SelectBestView(const FaceDataArr& faceDatas, FIndex fid, unsigned minCommonCameras, float ratioAngleToQuality) const; |
|
|
|
|
|
|
|
|
|
bool FaceViewSelection(unsigned minCommonCameras, float fOutlierThreshold, float fRatioDataSmoothness, int nIgnoreMaskLabel, const IIndexArr& views); |
|
|
|
|
@ -1776,6 +1778,97 @@ void MeshTexture::PerformLocalDepthConsistencyCheck(DepthMap& depthMap, FaceMap&
@@ -1776,6 +1778,97 @@ void MeshTexture::PerformLocalDepthConsistencyCheck(DepthMap& depthMap, FaceMap&
|
|
|
|
|
} |
|
|
|
|
//*/
|
|
|
|
|
|
|
|
|
|
IIndexArr MeshTexture::SelectBestViews2(const FaceDataArr& faceDatas, FIndex fid, unsigned minCommonCameras, float ratioAngleToQuality, FaceDataViewArr& facesDatas) const |
|
|
|
|
{ |
|
|
|
|
ASSERT(!faceDatas.empty()); |
|
|
|
|
|
|
|
|
|
// 计算每个视图能看到的相邻面片数量
|
|
|
|
|
std::unordered_map<IIndex, int> viewCoverageCount; |
|
|
|
|
for (const FaceData& fd : faceDatas) { |
|
|
|
|
if (!fd.bInvalidFacesRelative) { |
|
|
|
|
viewCoverageCount[fd.idxView] = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 统计每个视图能看到的面片数
|
|
|
|
|
for (const FaceData& fd : faceDatas) { |
|
|
|
|
if (!fd.bInvalidFacesRelative) { |
|
|
|
|
// 统计这个视图能看到的所有相邻面片
|
|
|
|
|
const Mesh::FaceFaces& ffaces = faceFaces[fid]; |
|
|
|
|
for (int i = 0; i < 3; ++i) { |
|
|
|
|
const FIndex neighborIdx = ffaces[i]; |
|
|
|
|
if (neighborIdx != NO_ID) { |
|
|
|
|
const FaceDataArr& neighborDatas = facesDatas[neighborIdx]; |
|
|
|
|
for (const FaceData& neighborFd : neighborDatas) { |
|
|
|
|
if (neighborFd.idxView == fd.idxView && !neighborFd.bInvalidFacesRelative) { |
|
|
|
|
viewCoverageCount[fd.idxView]++; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 重新计算分数,考虑覆盖范围
|
|
|
|
|
float maxQuality = 0; |
|
|
|
|
for (const FaceData& faceData: faceDatas) |
|
|
|
|
maxQuality = MAXF(maxQuality, faceData.quality); |
|
|
|
|
const Face& f = faces[fid]; |
|
|
|
|
const Vertex faceCenter((vertices[f[0]] + vertices[f[1]] + vertices[f[2]]) / 3.f); |
|
|
|
|
|
|
|
|
|
CLISTDEF0IDX(float,IIndex) scores(faceDatas.size()); |
|
|
|
|
FOREACH(idxFaceData, faceDatas) { |
|
|
|
|
const FaceData& faceData = faceDatas[idxFaceData]; |
|
|
|
|
if (faceData.bInvalidFacesRelative) { |
|
|
|
|
scores[idxFaceData] = -1.0f; // 无效视图分数为负
|
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const Image& imageData = images[faceData.idxView]; |
|
|
|
|
const Point3f camDir(Cast<Mesh::Type>(imageData.camera.C) - faceCenter); |
|
|
|
|
const Normal& faceNormal = scene.mesh.faceNormals[fid]; |
|
|
|
|
const float cosFaceCam(ComputeAngle(camDir.ptr(), faceNormal.ptr())); |
|
|
|
|
|
|
|
|
|
// 计算覆盖范围分数(0-1之间)
|
|
|
|
|
float coverageScore = 0.0f; |
|
|
|
|
if (viewCoverageCount.find(faceData.idxView) != viewCoverageCount.end()) { |
|
|
|
|
int maxCoverage = 0; |
|
|
|
|
for (const auto& pair : viewCoverageCount) { |
|
|
|
|
maxCoverage = MAX(maxCoverage, pair.second); |
|
|
|
|
} |
|
|
|
|
if (maxCoverage > 0) { |
|
|
|
|
coverageScore = static_cast<float>(viewCoverageCount[faceData.idxView]) / maxCoverage; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 综合角度、质量和覆盖范围
|
|
|
|
|
const float angleScore = ratioAngleToQuality * cosFaceCam; |
|
|
|
|
const float qualityScore = (1.0f - ratioAngleToQuality) * faceData.quality / maxQuality; |
|
|
|
|
const float coverageWeight = 0.3f; // 覆盖范围权重
|
|
|
|
|
const float combinedScore = 0.4f * angleScore + 0.3f * qualityScore + coverageWeight * coverageScore; |
|
|
|
|
|
|
|
|
|
scores[idxFaceData] = combinedScore; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 按分数排序
|
|
|
|
|
IIndexArr scorePodium(faceDatas.size()); |
|
|
|
|
std::iota(scorePodium.begin(), scorePodium.end(), 0); |
|
|
|
|
scorePodium.Sort([&scores](IIndex i, IIndex j) { |
|
|
|
|
return scores[i] > scores[j]; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// 选择最佳视图
|
|
|
|
|
IIndexArr cameras; |
|
|
|
|
for (IIndex i = 0; i < MIN(minCommonCameras, faceDatas.size()); ++i) { |
|
|
|
|
if (scores[scorePodium[i]] > 0.1f) { // 分数阈值
|
|
|
|
|
cameras.push_back(faceDatas[scorePodium[i]].idxView); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return cameras; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// order the camera view scores with highest score first and return the list of first <minCommonCameras> cameras
|
|
|
|
|
// ratioAngleToQuality represents the ratio in witch we combine normal angle to quality for a face to obtain the selection score
|
|
|
|
|
// - a ratio of 1 means only angle is considered
|
|
|
|
|
@ -2962,8 +3055,8 @@ bool MeshTexture::CreateVirtualFaces6(FaceDataViewArr& facesDatas, FaceDataViewA
@@ -2962,8 +3055,8 @@ bool MeshTexture::CreateVirtualFaces6(FaceDataViewArr& facesDatas, FaceDataViewA
|
|
|
|
|
ASSERT(posToErase != Mesh::FaceIdxArr::NO_INDEX); |
|
|
|
|
remainingFaces.RemoveAtMove(posToErase); |
|
|
|
|
} else { |
|
|
|
|
// IIndexArr selectedCams = SelectBestViews2(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality, facesDatas);
|
|
|
|
|
IIndexArr selectedCams = SelectBestViews(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality); |
|
|
|
|
|
|
|
|
|
//*
|
|
|
|
|
// 获取中心面片的法线 (注意变量名是 normalCenter, 不是 centerNormal)
|
|
|
|
|
const Normal& normalCenter = scene.mesh.faceNormals[virtualFaceCenterFaceID]; |
|
|
|
|
@ -4228,6 +4321,16 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4228,6 +4321,16 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
cQueue<FIndex, FIndex, 0> currentVirtualFaceQueue; |
|
|
|
|
std::unordered_set<FIndex> queuedFaces; |
|
|
|
|
|
|
|
|
|
// std::vector<std::unordered_set<IIndex>> faceValidCameras(faces.size());
|
|
|
|
|
// for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) {
|
|
|
|
|
// const FaceDataArr& faceDatas = facesDatas[idxFace];
|
|
|
|
|
// for (const FaceData& fd : faceDatas) {
|
|
|
|
|
// if (!fd.bInvalidFacesRelative) {
|
|
|
|
|
// faceValidCameras[idxFace].insert(fd.idxView);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Precompute average color for each face
|
|
|
|
|
Colors faceColors; // 创建一个空列表
|
|
|
|
|
faceColors.reserve(faces.size()); // 预分配空间(如果cList有reserve方法且您关心性能)
|
|
|
|
|
@ -4326,7 +4429,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4326,7 +4429,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
remainingFaces.RemoveAtMove(posToErase); |
|
|
|
|
} else { |
|
|
|
|
IIndexArr selectedCams = SelectBestViews(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality); |
|
|
|
|
|
|
|
|
|
// IIndexArr selectedCams = SelectBestViews2(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality, facesDatas);
|
|
|
|
|
//*
|
|
|
|
|
// 获取中心面片的法线 (注意变量名是 normalCenter, 不是 centerNormal)
|
|
|
|
|
const Normal& normalCenter = scene.mesh.faceNormals[virtualFaceCenterFaceID]; |
|
|
|
|
@ -4383,7 +4486,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4383,7 +4486,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
{ |
|
|
|
|
// printf("CreateVirtualFace %s, %d, %f\n", strName.c_str(), virtualFaceCenterFaceID, angleLimit);
|
|
|
|
|
|
|
|
|
|
if (angleDeg <= 45.0f) |
|
|
|
|
if (angleDeg <= 35.0f) |
|
|
|
|
{ |
|
|
|
|
filteredCams.push_back(idxView); |
|
|
|
|
/*
|
|
|
|
|
@ -4455,22 +4558,40 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4455,22 +4558,40 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
do { |
|
|
|
|
const FIndex currentFaceId = currentVirtualFaceQueue.GetHead(); |
|
|
|
|
currentVirtualFaceQueue.PopHead(); |
|
|
|
|
|
|
|
|
|
// check for condition to add in current virtual face
|
|
|
|
|
// normal angle smaller than thMaxNormalDeviation degrees
|
|
|
|
|
const Normal& faceNormal = scene.mesh.faceNormals[currentFaceId]; |
|
|
|
|
const float cosFaceToCenter(ComputeAngleN(normalCenter.ptr(), faceNormal.ptr())); |
|
|
|
|
// if (cosFaceToCenter < cosMaxNormalDeviation)
|
|
|
|
|
if (cosFaceToCenter < dynamicCosTh) |
|
|
|
|
continue; |
|
|
|
|
// if (cosFaceToCenter < dynamicCosTh) // 使用动态阈值
|
|
|
|
|
// continue;
|
|
|
|
|
// printf("dynamicCosTh=%f\n", dynamicCosTh);
|
|
|
|
|
// if (cosFaceToCenter < 0.99) // 对应60度,比原来的更宽松
|
|
|
|
|
// continue;
|
|
|
|
|
if (cosFaceToCenter < dynamicCosTh) // 使用动态阈值
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
// check if current face is seen by all cameras in selectedCams
|
|
|
|
|
ASSERT(!selectedCams.empty()); |
|
|
|
|
if (!IsFaceVisible(facesDatas[currentFaceId], selectedCams)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
// Check color similarity
|
|
|
|
|
// 3. 放宽颜色差异条件
|
|
|
|
|
const Color& centerColor = faceColors[virtualFaceCenterFaceID]; |
|
|
|
|
const Color& currentColor = faceColors[currentFaceId]; |
|
|
|
|
float colorDistance = cv::norm(centerColor - currentColor); |
|
|
|
|
if (colorDistance > 200.0f) { // 从200.0f放宽到250.0f
|
|
|
|
|
// continue; // 如果颜色差异太大,跳过
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// check if current face is seen by all cameras in selectedCams
|
|
|
|
|
// ASSERT(!selectedCams.empty());
|
|
|
|
|
// if (!IsFaceVisible(facesDatas[currentFaceId], selectedCams))
|
|
|
|
|
// continue;
|
|
|
|
|
|
|
|
|
|
// // Check color similarity
|
|
|
|
|
// const Color& centerColor = faceColors[virtualFaceCenterFaceID];
|
|
|
|
|
// const Color& currentColor = faceColors[currentFaceId];
|
|
|
|
|
// if (cv::norm(centerColor) > 1e-5 && cv::norm(currentColor) > 1e-5)
|
|
|
|
|
{ |
|
|
|
|
float colorDistance = cv::norm(centerColor - currentColor); |
|
|
|
|
@ -7040,7 +7161,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT
@@ -7040,7 +7161,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// construct and use virtual faces for patch creation instead of actual mesh faces;
|
|
|
|
|
// the virtual faces are composed of coplanar triangles sharing same views
|
|
|
|
|
if (bUseVirtualFaces) { |
|
|
|
|
@ -7058,7 +7179,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT
@@ -7058,7 +7179,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT
|
|
|
|
|
CreateVirtualFaces62(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); |
|
|
|
|
TD_TIMER_STARTD(); |
|
|
|
|
// CreateVirtualFaces7(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
|
|
|
|
DEBUG_EXTRA("CreateVirtualFaces7 completed: %s", TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
DEBUG_EXTRA("CreateVirtualFaces completed: %s", TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
|
|
|
|
|
size_t controlCounter(0); |
|
|
|
|
FOREACH(idxVF, virtualFaces) { |
|
|
|
|
|