算法优化
This commit is contained in:
1 parent
03929e5b95
commit
3693365bdf
1 file changed
+377
@@ -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 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 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);
|
||||
float CalculateBrightnessScore(const Image& imageData) 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
|
||||
{
|
||||
if (meshCurvatures.empty()) {
|
||||
@@ -7245,6 +7621,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT
|
||||
// CreateVirtualFaces6(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
||||
// CreateVirtualFaces61(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
||||
CreateVirtualFaces62(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
||||
// CreateVirtualFaces63(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
||||
TD_TIMER_STARTD();
|
||||
// CreateVirtualFaces7(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
||||
DEBUG_EXTRA("CreateVirtualFaces completed: %s", TD_TIMER_GET_FMT().c_str());
|
||||
|
||||
Reference in new issue
Block a user