|
|
|
@ -461,6 +461,7 @@ public: |
|
|
|
bool CreateVirtualFaces6(FaceDataViewArr& facesDatas, FaceDataViewArr& ComputeAverageQuality, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; |
|
|
|
bool CreateVirtualFaces6(FaceDataViewArr& facesDatas, FaceDataViewArr& ComputeAverageQuality, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; |
|
|
|
bool CreateVirtualFaces61(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f); |
|
|
|
bool CreateVirtualFaces61(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f); |
|
|
|
bool CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataViewArr& ComputeAverageQuality, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; |
|
|
|
bool CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataViewArr& ComputeAverageQuality, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; |
|
|
|
|
|
|
|
bool CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras=2, float thMaxNormalDeviation=25.f) const; |
|
|
|
static std::string GetFileNameWithoutExtension(std::string& strPath); |
|
|
|
static std::string GetFileNameWithoutExtension(std::string& strPath); |
|
|
|
float CalculateBrightnessScore(const Image& imageData) const; |
|
|
|
float CalculateBrightnessScore(const Image& imageData) const; |
|
|
|
bool IsFaceVisibleRelaxed(const FaceDataArr& faceDatas, const IIndexArr& selectedCams, float visibleRatioThreshold) const; |
|
|
|
bool IsFaceVisibleRelaxed(const FaceDataArr& faceDatas, const IIndexArr& selectedCams, float visibleRatioThreshold) const; |
|
|
|
@ -4305,6 +4306,381 @@ std::string MeshTexture::GetFileNameWithoutExtension(std::string& strPath) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool MeshTexture::CreateVirtualFaces63(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras, float thMaxNormalDeviation) const |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (meshCurvatures.empty()) { |
|
|
|
|
|
|
|
ComputeFaceCurvatures(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float thMaxColorDeviation = 130.0f; |
|
|
|
|
|
|
|
const float QUALITY_THRESHOLD = 0.9f; // 质量阈值,可根据实际情况调整
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const float ratioAngleToQuality(0.67f); |
|
|
|
|
|
|
|
const float cosMaxNormalDeviation(COS(FD2R(thMaxNormalDeviation))); |
|
|
|
|
|
|
|
Mesh::FaceIdxArr remainingFaces(faces.size()); |
|
|
|
|
|
|
|
std::iota(remainingFaces.begin(), remainingFaces.end(), 0); |
|
|
|
|
|
|
|
std::vector<bool> selectedFaces(faces.size(), false); |
|
|
|
|
|
|
|
cQueue<FIndex, FIndex, 0> currentVirtualFaceQueue; |
|
|
|
|
|
|
|
std::unordered_set<FIndex> queuedFaces; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Precompute average color for each face
|
|
|
|
|
|
|
|
Colors faceColors; |
|
|
|
|
|
|
|
faceColors.reserve(faces.size()); |
|
|
|
|
|
|
|
for (size_t i = 0; i < faces.size(); ++i) { |
|
|
|
|
|
|
|
faceColors.push_back(Color::ZERO); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (FIndex idxFace = 0; idxFace < faces.size(); ++idxFace) { |
|
|
|
|
|
|
|
const FaceDataArr& faceDatas = facesDatas[idxFace]; |
|
|
|
|
|
|
|
if (faceDatas.empty()) continue; |
|
|
|
|
|
|
|
Color sumColor = Color::ZERO; |
|
|
|
|
|
|
|
for (const FaceData& fd : faceDatas) { |
|
|
|
|
|
|
|
sumColor += fd.color; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
faceColors[idxFace] = sumColor / faceDatas.size(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
|
|
|
const FIndex startPos = RAND() % remainingFaces.size(); |
|
|
|
|
|
|
|
const FIndex virtualFaceCenterFaceID = remainingFaces[startPos]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 动态法线阈值
|
|
|
|
|
|
|
|
const float centerCurvature = meshCurvatures[virtualFaceCenterFaceID]; |
|
|
|
|
|
|
|
const float dynamicThreshold = (centerCurvature < 0.2f) ? 15.0f : 8.0f; |
|
|
|
|
|
|
|
const float dynamicCosTh = COS(FD2R(dynamicThreshold)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASSERT(currentVirtualFaceQueue.IsEmpty()); |
|
|
|
|
|
|
|
const Normal& normalCenter = scene.mesh.faceNormals[virtualFaceCenterFaceID]; |
|
|
|
|
|
|
|
const FaceDataArr& centerFaceDatas = facesDatas[virtualFaceCenterFaceID]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查中心面片是否包含无效视图
|
|
|
|
|
|
|
|
bool bHasInvalidView = false; |
|
|
|
|
|
|
|
int nInvalidViewCount = 0; |
|
|
|
|
|
|
|
int nTotalViewCount = 0; |
|
|
|
|
|
|
|
for (const FaceData& faceData : centerFaceDatas) { |
|
|
|
|
|
|
|
if (faceData.bInvalidFacesRelative) { |
|
|
|
|
|
|
|
bHasInvalidView = true; |
|
|
|
|
|
|
|
++nInvalidViewCount; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
++nTotalViewCount; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算中心面片的质量
|
|
|
|
|
|
|
|
float centerFaceQuality = 0.0f; |
|
|
|
|
|
|
|
int validViewCount = 0; |
|
|
|
|
|
|
|
for (const FaceData& fd : centerFaceDatas) { |
|
|
|
|
|
|
|
if (!fd.bInvalidFacesRelative) { |
|
|
|
|
|
|
|
centerFaceQuality += fd.quality; |
|
|
|
|
|
|
|
++validViewCount; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (validViewCount > 0) { |
|
|
|
|
|
|
|
centerFaceQuality /= validViewCount; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::pair<float, Color>> sortedViews; |
|
|
|
|
|
|
|
std::vector<std::pair<float, Color>> sortedLuminViews; |
|
|
|
|
|
|
|
std::vector<std::pair<float, Color>> validViews; |
|
|
|
|
|
|
|
sortedViews.reserve(centerFaceDatas.size()); |
|
|
|
|
|
|
|
for (const FaceData& fd : centerFaceDatas) { |
|
|
|
|
|
|
|
if (fd.bInvalidFacesRelative) { |
|
|
|
|
|
|
|
sortedViews.emplace_back(fd.quality, fd.color); |
|
|
|
|
|
|
|
sortedLuminViews.emplace_back(MeshTexture::GetLuminance(fd.color), fd.color); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
sortedViews.emplace_back(fd.quality, fd.color); |
|
|
|
|
|
|
|
sortedLuminViews.emplace_back(MeshTexture::GetLuminance(fd.color), fd.color); |
|
|
|
|
|
|
|
validViews.emplace_back(fd.quality, fd.color); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
std::sort(sortedViews.begin(), sortedViews.end(), |
|
|
|
|
|
|
|
[](const auto& a, const auto& b) { return a.first > b.first; }); |
|
|
|
|
|
|
|
std::sort(validViews.begin(), validViews.end(), |
|
|
|
|
|
|
|
[](const auto& a, const auto& b) { return a.first > b.first; }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int nSize = sortedViews.size(); |
|
|
|
|
|
|
|
float totalQuality = 0.0f; |
|
|
|
|
|
|
|
Color totalColor(0,0,0); |
|
|
|
|
|
|
|
for (int n = 0; n < nSize; ++n) { |
|
|
|
|
|
|
|
totalQuality += sortedViews[n].first; |
|
|
|
|
|
|
|
totalColor += sortedViews[n].second; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const float avgQuality = totalQuality / nSize; |
|
|
|
|
|
|
|
const Color avgColor = totalColor / nSize; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float totalLuminance = MeshTexture::GetLuminance(totalColor); |
|
|
|
|
|
|
|
float avgLuminance = totalLuminance / nSize; |
|
|
|
|
|
|
|
std::sort(sortedLuminViews.begin(), sortedLuminViews.end(), |
|
|
|
|
|
|
|
[avgLuminance](const auto& a, const auto& b) { |
|
|
|
|
|
|
|
float luminDistA = cv::norm(avgLuminance - a.first); |
|
|
|
|
|
|
|
float luminDistB = cv::norm(avgLuminance - b.first); |
|
|
|
|
|
|
|
return luminDistA < luminDistB; }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// select the common cameras
|
|
|
|
|
|
|
|
Mesh::FaceIdxArr virtualFace; |
|
|
|
|
|
|
|
FaceDataArr virtualFaceDatas; |
|
|
|
|
|
|
|
if (centerFaceDatas.empty()) { |
|
|
|
|
|
|
|
virtualFace.emplace_back(virtualFaceCenterFaceID); |
|
|
|
|
|
|
|
selectedFaces[virtualFaceCenterFaceID] = true; |
|
|
|
|
|
|
|
const auto posToErase = remainingFaces.FindFirst(virtualFaceCenterFaceID); |
|
|
|
|
|
|
|
ASSERT(posToErase != Mesh::FaceIdxArr::NO_INDEX); |
|
|
|
|
|
|
|
remainingFaces.RemoveAtMove(posToErase); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
IIndexArr selectedCams = SelectBestViews(centerFaceDatas, virtualFaceCenterFaceID, minCommonCameras, ratioAngleToQuality); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Normal& normalCenter = scene.mesh.faceNormals[virtualFaceCenterFaceID]; |
|
|
|
|
|
|
|
std::vector<std::pair<IIndex, float>> cameraAngles; // 存储相机索引和角度
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (IIndex idxView : selectedCams) { |
|
|
|
|
|
|
|
const Image& imageData = images[idxView]; |
|
|
|
|
|
|
|
const RMatrix& R = imageData.camera.R; |
|
|
|
|
|
|
|
Point3f localForward(0.0f, 0.0f, -1.0f); |
|
|
|
|
|
|
|
Point3f cameraForward; |
|
|
|
|
|
|
|
cameraForward.x = R(0,0) * localForward.x + R(0,1) * localForward.y + R(0,2) * localForward.z; |
|
|
|
|
|
|
|
cameraForward.y = R(1,0) * localForward.x + R(1,1) * localForward.y + R(1,2) * localForward.z; |
|
|
|
|
|
|
|
cameraForward.z = R(2,0) * localForward.x + R(2,1) * localForward.y + R(2,2) * localForward.z; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float norm = std::sqrt(cameraForward.x * cameraForward.x + |
|
|
|
|
|
|
|
cameraForward.y * cameraForward.y + |
|
|
|
|
|
|
|
cameraForward.z * cameraForward.z); |
|
|
|
|
|
|
|
if (norm > 0.0f) { |
|
|
|
|
|
|
|
cameraForward.x /= norm; |
|
|
|
|
|
|
|
cameraForward.y /= norm; |
|
|
|
|
|
|
|
cameraForward.z /= norm; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
cameraForward = Point3f(0, 0, -1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Point3f normalPoint(normalCenter.x, normalCenter.y, normalCenter.z); |
|
|
|
|
|
|
|
float cosAngle = cameraForward.dot(normalPoint); |
|
|
|
|
|
|
|
float angleDeg = std::acos(cosAngle) * 180.0f / M_PI; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string strPath = imageData.name; |
|
|
|
|
|
|
|
std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!scene.is_face_delete_edge(strName, virtualFaceCenterFaceID)) { |
|
|
|
|
|
|
|
if (scene.is_face_edge(strName, virtualFaceCenterFaceID)) { |
|
|
|
|
|
|
|
if (angleDeg <= 40.0f) { |
|
|
|
|
|
|
|
cameraAngles.emplace_back(idxView, angleDeg); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
cameraAngles.emplace_back(idxView, angleDeg); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 按angleDeg从小到大排序
|
|
|
|
|
|
|
|
std::sort(cameraAngles.begin(), cameraAngles.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); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (filteredCams.empty()) { |
|
|
|
|
|
|
|
selectedCams = filteredCams; |
|
|
|
|
|
|
|
isVirtualFace[virtualFaceCenterFaceID] = false; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
selectedCams = filteredCams; |
|
|
|
|
|
|
|
isVirtualFace[virtualFaceCenterFaceID] = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
currentVirtualFaceQueue.AddTail(virtualFaceCenterFaceID); |
|
|
|
|
|
|
|
queuedFaces.clear(); |
|
|
|
|
|
|
|
do { |
|
|
|
|
|
|
|
const FIndex currentFaceId = currentVirtualFaceQueue.GetHead(); |
|
|
|
|
|
|
|
currentVirtualFaceQueue.PopHead(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Normal& faceNormal = scene.mesh.faceNormals[currentFaceId]; |
|
|
|
|
|
|
|
const float cosFaceToCenter(ComputeAngleN(normalCenter.ptr(), faceNormal.ptr())); |
|
|
|
|
|
|
|
if (cosFaceToCenter < dynamicCosTh) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASSERT(!selectedCams.empty()); |
|
|
|
|
|
|
|
if (!IsFaceVisible(facesDatas[currentFaceId], selectedCams)) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Color& centerColor = faceColors[virtualFaceCenterFaceID]; |
|
|
|
|
|
|
|
const Color& currentColor = faceColors[currentFaceId]; |
|
|
|
|
|
|
|
float colorDistance = cv::norm(centerColor - currentColor); |
|
|
|
|
|
|
|
if (colorDistance > 200.0f) { |
|
|
|
|
|
|
|
// continue; // 可选:如果颜色差异太大,跳过
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (colorDistance > thMaxColorDeviation) { |
|
|
|
|
|
|
|
// continue; // 可选:如果颜色差异太大,跳过
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
const auto posToErase = remainingFaces.FindFirst(currentFaceId); |
|
|
|
|
|
|
|
ASSERT(posToErase != Mesh::FaceIdxArr::NO_INDEX); |
|
|
|
|
|
|
|
remainingFaces.RemoveAtMove(posToErase); |
|
|
|
|
|
|
|
selectedFaces[currentFaceId] = true; |
|
|
|
|
|
|
|
virtualFace.push_back(currentFaceId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Mesh::FaceFaces& ffaces = faceFaces[currentFaceId]; |
|
|
|
|
|
|
|
for (int i = 0; i < 3; ++i) { |
|
|
|
|
|
|
|
const FIndex fIdx = ffaces[i]; |
|
|
|
|
|
|
|
if (fIdx == NO_ID) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
if (!selectedFaces[fIdx] && queuedFaces.find(fIdx) == queuedFaces.end()) { |
|
|
|
|
|
|
|
currentVirtualFaceQueue.AddTail(fIdx); |
|
|
|
|
|
|
|
queuedFaces.emplace(fIdx); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} while (!currentVirtualFaceQueue.IsEmpty()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算虚拟面质量并创建虚拟面
|
|
|
|
|
|
|
|
for (IIndex idxView: selectedCams) { |
|
|
|
|
|
|
|
FaceData& virtualFaceData = virtualFaceDatas.emplace_back(); |
|
|
|
|
|
|
|
virtualFaceData.quality = 0; |
|
|
|
|
|
|
|
virtualFaceData.idxView = idxView; |
|
|
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
|
|
|
virtualFaceData.color = Point3f::ZERO; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Image& imageData = images[idxView]; |
|
|
|
|
|
|
|
std::string strPath = imageData.name; |
|
|
|
|
|
|
|
std::string strName = MeshTexture::GetFileNameWithoutExtension(strPath); |
|
|
|
|
|
|
|
int invalidQuality = 0; |
|
|
|
|
|
|
|
Color invalidColor = Point3f::ZERO; |
|
|
|
|
|
|
|
unsigned processedFaces(0); |
|
|
|
|
|
|
|
int invalidCount = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (FIndex fid : virtualFace) { |
|
|
|
|
|
|
|
const FaceDataArr& faceDatas = facesDatas[fid]; |
|
|
|
|
|
|
|
for (FaceData& faceData: faceDatas) { |
|
|
|
|
|
|
|
int nViewCount = 0; |
|
|
|
|
|
|
|
if (faceData.idxView == idxView) { |
|
|
|
|
|
|
|
for (const FaceData& fd : faceDatas) { |
|
|
|
|
|
|
|
if (faceData.bInvalidFacesRelative) { |
|
|
|
|
|
|
|
++nViewCount; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (bHasInvalidView) { |
|
|
|
|
|
|
|
++processedFaces; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
++processedFaces; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
} 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 { |
|
|
|
|
|
|
|
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(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ASSERT(!virtualFaceDatas.empty()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
virtualFacesDatas.emplace_back(std::move(virtualFaceDatas)); |
|
|
|
|
|
|
|
virtualFaces.emplace_back(std::move(virtualFace)); |
|
|
|
|
|
|
|
} while (!remainingFaces.empty()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras, float thMaxNormalDeviation) const |
|
|
|
bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataViewArr& virtualFacesDatas, VirtualFaceIdxsArr& virtualFaces, std::vector<bool>& isVirtualFace, unsigned minCommonCameras, float thMaxNormalDeviation) const |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (meshCurvatures.empty()) { |
|
|
|
if (meshCurvatures.empty()) { |
|
|
|
@ -7245,6 +7621,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT |
|
|
|
// CreateVirtualFaces6(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
|
|
|
// CreateVirtualFaces6(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
|
|
|
// CreateVirtualFaces61(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
|
|
|
// CreateVirtualFaces61(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
|
|
|
CreateVirtualFaces62(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); |
|
|
|
CreateVirtualFaces62(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); |
|
|
|
|
|
|
|
// CreateVirtualFaces63(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
|
|
|
TD_TIMER_STARTD(); |
|
|
|
TD_TIMER_STARTD(); |
|
|
|
// CreateVirtualFaces7(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
|
|
|
// CreateVirtualFaces7(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
|
|
|
DEBUG_EXTRA("CreateVirtualFaces completed: %s", TD_TIMER_GET_FMT().c_str()); |
|
|
|
DEBUG_EXTRA("CreateVirtualFaces completed: %s", TD_TIMER_GET_FMT().c_str()); |
|
|
|
|