|
|
|
|
@ -4345,7 +4345,7 @@ bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataView
@@ -4345,7 +4345,7 @@ bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
|
|
|
|
|
// 动态法线阈值
|
|
|
|
|
const float centerCurvature = meshCurvatures[virtualFaceCenterFaceID]; |
|
|
|
|
const float dynamicThreshold = (centerCurvature < 0.2f) ? 15.0f : 8.0f; |
|
|
|
|
const float dynamicThreshold = (centerCurvature < 0.2f) ? 18.0f : 10.0f; // 放宽角度阈值
|
|
|
|
|
const float dynamicCosTh = COS(FD2R(dynamicThreshold)); |
|
|
|
|
|
|
|
|
|
ASSERT(currentVirtualFaceQueue.IsEmpty()); |
|
|
|
|
@ -4468,32 +4468,20 @@ bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataView
@@ -4468,32 +4468,20 @@ bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 按angleDeg从小到大排序
|
|
|
|
|
std::sort(cameraAngles.begin(), cameraAngles.end(), |
|
|
|
|
std::vector<std::pair<IIndex, float>> sortedCams = cameraAngles; |
|
|
|
|
std::sort(sortedCams.begin(), sortedCams.end(), |
|
|
|
|
[](const std::pair<IIndex, float>& a, const std::pair<IIndex, float>& b) { |
|
|
|
|
return a.second < b.second; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
IIndexArr filteredCams; |
|
|
|
|
|
|
|
|
|
// 核心优化:根据中心面片质量决定选择多少张视图
|
|
|
|
|
if (centerFaceQuality >= QUALITY_THRESHOLD) { |
|
|
|
|
// 质量高于阈值,尽量使用同一张视图(角度最小的)
|
|
|
|
|
if (!cameraAngles.empty()) { |
|
|
|
|
// 只选择角度最小的一张视图
|
|
|
|
|
filteredCams.push_back(cameraAngles[0].first); |
|
|
|
|
} else if (!selectedCams.empty()) { |
|
|
|
|
// 如果没有符合条件的相机,回退到原始选择中的第一个
|
|
|
|
|
filteredCams.push_back(selectedCams[0]); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// 质量低于阈值,可以选择多张视图
|
|
|
|
|
size_t count = std::min(cameraAngles.size(), static_cast<size_t>(3)); |
|
|
|
|
for (size_t i = 0; i < count; ++i) { |
|
|
|
|
filteredCams.push_back(cameraAngles[i].first); |
|
|
|
|
} |
|
|
|
|
size_t count = std::min(sortedCams.size(), static_cast<size_t>(3)); |
|
|
|
|
for (size_t i = 0; i < count; ++i) { |
|
|
|
|
filteredCams.push_back(sortedCams[i].first); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (filteredCams.empty()) { |
|
|
|
|
// 处理空情况
|
|
|
|
|
selectedCams = filteredCams; |
|
|
|
|
isVirtualFace[virtualFaceCenterFaceID] = false; |
|
|
|
|
} else { |
|
|
|
|
@ -4516,15 +4504,18 @@ bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataView
@@ -4516,15 +4504,18 @@ bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
if (!IsFaceVisible(facesDatas[currentFaceId], selectedCams)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
// 修改3:调整颜色差异检查
|
|
|
|
|
const Color& centerColor = faceColors[virtualFaceCenterFaceID]; |
|
|
|
|
const Color& currentColor = faceColors[currentFaceId]; |
|
|
|
|
float colorDistance = cv::norm(centerColor - currentColor); |
|
|
|
|
if (colorDistance > 200.0f) { |
|
|
|
|
// continue; // 可选:如果颜色差异太大,跳过
|
|
|
|
|
|
|
|
|
|
// 放宽颜色差异条件
|
|
|
|
|
if (colorDistance > 250.0f) { // 增加阈值
|
|
|
|
|
// 不跳过,继续处理
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (colorDistance > thMaxColorDeviation) { |
|
|
|
|
// continue; // 可选:如果颜色差异太大,跳过
|
|
|
|
|
// 保持原有逻辑
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
@ -4550,6 +4541,7 @@ bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataView
@@ -4550,6 +4541,7 @@ bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
// 计算虚拟面质量并创建虚拟面
|
|
|
|
|
for (IIndex idxView: selectedCams) { |
|
|
|
|
FaceData& virtualFaceData = virtualFaceDatas.emplace_back(); |
|
|
|
|
|
|
|
|
|
virtualFaceData.quality = 0; |
|
|
|
|
virtualFaceData.idxView = idxView; |
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
@ -4587,88 +4579,28 @@ bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataView
@@ -4587,88 +4579,28 @@ bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
|
|
|
|
|
int validViewsSize = validViews.size(); |
|
|
|
|
if (bHasInvalidView) { |
|
|
|
|
// 使用简化逻辑
|
|
|
|
|
const Color medianColor = ComputeMedianColorAndQuality(sortedViews).color; |
|
|
|
|
const float medianQuality = ComputeMedianColorAndQuality(sortedViews).quality; |
|
|
|
|
const float medianLuminance = ComputeMedianLuminance(sortedViews); |
|
|
|
|
const float colorMAD = ComputeColorMAD(sortedViews, medianColor); |
|
|
|
|
const float luminanceMAD = ComputeLuminanceMAD(sortedViews, medianLuminance); |
|
|
|
|
const float maxColorDeviation = 0.01f * colorMAD; |
|
|
|
|
const float maxLuminanceDeviation = 0.01f * luminanceMAD; |
|
|
|
|
|
|
|
|
|
std::vector<int> validIndices; |
|
|
|
|
for (int n = 0; n < sortedViews.size(); ++n) { |
|
|
|
|
const Color& viewColor = sortedViews[n].second; |
|
|
|
|
const float viewLuminance = MeshTexture::GetLuminance(viewColor); |
|
|
|
|
const float colorDistance = cv::norm(viewColor - medianColor); |
|
|
|
|
const float luminanceDistance = std::abs(viewLuminance - medianLuminance); |
|
|
|
|
|
|
|
|
|
if (colorDistance <= maxColorDeviation && luminanceDistance <= maxLuminanceDeviation) { |
|
|
|
|
if (scene.is_face_normal_visible_map(strName, virtualFaceCenterFaceID)) |
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
} else { |
|
|
|
|
const FIndex currentFaceId = currentVirtualFaceQueue.GetHead(); |
|
|
|
|
const Normal& faceNormal = scene.mesh.faceNormals[currentFaceId]; |
|
|
|
|
const float cosFaceToCenter(ComputeAngleN(normalCenter.ptr(), faceNormal.ptr())); |
|
|
|
|
bool bColorSimilarity = true; |
|
|
|
|
const Color& centerColor = faceColors[virtualFaceCenterFaceID]; |
|
|
|
|
const Color& currentColor = faceColors[currentFaceId]; |
|
|
|
|
float colorDistance2 = cv::norm(centerColor - currentColor); |
|
|
|
|
if (colorDistance2 > thMaxColorDeviation) { |
|
|
|
|
bColorSimilarity = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (cosFaceToCenter<dynamicCosTh) { |
|
|
|
|
if (nInvalidViewCount<=2) { |
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
} else { |
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (nInvalidViewCount<=2) { |
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
} else { |
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 计算虚拟面数据
|
|
|
|
|
ASSERT(processedFaces > 0); |
|
|
|
|
virtualFaceData.quality = 0; |
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
virtualFaceData.color = Point3f::ZERO; |
|
|
|
|
#endif |
|
|
|
|
// 直接使用中位数计算
|
|
|
|
|
virtualFaceData.quality = medianQuality; |
|
|
|
|
virtualFaceData.color = medianColor; |
|
|
|
|
} else { |
|
|
|
|
const Color medianColor = ComputeMedianColorAndQuality(sortedViews).color; |
|
|
|
|
const float medianQuality = ComputeMedianColorAndQuality(sortedViews).quality; |
|
|
|
|
const float medianLuminance = ComputeMedianLuminance(sortedViews); |
|
|
|
|
const float colorMAD = ComputeColorMAD(sortedViews, medianColor); |
|
|
|
|
const float luminanceMAD = ComputeLuminanceMAD(sortedViews, medianLuminance); |
|
|
|
|
const float maxColorDeviation = 0.01f * colorMAD; |
|
|
|
|
const float maxLuminanceDeviation = 0.05f * luminanceMAD; |
|
|
|
|
|
|
|
|
|
std::vector<int> validIndices; |
|
|
|
|
for (int n = 0; n < sortedViews.size(); ++n) { |
|
|
|
|
const Color& viewColor = sortedViews[n].second; |
|
|
|
|
const float viewLuminance = MeshTexture::GetLuminance(viewColor); |
|
|
|
|
const float colorDistance = cv::norm(viewColor - medianColor); |
|
|
|
|
const float luminanceDistance = std::abs(viewLuminance - medianLuminance); |
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (validIndices.empty()) { |
|
|
|
|
virtualFaceData.quality = medianQuality; |
|
|
|
|
virtualFaceData.color = medianColor; |
|
|
|
|
} else { |
|
|
|
|
// 使用有效视图计算
|
|
|
|
|
if (!validViews.empty()) { |
|
|
|
|
float totalQuality2 = 0.0f; |
|
|
|
|
Color totalColor2 = Color(0,0,0); |
|
|
|
|
for (int idx : validIndices) { |
|
|
|
|
totalQuality2 += validViews[idx].first; |
|
|
|
|
totalColor2 += validViews[idx].second; |
|
|
|
|
for (const auto& v : validViews) { |
|
|
|
|
totalQuality2 += v.first; |
|
|
|
|
totalColor2 += v.second; |
|
|
|
|
} |
|
|
|
|
virtualFaceData.quality = totalQuality2 / validIndices.size(); |
|
|
|
|
virtualFaceData.color = totalColor2 / validIndices.size(); |
|
|
|
|
virtualFaceData.quality = totalQuality2 / validViews.size(); |
|
|
|
|
virtualFaceData.color = totalColor2 / validViews.size(); |
|
|
|
|
} else { |
|
|
|
|
// 回退到平均值
|
|
|
|
|
virtualFaceData.quality = avgQuality; |
|
|
|
|
virtualFaceData.color = avgColor; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|