|
|
|
|
@ -4360,7 +4360,6 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4360,7 +4360,6 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
if (angleDeg <= 45.0f) |
|
|
|
|
{ |
|
|
|
|
// filteredCams.push_back(idxView);
|
|
|
|
|
|
|
|
|
|
//*
|
|
|
|
|
float brightnessScore = CalculateBrightnessScore(imageData); // 亮度评分函数
|
|
|
|
|
float angleScore = 1.0f - (angleDeg / 45.0f); |
|
|
|
|
@ -4374,9 +4373,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4374,9 +4373,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
} |
|
|
|
|
qualityScore = std::max(0.0f, std::min(1.0f, qualityScore)); |
|
|
|
|
float overallScore = 0.5f * angleScore + 0.3f * brightnessScore + 0.2f * qualityScore; |
|
|
|
|
|
|
|
|
|
if (overallScore > 0.04f) { |
|
|
|
|
|
|
|
|
|
filteredCams.push_back(idxView); |
|
|
|
|
} |
|
|
|
|
//*/
|
|
|
|
|
@ -4400,9 +4397,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4400,9 +4397,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
} |
|
|
|
|
qualityScore = std::max(0.0f, std::min(1.0f, qualityScore)); |
|
|
|
|
float overallScore = 0.5f * angleScore + 0.3f * brightnessScore + 0.2f * qualityScore; |
|
|
|
|
|
|
|
|
|
if (overallScore > 0.02f) { |
|
|
|
|
|
|
|
|
|
filteredCams.push_back(idxView); |
|
|
|
|
} |
|
|
|
|
//*/
|
|
|
|
|
@ -4478,6 +4473,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4478,6 +4473,7 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
} |
|
|
|
|
} while (!currentVirtualFaceQueue.IsEmpty()); |
|
|
|
|
|
|
|
|
|
// compute virtual face quality and create virtual face
|
|
|
|
|
for (IIndex idxView: selectedCams) { |
|
|
|
|
FaceData& virtualFaceData = virtualFaceDatas.emplace_back(); |
|
|
|
|
virtualFaceData.quality = 0; |
|
|
|
|
@ -4485,30 +4481,218 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4485,30 +4481,218 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
virtualFaceData.color = Point3f::ZERO; |
|
|
|
|
#endif |
|
|
|
|
int invalidQuality = 0; |
|
|
|
|
Color invalidColor = Point3f::ZERO; |
|
|
|
|
unsigned processedFaces(0); |
|
|
|
|
bool bInvalidFacesRelative = false; |
|
|
|
|
int invalidCount = 0; |
|
|
|
|
for (FIndex fid : virtualFace) { |
|
|
|
|
const FaceDataArr& faceDatas = facesDatas[fid]; |
|
|
|
|
for (FaceData& faceData: faceDatas) { |
|
|
|
|
if (faceData.idxView == idxView) { |
|
|
|
|
virtualFaceData.quality += faceData.quality; |
|
|
|
|
|
|
|
|
|
int nViewCount = 0; |
|
|
|
|
if (faceData.idxView == idxView) |
|
|
|
|
{ |
|
|
|
|
for (const FaceData& fd : faceDatas) |
|
|
|
|
{ |
|
|
|
|
if ( faceData.bInvalidFacesRelative) |
|
|
|
|
{ |
|
|
|
|
++nViewCount; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// if (faceData.bInvalidFacesRelative)
|
|
|
|
|
if (bHasInvalidView) |
|
|
|
|
{ |
|
|
|
|
// invalidQuality += faceData.quality;
|
|
|
|
|
// #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA
|
|
|
|
|
// invalidColor += faceData.color;
|
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
|
|
++processedFaces; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// virtualFaceData.quality += faceData.quality;
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
virtualFaceData.color += faceData.color; |
|
|
|
|
// virtualFaceData.color += faceData.color;
|
|
|
|
|
#endif |
|
|
|
|
++processedFaces; |
|
|
|
|
if (faceData.bInvalidFacesRelative) |
|
|
|
|
++invalidCount; |
|
|
|
|
break; |
|
|
|
|
// break;
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float maxLuminance = 120.0f; |
|
|
|
|
float minLuminance = 90.0f; |
|
|
|
|
int validViewsSize = validViews.size(); |
|
|
|
|
// bHasInvalidView = true;
|
|
|
|
|
if (bHasInvalidView) |
|
|
|
|
{ |
|
|
|
|
// 使用鲁棒的统计方法计算颜色和亮度的中心值
|
|
|
|
|
const Color medianColor = ComputeMedianColorAndQuality(sortedViews).color; |
|
|
|
|
const float medianQuality = ComputeMedianColorAndQuality(sortedViews).quality; |
|
|
|
|
const float medianLuminance = ComputeMedianLuminance(sortedViews); |
|
|
|
|
|
|
|
|
|
// 计算颜色和亮度的绝对中位差(MAD)作为偏差阈值
|
|
|
|
|
const float colorMAD = ComputeColorMAD(sortedViews, medianColor); |
|
|
|
|
const float luminanceMAD = ComputeLuminanceMAD(sortedViews, medianLuminance); |
|
|
|
|
|
|
|
|
|
// 基于MAD设置动态阈值(3倍MAD是统计学上常用的异常值阈值)
|
|
|
|
|
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) |
|
|
|
|
{ |
|
|
|
|
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; |
|
|
|
|
// Check color similarity
|
|
|
|
|
const Color& centerColor = faceColors[virtualFaceCenterFaceID]; |
|
|
|
|
const Color& currentColor = faceColors[currentFaceId]; |
|
|
|
|
|
|
|
|
|
float colorDistance = cv::norm(centerColor - currentColor); |
|
|
|
|
// printf("1colorDistance=%f\n", colorDistance);
|
|
|
|
|
if (colorDistance > thMaxColorDeviation) { |
|
|
|
|
// printf("2colorDistance=%f\n", colorDistance);
|
|
|
|
|
bColorSimilarity = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// if ((cosFaceToCenter<dynamicCosTh) || !IsFaceVisible(facesDatas[currentFaceId], selectedCams))
|
|
|
|
|
if (cosFaceToCenter<dynamicCosTh) |
|
|
|
|
{ |
|
|
|
|
if (nInvalidViewCount<=2) |
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// if ((colorDistance <= 350.0f))
|
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
if (nInvalidViewCount<=2) |
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// if (bColorSimilarity)
|
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (validIndices.empty()) { |
|
|
|
|
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) |
|
|
|
|
{ |
|
|
|
|
// validIndices.push_back(n);
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (validIndices.empty()) { |
|
|
|
|
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 (luminanceDistance <= maxLuminanceDeviation) |
|
|
|
|
{ |
|
|
|
|
// validIndices.push_back(n);
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
ASSERT(processedFaces > 0); |
|
|
|
|
virtualFaceData.quality /= processedFaces; |
|
|
|
|
// virtualFaceData.quality /= processedFaces;
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
virtualFaceData.color /= processedFaces; |
|
|
|
|
// virtualFaceData.color /= processedFaces;
|
|
|
|
|
#endif |
|
|
|
|
virtualFaceData.bInvalidFacesRelative = (invalidCount > processedFaces / 2); |
|
|
|
|
|
|
|
|
|
virtualFaceData.quality = 0; |
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
virtualFaceData.color = Point3f::ZERO; |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// 使用鲁棒的统计方法计算颜色和亮度的中心值
|
|
|
|
|
const Color medianColor = ComputeMedianColorAndQuality(sortedViews).color; |
|
|
|
|
const float medianQuality = ComputeMedianColorAndQuality(sortedViews).quality; |
|
|
|
|
const float medianLuminance = ComputeMedianLuminance(sortedViews); |
|
|
|
|
|
|
|
|
|
// 计算颜色和亮度的绝对中位差(MAD)作为偏差阈值
|
|
|
|
|
const float colorMAD = ComputeColorMAD(sortedViews, medianColor); |
|
|
|
|
const float luminanceMAD = ComputeLuminanceMAD(sortedViews, medianLuminance); |
|
|
|
|
|
|
|
|
|
// 基于MAD设置动态阈值(3倍MAD是统计学上常用的异常值阈值)
|
|
|
|
|
const float maxColorDeviation = 0.01f * colorMAD; |
|
|
|
|
// const float maxLuminanceDeviation = 0.01f * luminanceMAD;
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
// if (colorDistance <= maxColorDeviation &&
|
|
|
|
|
// luminanceDistance <= maxLuminanceDeviation)
|
|
|
|
|
// if (luminanceDistance <= maxLuminanceDeviation)
|
|
|
|
|
{ |
|
|
|
|
validIndices.push_back(n); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (validIndices.empty()) { |
|
|
|
|
|
|
|
|
|
virtualFaceData.quality = medianQuality; |
|
|
|
|
virtualFaceData.color = medianColor; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
// 使用过滤后的视图重新计算平均值
|
|
|
|
|
float totalQuality2 = 0.0f; |
|
|
|
|
Color totalColor2 = Color(0,0,0); |
|
|
|
|
for (int idx : validIndices) { |
|
|
|
|
totalQuality2 += validViews[idx].first; |
|
|
|
|
totalColor2 += validViews[idx].second; |
|
|
|
|
} |
|
|
|
|
virtualFaceData.quality = totalQuality2 / validIndices.size(); |
|
|
|
|
virtualFaceData.color = totalColor2 / validIndices.size(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// virtualFaceData.bInvalidFacesRelative = (invalidCount > 1);
|
|
|
|
|
// virtualFaceData.bInvalidFacesRelative = (invalidCount > processedFaces * 2 / 3);
|
|
|
|
|
} |
|
|
|
|
ASSERT(!virtualFaceDatas.empty()); |
|
|
|
|
} |
|
|
|
|
|