Compare commits
45
Commits
master
..
81036ad095
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81036ad095 | ||
|
|
ff7b75d219 | ||
|
|
b0c165499c | ||
|
|
3adc1c012a | ||
|
|
93ee28a3ca | ||
|
|
6922abe692 | ||
|
|
5229b4f284 | ||
|
|
d95c2fc8ff | ||
|
|
29388cf341 | ||
|
|
42f6d9c84c | ||
|
|
82c019ee49 | ||
|
|
46d5d65b3f | ||
|
|
93e7d60416 | ||
|
|
680c34242a | ||
|
|
4a9013f12f | ||
|
|
0d816514fa | ||
|
|
ddb42d08f4 | ||
|
|
7a6887349e | ||
|
|
c70d56d3cb | ||
|
|
f831f93361 | ||
|
|
0e1b02cda5 | ||
|
|
5e59d7c60b | ||
|
|
c38456c7b4 | ||
|
|
3843bea5f6 | ||
|
|
992439bc44 | ||
|
|
4105129a7d | ||
|
|
8529835712 | ||
|
|
e2c5313fdd | ||
|
|
c9d1eac96a | ||
|
|
0dceffb66f | ||
|
|
f787e874aa | ||
|
|
01ef0f2a1d | ||
|
|
d82e3f491a | ||
|
|
811f85bbbd | ||
|
|
80c0dcbb49 | ||
|
|
1b93beb86a | ||
|
|
84a492600f | ||
|
|
0f24212b87 | ||
|
|
6271fb3af0 | ||
|
|
7747494618 | ||
|
|
aadfbb4b08 | ||
|
|
e1258c2d3e | ||
|
|
c70d12b645 | ||
|
|
7fd81ffbea | ||
|
|
5e1623e303 |
No files matched your search
@@ -7,7 +7,6 @@
|
|||||||
# Precompiled Headers
|
# Precompiled Headers
|
||||||
*.gch
|
*.gch
|
||||||
*.pch
|
*.pch
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Compiled Dynamic libraries
|
# Compiled Dynamic libraries
|
||||||
*.so
|
*.so
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ ENDIF()
|
|||||||
PROJECT(OpenMVS)
|
PROJECT(OpenMVS)
|
||||||
|
|
||||||
SET(ENV_PYTHON_PATH "/home/algo/.conda/envs/py310_pyt210/lib/python3.10/site-packages")
|
SET(ENV_PYTHON_PATH "/home/algo/.conda/envs/py310_pyt210/lib/python3.10/site-packages")
|
||||||
SET(ENV_MVS_PATH "/home/algo/Documents/openMVS/openMVS/libs/MVS")
|
SET(ENV_MVS_PATH "/home/algo/Documents/openMVS/openMVS.ManualUV/libs/MVS")
|
||||||
|
|
||||||
CONFIGURE_FILE(
|
CONFIGURE_FILE(
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/build/Templates/ConfigEnv.h.in"
|
"${CMAKE_CURRENT_SOURCE_DIR}/build/Templates/ConfigEnv.h.in"
|
||||||
|
|||||||
@@ -94,6 +94,9 @@ unsigned nMaxThreads;
|
|||||||
int nMaxTextureSize;
|
int nMaxTextureSize;
|
||||||
String strExportType;
|
String strExportType;
|
||||||
String strConfigFileName;
|
String strConfigFileName;
|
||||||
|
bool bUseExistingUV;
|
||||||
|
String strUVMeshFileName;
|
||||||
|
|
||||||
boost::program_options::variables_map vm;
|
boost::program_options::variables_map vm;
|
||||||
} // namespace OPT
|
} // namespace OPT
|
||||||
|
|
||||||
@@ -163,6 +166,8 @@ bool Application::Initialize(size_t argc, LPCTSTR* argv)
|
|||||||
("image-folder", boost::program_options::value<std::string>(&OPT::strImageFolder)->default_value(COLMAP_IMAGES_FOLDER), "folder to the undistorted images")
|
("image-folder", boost::program_options::value<std::string>(&OPT::strImageFolder)->default_value(COLMAP_IMAGES_FOLDER), "folder to the undistorted images")
|
||||||
("origin-faceview", boost::program_options::value(&OPT::bOriginFaceview)->default_value(false), "use origin faceview selection")
|
("origin-faceview", boost::program_options::value(&OPT::bOriginFaceview)->default_value(false), "use origin faceview selection")
|
||||||
("id", boost::program_options::value(&OPT::nID)->default_value(0), "id")
|
("id", boost::program_options::value(&OPT::nID)->default_value(0), "id")
|
||||||
|
("use-existing-uv", boost::program_options::value(&OPT::bUseExistingUV)->default_value(false), "use existing UV coordinates from the input mesh")
|
||||||
|
("uv-mesh-file", boost::program_options::value<std::string>(&OPT::strUVMeshFileName), "mesh file with pre-computed UV coordinates")
|
||||||
;
|
;
|
||||||
|
|
||||||
// hidden options, allowed both on command line and
|
// hidden options, allowed both on command line and
|
||||||
@@ -1134,12 +1139,12 @@ int main(int argc, LPCTSTR* argv)
|
|||||||
if (!scene.TextureMesh(OPT::nResolutionLevel, OPT::nMinResolution, OPT::minCommonCameras, OPT::fOutlierThreshold, OPT::fRatioDataSmoothness,
|
if (!scene.TextureMesh(OPT::nResolutionLevel, OPT::nMinResolution, OPT::minCommonCameras, OPT::fOutlierThreshold, OPT::fRatioDataSmoothness,
|
||||||
OPT::bGlobalSeamLeveling, OPT::bLocalSeamLeveling, OPT::nTextureSizeMultiple, OPT::nRectPackingHeuristic, Pixel8U(OPT::nColEmpty),
|
OPT::bGlobalSeamLeveling, OPT::bLocalSeamLeveling, OPT::nTextureSizeMultiple, OPT::nRectPackingHeuristic, Pixel8U(OPT::nColEmpty),
|
||||||
OPT::fSharpnessWeight, OPT::nIgnoreMaskLabel, OPT::nMaxTextureSize, views, baseFileName, OPT::bOriginFaceview,
|
OPT::fSharpnessWeight, OPT::nIgnoreMaskLabel, OPT::nMaxTextureSize, views, baseFileName, OPT::bOriginFaceview,
|
||||||
OPT::strInputFileName, OPT::strMeshFileName))
|
OPT::strInputFileName, OPT::strMeshFileName, OPT::bUseExistingUV, OPT::strUVMeshFileName))
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
VERBOSE("Mesh texturing completed: %u vertices, %u faces (%s)", scene.mesh.vertices.GetSize(), scene.mesh.faces.GetSize(), TD_TIMER_GET_FMT().c_str());
|
VERBOSE("Mesh texturing completed: %u vertices, %u faces (%s)", scene.mesh.vertices.GetSize(), scene.mesh.faces.GetSize(), TD_TIMER_GET_FMT().c_str());
|
||||||
|
|
||||||
// save the final mesh
|
// save the final mesh
|
||||||
scene.mesh.Save(baseFileName+OPT::strExportType);
|
scene.mesh.Save(baseFileName+OPT::strExportType,cList<String>(),true,OPT::bUseExistingUV);
|
||||||
#if TD_VERBOSE != TD_VERBOSE_OFF
|
#if TD_VERBOSE != TD_VERBOSE_OFF
|
||||||
if (VERBOSITY_LEVEL > 2)
|
if (VERBOSITY_LEVEL > 2)
|
||||||
scene.ExportCamerasMLP(baseFileName+_T(".mlp"), baseFileName+OPT::strExportType);
|
scene.ExportCamerasMLP(baseFileName+_T(".mlp"), baseFileName+OPT::strExportType);
|
||||||
|
|||||||
+508
-848
File diff suppressed because it is too large.
Load diff
+128
-1
@@ -48,6 +48,7 @@ ObjModel::MaterialLib::MaterialLib()
|
|||||||
|
|
||||||
bool ObjModel::MaterialLib::Save(const String& prefix, bool texLossless) const
|
bool ObjModel::MaterialLib::Save(const String& prefix, bool texLossless) const
|
||||||
{
|
{
|
||||||
|
DEBUG_EXTRA("MaterialLib::Save %s", prefix.c_str());
|
||||||
std::ofstream out((prefix+".mtl").c_str());
|
std::ofstream out((prefix+".mtl").c_str());
|
||||||
if (!out.good())
|
if (!out.good())
|
||||||
return false;
|
return false;
|
||||||
@@ -130,7 +131,7 @@ bool ObjModel::MaterialLib::Load(const String& fileName)
|
|||||||
|
|
||||||
// S T R U C T S ///////////////////////////////////////////////////
|
// S T R U C T S ///////////////////////////////////////////////////
|
||||||
|
|
||||||
bool ObjModel::Save(const String& fileName, unsigned precision, bool texLossless) const
|
bool ObjModel::Save(const String& fileName, unsigned precision, bool texLossless, bool bUseExistingUV) const
|
||||||
{
|
{
|
||||||
if (vertices.empty())
|
if (vertices.empty())
|
||||||
return false;
|
return false;
|
||||||
@@ -140,6 +141,9 @@ bool ObjModel::Save(const String& fileName, unsigned precision, bool texLossless
|
|||||||
if (!material_lib.Save(prefix, texLossless))
|
if (!material_lib.Save(prefix, texLossless))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (bUseExistingUV)
|
||||||
|
return true;
|
||||||
|
|
||||||
std::ofstream out((prefix + ".obj").c_str());
|
std::ofstream out((prefix + ".obj").c_str());
|
||||||
if (!out.good())
|
if (!out.good())
|
||||||
return false;
|
return false;
|
||||||
@@ -269,6 +273,129 @@ bool ObjModel::Load(const String& fileName)
|
|||||||
return !vertices.empty();
|
return !vertices.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ObjModel::LoadUV(const String& fileName, SEACAVE::cList<TexCoord,const TexCoord&,0,8192,uint32_t> &faceTexcoords, bool bLoadUV)
|
||||||
|
{
|
||||||
|
DEBUG_EXTRA("LoadUV bLoadUV=%b", bLoadUV);
|
||||||
|
ASSERT(vertices.empty() && groups.empty() && material_lib.materials.empty());
|
||||||
|
std::ifstream fin(fileName.c_str());
|
||||||
|
String line, keyword;
|
||||||
|
std::istringstream in;
|
||||||
|
|
||||||
|
while (fin.good()) {
|
||||||
|
std::getline(fin, line);
|
||||||
|
if (line.empty() || line[0u] == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
in.str(line);
|
||||||
|
in >> keyword;
|
||||||
|
|
||||||
|
if (keyword == "v") {
|
||||||
|
Vertex v;
|
||||||
|
in >> v[0] >> v[1] >> v[2];
|
||||||
|
if (in.fail())
|
||||||
|
{
|
||||||
|
DEBUG_EXTRA("1");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
vertices.push_back(v);
|
||||||
|
// DEBUG_EXTRA("10, %d", vertices.size());
|
||||||
|
} else if (keyword == "vt") {
|
||||||
|
TexCoord vt;
|
||||||
|
in >> vt[0] >> vt[1];
|
||||||
|
if (in.fail())
|
||||||
|
{
|
||||||
|
DEBUG_EXTRA("2");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
texcoords.push_back(vt);
|
||||||
|
} else if (keyword == "vn") {
|
||||||
|
Normal vn;
|
||||||
|
in >> vn[0] >> vn[1] >> vn[2];
|
||||||
|
if (in.fail())
|
||||||
|
{
|
||||||
|
DEBUG_EXTRA("3");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
normals.push_back(vn);
|
||||||
|
} else if (keyword == "f") {
|
||||||
|
Face f;
|
||||||
|
memset(&f, 0xFF, sizeof(Face));
|
||||||
|
|
||||||
|
for (size_t k = 0; k < 3; ++k) {
|
||||||
|
in >> keyword;
|
||||||
|
|
||||||
|
// 更健壮的解析方法,处理各种索引格式
|
||||||
|
std::vector<String> parts;
|
||||||
|
size_t start = 0, end = 0;
|
||||||
|
|
||||||
|
// 按'/'分割字符串
|
||||||
|
while ((end = keyword.find('/', start)) != String::npos) {
|
||||||
|
parts.push_back(keyword.substr(start, end - start));
|
||||||
|
start = end + 1;
|
||||||
|
}
|
||||||
|
parts.push_back(keyword.substr(start));
|
||||||
|
|
||||||
|
// 根据分割后的部分数量处理不同情况
|
||||||
|
if (parts.size() >= 1 && !parts[0].empty()) {
|
||||||
|
f.vertices[k] = std::stoi(parts[0]) - OBJ_INDEX_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.size() >= 2 && !parts[1].empty()) {
|
||||||
|
f.texcoords[k] = std::stoi(parts[1]) - OBJ_INDEX_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.size() >= 3 && !parts[2].empty()) {
|
||||||
|
f.normals[k] = std::stoi(parts[2]) - OBJ_INDEX_OFFSET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in.fail())
|
||||||
|
{
|
||||||
|
DEBUG_EXTRA("4");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bLoadUV)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
if (f.texcoords[i] != NO_ID && f.texcoords[i] < texcoords.size()) {
|
||||||
|
faceTexcoords.push_back(texcoords[f.texcoords[i]]);
|
||||||
|
} else {
|
||||||
|
// 索引无效(例如面定义中未提供vt索引或索引越界),使用默认值
|
||||||
|
faceTexcoords.push_back(Point2f(0.0f, 0.0f)); // 默认UV
|
||||||
|
DEBUG_EXTRA("Invalid texcoords %d", f.texcoords[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG_EXTRA("faceTexcoords push_back [(%f,%f),(%f,%f),(%f,%f)]", texcoords[f.texcoords[0]].x, texcoords[f.texcoords[0]].y,
|
||||||
|
// texcoords[f.texcoords[1]].x, texcoords[f.texcoords[1]].y, texcoords[f.texcoords[2]].x, texcoords[f.texcoords[2]].y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groups.empty())
|
||||||
|
AddGroup("");
|
||||||
|
groups.back().faces.push_back(f);
|
||||||
|
// } else if (keyword == "mtllib") {
|
||||||
|
// in >> keyword;
|
||||||
|
// if (!material_lib.Load(keyword))
|
||||||
|
// DEBUG_EXTRA("3");
|
||||||
|
// return false;
|
||||||
|
} else if (keyword == "usemtl") {
|
||||||
|
Group group;
|
||||||
|
in >> group.material_name;
|
||||||
|
if (in.fail())
|
||||||
|
{
|
||||||
|
DEBUG_EXTRA("5");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
groups.push_back(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
in.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_EXTRA("6, vertices.size=%d, faceTexcoords.size=%d", vertices.size(), faceTexcoords.size());
|
||||||
|
return !vertices.empty();
|
||||||
|
}
|
||||||
|
|
||||||
ObjModel::Group& ObjModel::AddGroup(const String& material_name)
|
ObjModel::Group& ObjModel::AddGroup(const String& material_name)
|
||||||
{
|
{
|
||||||
|
|||||||
+2
-1
@@ -93,9 +93,10 @@ public:
|
|||||||
ObjModel() {}
|
ObjModel() {}
|
||||||
|
|
||||||
// Saves the obj model to an .obj file, its material lib and the materials with the given file name
|
// Saves the obj model to an .obj file, its material lib and the materials with the given file name
|
||||||
bool Save(const String& fileName, unsigned precision=6, bool texLossless=false) const;
|
bool Save(const String& fileName, unsigned precision=6, bool texLossless=false, bool bUseExistingUV=false) const;
|
||||||
// Loads the obj model from an .obj file, its material lib and the materials with the given file name
|
// Loads the obj model from an .obj file, its material lib and the materials with the given file name
|
||||||
bool Load(const String& fileName);
|
bool Load(const String& fileName);
|
||||||
|
bool LoadUV(const String& fileName, SEACAVE::cList<TexCoord,const TexCoord&,0,8192,uint32_t> &faceTexcoords, bool bLoadUV = false);
|
||||||
|
|
||||||
// Creates a new group with the given material name
|
// Creates a new group with the given material name
|
||||||
Group& AddGroup(const String& material_name);
|
Group& AddGroup(const String& material_name);
|
||||||
|
|||||||
+62
-12
@@ -1191,15 +1191,14 @@ namespace BasicPLY {
|
|||||||
} // namespace MeshInternal
|
} // namespace MeshInternal
|
||||||
|
|
||||||
// import the mesh from the given file
|
// import the mesh from the given file
|
||||||
bool Mesh::Load(const String& fileName)
|
bool Mesh::Load(const String& fileName, bool bLoadUV)
|
||||||
{
|
{
|
||||||
TD_TIMER_STARTD();
|
TD_TIMER_STARTD();
|
||||||
const String ext(Util::getFileExt(fileName).ToLower());
|
const String ext(Util::getFileExt(fileName).ToLower());
|
||||||
bool ret;
|
bool ret;
|
||||||
if (ext == _T(".obj"))
|
if (ext == _T(".obj"))
|
||||||
ret = LoadOBJ(fileName);
|
ret = LoadOBJ(fileName, bLoadUV);
|
||||||
else
|
else if (ext == _T(".gltf") || ext == _T(".glb"))
|
||||||
if (ext == _T(".gltf") || ext == _T(".glb"))
|
|
||||||
ret = LoadGLTF(fileName, ext == _T(".glb"));
|
ret = LoadGLTF(fileName, ext == _T(".glb"));
|
||||||
else
|
else
|
||||||
ret = LoadPLY(fileName);
|
ret = LoadPLY(fileName);
|
||||||
@@ -1208,6 +1207,43 @@ bool Mesh::Load(const String& fileName)
|
|||||||
DEBUG_EXTRA("Mesh loaded: %u vertices, %u faces (%s)", vertices.size(), faces.size(), TD_TIMER_GET_FMT().c_str());
|
DEBUG_EXTRA("Mesh loaded: %u vertices, %u faces (%s)", vertices.size(), faces.size(), TD_TIMER_GET_FMT().c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mesh::CheckUVValid()
|
||||||
|
{
|
||||||
|
for (int_t idxFace = 0; idxFace < (int_t)faces.size(); ++idxFace)
|
||||||
|
{
|
||||||
|
FOREACH(idxFace, faces)
|
||||||
|
{
|
||||||
|
const FIndex faceID = (FIndex)idxFace;
|
||||||
|
|
||||||
|
const TexCoord* uv = &faceTexcoords[faceID * 3];
|
||||||
|
|
||||||
|
const Point2f& a = uv[0];
|
||||||
|
const Point2f& b = uv[1];
|
||||||
|
const Point2f& c = uv[2];
|
||||||
|
|
||||||
|
// DEBUG_EXTRA("a=(%f,%f),b=(%f,%f),c=(%f,%f)", a.x, a.y, b.x, b.y, c.x, c.y);
|
||||||
|
|
||||||
|
// 计算边向量
|
||||||
|
Point2f v0 = b - a;
|
||||||
|
Point2f v1 = c - a;
|
||||||
|
float denom = (v0.x * v0.x + v0.y * v0.y) * (v1.x * v1.x + v1.y * v1.y) -
|
||||||
|
std::pow(v0.x * v1.x + v0.y * v1.y, 2);
|
||||||
|
|
||||||
|
// 处理退化三角形情况(面积接近0)
|
||||||
|
const float epsilon = 1e-10f;
|
||||||
|
if (std::abs(denom) < epsilon)
|
||||||
|
{
|
||||||
|
// DEBUG_EXTRA("PointInTriangle - Degenerate triangle, denom=%.10f", denom);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// DEBUG_EXTRA("PointInTriangle Yes idxFace=%d", idxFace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// import the mesh as a PLY file
|
// import the mesh as a PLY file
|
||||||
bool Mesh::LoadPLY(const String& fileName)
|
bool Mesh::LoadPLY(const String& fileName)
|
||||||
{
|
{
|
||||||
@@ -1302,16 +1338,28 @@ bool Mesh::LoadPLY(const String& fileName)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// import the mesh as a OBJ file
|
// import the mesh as a OBJ file
|
||||||
bool Mesh::LoadOBJ(const String& fileName)
|
bool Mesh::LoadOBJ(const String& fileName, bool bLoadUV)
|
||||||
{
|
{
|
||||||
ASSERT(!fileName.empty());
|
ASSERT(!fileName.empty());
|
||||||
Release();
|
Release();
|
||||||
|
|
||||||
// open and parse OBJ file
|
// open and parse OBJ file
|
||||||
ObjModel model;
|
ObjModel model;
|
||||||
if (!model.Load(fileName)) {
|
if (bLoadUV)
|
||||||
DEBUG_EXTRA("error: invalid OBJ file");
|
{
|
||||||
return false;
|
if (!model.LoadUV(fileName, faceTexcoords, true)) {
|
||||||
|
DEBUG_EXTRA("error: LoadUV invalid OBJ file %s", fileName.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!model.LoadUV(fileName, faceTexcoords)) {
|
||||||
|
// if (!model.Load(fileName)) {
|
||||||
|
DEBUG_EXTRA("error: Load invalid OBJ file %s", fileName.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.get_vertices().empty() || model.get_groups().empty()) {
|
if (model.get_vertices().empty() || model.get_groups().empty()) {
|
||||||
@@ -1340,11 +1388,13 @@ bool Mesh::LoadOBJ(const String& fileName)
|
|||||||
for (const ObjModel::Face& f: group.faces) {
|
for (const ObjModel::Face& f: group.faces) {
|
||||||
ASSERT(f.vertices[0] != NO_ID);
|
ASSERT(f.vertices[0] != NO_ID);
|
||||||
faces.emplace_back(f.vertices[0], f.vertices[1], f.vertices[2]);
|
faces.emplace_back(f.vertices[0], f.vertices[1], f.vertices[2]);
|
||||||
|
/*
|
||||||
if (f.texcoords[0] != NO_ID) {
|
if (f.texcoords[0] != NO_ID) {
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
faceTexcoords.emplace_back(model.get_texcoords()[f.texcoords[i]]);
|
faceTexcoords.emplace_back(model.get_texcoords()[f.texcoords[i]]);
|
||||||
faceTexindices.emplace_back((TexIndex)groupIdx);
|
faceTexindices.emplace_back((TexIndex)groupIdx);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if (f.normals[0] != NO_ID) {
|
if (f.normals[0] != NO_ID) {
|
||||||
Normal& n = faceNormals.emplace_back(Normal::ZERO);
|
Normal& n = faceNormals.emplace_back(Normal::ZERO);
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
@@ -1445,13 +1495,13 @@ bool Mesh::LoadGLTF(const String& fileName, bool bBinary)
|
|||||||
/*----------------------------------------------------------------*/
|
/*----------------------------------------------------------------*/
|
||||||
|
|
||||||
// export the mesh to the given file
|
// export the mesh to the given file
|
||||||
bool Mesh::Save(const String& fileName, const cList<String>& comments, bool bBinary) const
|
bool Mesh::Save(const String& fileName, const cList<String>& comments, bool bBinary, bool bUseExistingUV) const
|
||||||
{
|
{
|
||||||
TD_TIMER_STARTD();
|
TD_TIMER_STARTD();
|
||||||
const String ext(Util::getFileExt(fileName).ToLower());
|
const String ext(Util::getFileExt(fileName).ToLower());
|
||||||
bool ret;
|
bool ret;
|
||||||
if (ext == _T(".obj"))
|
if (ext == _T(".obj"))
|
||||||
ret = SaveOBJ(fileName);
|
ret = SaveOBJ(fileName, bUseExistingUV);
|
||||||
else
|
else
|
||||||
if (ext == _T(".gltf") || ext == _T(".glb"))
|
if (ext == _T(".gltf") || ext == _T(".glb"))
|
||||||
ret = SaveGLTF(fileName, ext == _T(".glb"));
|
ret = SaveGLTF(fileName, ext == _T(".glb"));
|
||||||
@@ -1538,7 +1588,7 @@ bool Mesh::SavePLY(const String& fileName, const cList<String>& comments, bool b
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// export the mesh as a OBJ file
|
// export the mesh as a OBJ file
|
||||||
bool Mesh::SaveOBJ(const String& fileName) const
|
bool Mesh::SaveOBJ(const String& fileName, bool bUseExistingUV) const
|
||||||
{
|
{
|
||||||
ASSERT(!fileName.empty());
|
ASSERT(!fileName.empty());
|
||||||
Util::ensureFolder(fileName);
|
Util::ensureFolder(fileName);
|
||||||
@@ -1597,7 +1647,7 @@ bool Mesh::SaveOBJ(const String& fileName) const
|
|||||||
pMaterial->diffuse_map = texturesDiffuse[idxTexture];
|
pMaterial->diffuse_map = texturesDiffuse[idxTexture];
|
||||||
}
|
}
|
||||||
|
|
||||||
return model.Save(fileName, 6U, true);
|
return model.Save(fileName, 6U, true, bUseExistingUV);
|
||||||
}
|
}
|
||||||
// export the mesh as a GLTF file
|
// export the mesh as a GLTF file
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
+6
-4
@@ -262,8 +262,8 @@ public:
|
|||||||
bool TransferTexture(Mesh& mesh, const FaceIdxArr& faceSubsetIndices={}, unsigned borderSize=3, unsigned textureSize=4096);
|
bool TransferTexture(Mesh& mesh, const FaceIdxArr& faceSubsetIndices={}, unsigned borderSize=3, unsigned textureSize=4096);
|
||||||
|
|
||||||
// file IO
|
// file IO
|
||||||
bool Load(const String& fileName);
|
bool Load(const String& fileName, bool bLoadUV=false);
|
||||||
bool Save(const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true) const;
|
bool Save(const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true, bool bUseExistingUV=false) const;
|
||||||
bool Save(const FacesChunkArr&, const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true) const;
|
bool Save(const FacesChunkArr&, const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true) const;
|
||||||
static bool Save(const VertexArr& vertices, const String& fileName, bool bBinary=true);
|
static bool Save(const VertexArr& vertices, const String& fileName, bool bBinary=true);
|
||||||
|
|
||||||
@@ -271,13 +271,15 @@ public:
|
|||||||
static inline VIndex GetVertex(const Face& f, VIndex v) { const uint32_t idx(FindVertex(f, v)); ASSERT(idx != NO_ID); return f[idx]; }
|
static inline VIndex GetVertex(const Face& f, VIndex v) { const uint32_t idx(FindVertex(f, v)); ASSERT(idx != NO_ID); return f[idx]; }
|
||||||
static inline VIndex& GetVertex(Face& f, VIndex v) { const uint32_t idx(FindVertex(f, v)); ASSERT(idx != NO_ID); return f[idx]; }
|
static inline VIndex& GetVertex(Face& f, VIndex v) { const uint32_t idx(FindVertex(f, v)); ASSERT(idx != NO_ID); return f[idx]; }
|
||||||
|
|
||||||
|
void CheckUVValid();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool LoadPLY(const String& fileName);
|
bool LoadPLY(const String& fileName);
|
||||||
bool LoadOBJ(const String& fileName);
|
bool LoadOBJ(const String& fileName, bool bLoadUV);
|
||||||
bool LoadGLTF(const String& fileName, bool bBinary=true);
|
bool LoadGLTF(const String& fileName, bool bBinary=true);
|
||||||
|
|
||||||
bool SavePLY(const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true, bool bTexLossless=true) const;
|
bool SavePLY(const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true, bool bTexLossless=true) const;
|
||||||
bool SaveOBJ(const String& fileName) const;
|
bool SaveOBJ(const String& fileName, bool bUseExistingUV) const;
|
||||||
bool SaveGLTF(const String& fileName, bool bBinary=true) const;
|
bool SaveGLTF(const String& fileName, bool bBinary=true) const;
|
||||||
|
|
||||||
#ifdef _USE_CUDA
|
#ifdef _USE_CUDA
|
||||||
|
|||||||
+17
-8
@@ -65,8 +65,6 @@ public:
|
|||||||
std::map<std::string, std::unordered_set<int>> visible_faces_map;
|
std::map<std::string, std::unordered_set<int>> visible_faces_map;
|
||||||
std::map<std::string, std::unordered_set<int>> edge_faces_map;
|
std::map<std::string, std::unordered_set<int>> edge_faces_map;
|
||||||
std::map<std::string, std::unordered_set<int>> delete_edge_faces_map;
|
std::map<std::string, std::unordered_set<int>> delete_edge_faces_map;
|
||||||
std::map<std::string, std::unordered_set<int>> delete_edge_faces_map2;
|
|
||||||
std::map<std::string, std::unordered_set<int>> face_normal_visible_map;
|
|
||||||
std::unordered_set<int> face_visible_relative;
|
std::unordered_set<int> face_visible_relative;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -165,23 +163,34 @@ public:
|
|||||||
std::unordered_set<int>& face_visible_relative,
|
std::unordered_set<int>& face_visible_relative,
|
||||||
std::map<std::string, std::unordered_set<int>>& edge_faces_map,
|
std::map<std::string, std::unordered_set<int>>& edge_faces_map,
|
||||||
std::map<std::string, std::unordered_set<int>>& delete_edge_faces_map,
|
std::map<std::string, std::unordered_set<int>>& delete_edge_faces_map,
|
||||||
std::map<std::string, std::unordered_set<int>>& delete_edge_faces_map2,
|
|
||||||
std::map<std::string, std::unordered_set<int>>& face_normal_visible_map,
|
|
||||||
std::string& basePath);
|
std::string& basePath);
|
||||||
|
bool LoadVisibleFacesData() {
|
||||||
|
std::map<std::string, std::unordered_set<int>> visible_faces_map;
|
||||||
|
std::unordered_set<int> face_visible_relative;
|
||||||
|
std::map<std::string, std::unordered_set<int>> edge_faces_map;
|
||||||
|
std::map<std::string, std::unordered_set<int>> delete_edge_faces_map;
|
||||||
|
std::string basePath = GetDefaultBasePath(); // 你需要实现这个函数
|
||||||
|
|
||||||
|
return LoadVisibleFacesData(visible_faces_map, face_visible_relative,
|
||||||
|
edge_faces_map, delete_edge_faces_map, basePath);
|
||||||
|
}
|
||||||
|
std::string GetDefaultBasePath() {
|
||||||
|
// 根据你的需求实现这个函数
|
||||||
|
// 例如:返回一个默认的路径,或者从配置中读取
|
||||||
|
return "default_path";
|
||||||
|
}
|
||||||
|
|
||||||
// Mesh texturing
|
// Mesh texturing
|
||||||
bool TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsigned minCommonCameras=0, float fOutlierThreshold=0.f, float fRatioDataSmoothness=0.3f,
|
bool TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsigned minCommonCameras=0, float fOutlierThreshold=0.f, float fRatioDataSmoothness=0.3f,
|
||||||
bool bGlobalSeamLeveling=true, bool bLocalSeamLeveling=true, unsigned nTextureSizeMultiple=0, unsigned nRectPackingHeuristic=3, Pixel8U colEmpty=Pixel8U(255,127,39),
|
bool bGlobalSeamLeveling=true, bool bLocalSeamLeveling=true, unsigned nTextureSizeMultiple=0, unsigned nRectPackingHeuristic=3, Pixel8U colEmpty=Pixel8U(255,127,39),
|
||||||
float fSharpnessWeight=0.5f, int ignoreMaskLabel=-1, int maxTextureSize=0, const IIndexArr& views=IIndexArr(), const SEACAVE::String& basename = "", bool bOriginFaceview = false,
|
float fSharpnessWeight=0.5f, int ignoreMaskLabel=-1, int maxTextureSize=0, const IIndexArr& views=IIndexArr(), const SEACAVE::String& basename = "", bool bOriginFaceview = false,
|
||||||
const std::string& inputFileName = "", const std::string& meshFileName = "");
|
const std::string& inputFileName = "", const std::string& meshFileName = "", bool bUseExistingUV = false, const std::string& strUVMeshFileName = "");
|
||||||
|
|
||||||
std::string runPython(const std::string& command);
|
std::string runPython(const std::string& command);
|
||||||
bool is_face_visible(const std::string& image_name, int face_index);
|
bool is_face_visible(const std::string& image_name, int face_index);
|
||||||
bool is_face_visible_relative(int face_index);
|
bool is_face_visible_relative(int face_index);
|
||||||
bool is_face_edge(const std::string& image_name, int face_index);
|
bool is_face_edge(const std::string& image_name, int face_index);
|
||||||
bool is_face_delete_edge(const std::string& image_name, int face_index);
|
bool is_face_delete_edge(const std::string& image_name, int face_index);
|
||||||
bool is_face_delete_edge2(const std::string& image_name, int face_index);
|
|
||||||
bool is_face_normal_visible_map(const std::string& image_name, int face_index);
|
|
||||||
|
|
||||||
void SegmentMeshBasedOnCurvature(Mesh::FaceIdxArr& regionMap, float curvatureThreshold);
|
void SegmentMeshBasedOnCurvature(Mesh::FaceIdxArr& regionMap, float curvatureThreshold);
|
||||||
|
|
||||||
|
|||||||
+10108
-4454
File diff suppressed because it is too large.
Load diff
+159
-139
@@ -4,8 +4,7 @@ import os
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from scipy.spatial.transform import Rotation
|
from scipy.spatial.transform import Rotation
|
||||||
import sys
|
import sys
|
||||||
# sys.path.append("/home/algo/Documents/openMVS/openMVS/libs/MVS/utils")
|
sys.path.append("/home/algo/Documents/openMVS/openMVS/libs/MVS/utils")
|
||||||
sys.path.append("/root/code/openMVS/libs/MVS/utils")
|
|
||||||
from colmap_loader import read_cameras_text, read_images_text, read_int_text, write_int_text, read_indices_from_file
|
from colmap_loader import read_cameras_text, read_images_text, read_int_text, write_int_text, read_indices_from_file
|
||||||
# from get_pose_matrix import get_w2c
|
# from get_pose_matrix import get_w2c
|
||||||
import argparse
|
import argparse
|
||||||
@@ -34,7 +33,6 @@ from typing import Dict, List, Set
|
|||||||
import struct
|
import struct
|
||||||
import math
|
import math
|
||||||
# import os
|
# import os
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
CameraModel = collections.namedtuple(
|
CameraModel = collections.namedtuple(
|
||||||
"CameraModel", ["model_id", "model_name", "num_params"]
|
"CameraModel", ["model_id", "model_name", "num_params"]
|
||||||
@@ -1352,90 +1350,14 @@ class ModelProcessor:
|
|||||||
|
|
||||||
face_visible = v0_visible | v1_visible | v2_visible
|
face_visible = v0_visible | v1_visible | v2_visible
|
||||||
|
|
||||||
# ============ 新增:法线夹角过滤 ============
|
|
||||||
# 1. 获取面片法线(向量化计算,性能更好)
|
|
||||||
if not hasattr(self, 'face_normals_tensor'):
|
|
||||||
# 从mesh获取顶点和面片索引
|
|
||||||
vertices = np.asarray(self.mesh.vertices) # 形状: (V, 3)
|
|
||||||
triangles = np.asarray(self.mesh.triangles) # 形状: (F, 3)
|
|
||||||
|
|
||||||
# 向量化计算法线
|
|
||||||
# 获取所有三角形的顶点
|
|
||||||
v0 = vertices[triangles[:, 0]] # 形状: (F, 3)
|
|
||||||
v1 = vertices[triangles[:, 1]] # 形状: (F, 3)
|
|
||||||
v2 = vertices[triangles[:, 2]] # 形状: (F, 3)
|
|
||||||
|
|
||||||
# 计算边向量
|
|
||||||
edge1 = v1 - v0
|
|
||||||
edge2 = v2 - v0
|
|
||||||
|
|
||||||
# 向量化叉积
|
|
||||||
# np.cross支持批量计算
|
|
||||||
normals = np.cross(edge1, edge2)
|
|
||||||
|
|
||||||
# 计算法线长度
|
|
||||||
norms = np.linalg.norm(normals, axis=1, keepdims=True)
|
|
||||||
|
|
||||||
# 避免除零
|
|
||||||
norms[norms < 1e-6] = 1.0
|
|
||||||
|
|
||||||
# 归一化
|
|
||||||
normals = normals / norms
|
|
||||||
|
|
||||||
# 将退化三角形的法线设为默认值
|
|
||||||
mask = norms[:, 0] < 1e-6
|
|
||||||
if np.any(mask):
|
|
||||||
normals[mask] = np.array([0.0, 0.0, 1.0])
|
|
||||||
|
|
||||||
# 转换为GPU张量
|
|
||||||
self.face_normals_tensor = torch.tensor(normals, device=self.device, dtype=torch.float32)
|
|
||||||
|
|
||||||
# 2. 计算摄像机方向(从面片中心指向摄像机)
|
|
||||||
# 获取面片顶点坐标
|
|
||||||
v0_pos = self.vertices_tensor[v0_indices]
|
|
||||||
v1_pos = self.vertices_tensor[v1_indices]
|
|
||||||
v2_pos = self.vertices_tensor[v2_indices]
|
|
||||||
|
|
||||||
# 计算面片中心
|
|
||||||
face_centers = (v0_pos + v1_pos + v2_pos) / 3.0
|
|
||||||
|
|
||||||
# 计算摄像机方向向量
|
|
||||||
camera_pos = torch.tensor(eye, device=self.device, dtype=torch.float32)
|
|
||||||
if len(camera_pos.shape) == 1:
|
|
||||||
camera_pos = camera_pos.unsqueeze(0) # 从(3)变为(1,3)
|
|
||||||
|
|
||||||
# 方向:从面片中心指向摄像机
|
|
||||||
view_dirs = camera_pos - face_centers
|
|
||||||
view_dirs = view_dirs / torch.norm(view_dirs, dim=1, keepdim=True)
|
|
||||||
|
|
||||||
# 3. 计算法线与摄像机方向的夹角
|
|
||||||
face_normals = self.face_normals_tensor
|
|
||||||
# 归一化法线
|
|
||||||
face_normals = face_normals / torch.norm(face_normals, dim=1, keepdim=True)
|
|
||||||
|
|
||||||
# 计算点积(余弦值)
|
|
||||||
cos_angles = torch.sum(face_normals * view_dirs, dim=1)
|
|
||||||
|
|
||||||
# 计算角度(弧度转角度)
|
|
||||||
angles_deg = torch.acos(torch.clamp(cos_angles, -1.0, 1.0)) * 180.0 / torch.pi
|
|
||||||
|
|
||||||
# 4. 创建法线可见性掩码(夹角 ≤ 45度)
|
|
||||||
normal_visible_mask = angles_deg <= 40.0
|
|
||||||
|
|
||||||
# 5. 结合遮挡可见性和法线可见性
|
|
||||||
face_normal_visible = face_visible & normal_visible_mask
|
|
||||||
# ============ 法线夹角过滤结束 ============
|
|
||||||
|
|
||||||
# 使用与CPU版本相同的后续处理
|
# 使用与CPU版本相同的后续处理
|
||||||
shrunk_visibility = self._shrink_face_visibility(face_visible.cpu().numpy(), 6)
|
shrunk_visibility = self._shrink_face_visibility(face_visible.cpu().numpy(), 6)
|
||||||
expanded_visibility = self._expand_face_visibility(face_visible.cpu().numpy(), 0)
|
expanded_visibility = self._expand_face_visibility(face_visible.cpu().numpy(), 30)
|
||||||
shrunk_visibility2 = self._shrink_face_visibility(face_visible.cpu().numpy(), 0)
|
shrunk_visibility2 = self._shrink_face_visibility(face_visible.cpu().numpy(), 50)
|
||||||
shrunk_visibility3 = self._shrink_face_visibility(face_visible.cpu().numpy(), 100)
|
|
||||||
expanded_edge = expanded_visibility & ~shrunk_visibility2
|
expanded_edge = expanded_visibility & ~shrunk_visibility2
|
||||||
delete_edge = face_visible.cpu().numpy() & ~shrunk_visibility
|
delete_edge = face_visible.cpu().numpy() & ~shrunk_visibility
|
||||||
delete_edge2 = face_visible.cpu().numpy() & ~shrunk_visibility3
|
|
||||||
|
|
||||||
return shrunk_visibility, expanded_edge, delete_edge, delete_edge2, face_normal_visible
|
return shrunk_visibility, expanded_edge, delete_edge
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def _gen_depth_image_gpu(self, cam_data, render):
|
def _gen_depth_image_gpu(self, cam_data, render):
|
||||||
@@ -1466,8 +1388,6 @@ class ModelProcessor:
|
|||||||
visible_faces_dict = {}
|
visible_faces_dict = {}
|
||||||
edge_faces_dict = {}
|
edge_faces_dict = {}
|
||||||
delete_edge_faces_dict = {}
|
delete_edge_faces_dict = {}
|
||||||
delete_edge_faces_dict2 = {}
|
|
||||||
face_normal_visible_dict = {}
|
|
||||||
|
|
||||||
total_start = time.time()
|
total_start = time.time()
|
||||||
|
|
||||||
@@ -1493,15 +1413,13 @@ class ModelProcessor:
|
|||||||
# continue
|
# continue
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
face_visibility, face_edge, face_delete_edge, face_delete_edge2, face_normal_visible = self._flag_model_gpu(camera_data)
|
face_visibility, face_edge, face_delete_edge = self._flag_model_gpu(camera_data)
|
||||||
processing_time = time.time() - start_time
|
processing_time = time.time() - start_time
|
||||||
|
|
||||||
visible_faces = np.where(face_visibility)[0].tolist()
|
visible_faces = np.where(face_visibility)[0].tolist()
|
||||||
visible_faces_dict[img_name] = visible_faces
|
visible_faces_dict[img_name] = visible_faces
|
||||||
edge_faces_dict[img_name] = np.where(face_edge)[0].tolist()
|
edge_faces_dict[img_name] = np.where(face_edge)[0].tolist()
|
||||||
delete_edge_faces_dict[img_name] = np.where(face_delete_edge)[0].tolist()
|
delete_edge_faces_dict[img_name] = np.where(face_delete_edge)[0].tolist()
|
||||||
delete_edge_faces_dict2[img_name] = np.where(face_delete_edge2)[0].tolist()
|
|
||||||
face_normal_visible_dict[img_name] = np.where(face_normal_visible.cpu().numpy())[0].tolist()
|
|
||||||
|
|
||||||
print(f"图像 {img_name} 处理完成,耗时: {processing_time:.2f}秒,可见面数量{len(visible_faces)}")
|
print(f"图像 {img_name} 处理完成,耗时: {processing_time:.2f}秒,可见面数量{len(visible_faces)}")
|
||||||
|
|
||||||
@@ -1509,14 +1427,12 @@ class ModelProcessor:
|
|||||||
print(f"所有图像处理完成,总耗时: {total_time:.2f}秒")
|
print(f"所有图像处理完成,总耗时: {total_time:.2f}秒")
|
||||||
print(f"平均每张图像耗时: {total_time/len(images):.2f}秒")
|
print(f"平均每张图像耗时: {total_time/len(images):.2f}秒")
|
||||||
|
|
||||||
self.save_occlusion_data(visible_faces_dict, edge_faces_dict, delete_edge_faces_dict, delete_edge_faces_dict2, face_normal_visible_dict, self.asset_dir)
|
self.save_occlusion_data(visible_faces_dict, edge_faces_dict, delete_edge_faces_dict, self.asset_dir)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"result1": visible_faces_dict,
|
"result1": visible_faces_dict,
|
||||||
"result2": edge_faces_dict,
|
"result2": edge_faces_dict,
|
||||||
"result3": delete_edge_faces_dict,
|
"result3": delete_edge_faces_dict
|
||||||
"result4": delete_edge_faces_dict2,
|
|
||||||
"result5": face_normal_visible_dict
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#"""
|
#"""
|
||||||
@@ -2010,6 +1926,64 @@ class ModelProcessor:
|
|||||||
depth = render.render_to_depth_image(z_in_view_space=True)
|
depth = render.render_to_depth_image(z_in_view_space=True)
|
||||||
return np.asarray(depth)
|
return np.asarray(depth)
|
||||||
|
|
||||||
|
def sort_vertices(vertices_original):
|
||||||
|
return sorted(
|
||||||
|
(v for v in vertices_original),
|
||||||
|
key=lambda v: (v.co.x, v.co.y, v.co.z)
|
||||||
|
)
|
||||||
|
|
||||||
|
def _flag_model(self, camera_data, face_points):
|
||||||
|
"""标记可见顶点"""
|
||||||
|
vertex_visible = []
|
||||||
|
vertex_occlusion = []
|
||||||
|
depth_images = []
|
||||||
|
|
||||||
|
render = o3d.visualization.rendering.OffscreenRenderer(camera_data['width'], camera_data['height'])
|
||||||
|
|
||||||
|
material = o3d.visualization.rendering.MaterialRecord()
|
||||||
|
render.scene.add_geometry("mesh", self.mesh, material)
|
||||||
|
|
||||||
|
# 生成深度图
|
||||||
|
depth_image = self._gen_depth_image(camera_data, render)
|
||||||
|
|
||||||
|
# 计算可见性
|
||||||
|
R = self.qvec2rotmat(camera_data['qvec']).T
|
||||||
|
eye = -R @ camera_data['tvec']
|
||||||
|
# eye = camera_data['tvec']
|
||||||
|
# final_visible_list, final_occlusion_list, final_vertex_difference_list = self._compute_vertex_in_frustum(
|
||||||
|
final_visible_list, final_occlusion_list = self._compute_vertex_in_frustum(
|
||||||
|
camera_data['fx'], camera_data['fy'],
|
||||||
|
camera_data['cx'], camera_data['cy'],
|
||||||
|
R, eye,
|
||||||
|
camera_data['height'], camera_data['width'],
|
||||||
|
depth_image,camera_data['qvec'], camera_data['tvec']
|
||||||
|
)
|
||||||
|
print("_flag_model", len(final_occlusion_list), len(self.mesh.vertices), len(self.mesh.vertex_colors))
|
||||||
|
|
||||||
|
# 获取三角形面片数组
|
||||||
|
triangles = np.asarray(self.mesh.triangles)
|
||||||
|
|
||||||
|
face_visible_bitmap = np.zeros(len(triangles), dtype=bool)
|
||||||
|
|
||||||
|
# 遍历所有面片
|
||||||
|
for face_idx, face in enumerate(triangles):
|
||||||
|
v0, v1, v2 = face
|
||||||
|
|
||||||
|
face_visible_bitmap[face_idx] = any([ # any all
|
||||||
|
final_visible_list[v0],
|
||||||
|
final_visible_list[v1],
|
||||||
|
final_visible_list[v2]
|
||||||
|
])
|
||||||
|
|
||||||
|
shrunk_visibility = self._shrink_face_visibility(face_visible_bitmap, 6) # 6 10
|
||||||
|
|
||||||
|
expanded_visibility = self._expand_face_visibility(face_visible_bitmap, 30)
|
||||||
|
shrunk_visibility2 = self._shrink_face_visibility(face_visible_bitmap, 50)
|
||||||
|
expanded_edge = expanded_visibility & ~shrunk_visibility2
|
||||||
|
delete_edge = face_visible_bitmap & ~shrunk_visibility
|
||||||
|
|
||||||
|
return shrunk_visibility, expanded_edge, delete_edge
|
||||||
|
|
||||||
def _flag_contour(self, camera_data, face_points):
|
def _flag_contour(self, camera_data, face_points):
|
||||||
"""标记可见顶点"""
|
"""标记可见顶点"""
|
||||||
vertex_visible = []
|
vertex_visible = []
|
||||||
@@ -2099,11 +2073,97 @@ class ModelProcessor:
|
|||||||
face_visible_bitmap = np.ones(len(triangles), dtype=bool) # 临时填充
|
face_visible_bitmap = np.ones(len(triangles), dtype=bool) # 临时填充
|
||||||
return face_visible_bitmap, face_edge
|
return face_visible_bitmap, face_edge
|
||||||
|
|
||||||
|
"""
|
||||||
|
def _mask_face_occlusion(self):
|
||||||
|
# 读取相机数据
|
||||||
|
cameras = read_cameras_text(os.path.join(self.pose_path, "cameras.txt"))
|
||||||
|
images = read_images_text(os.path.join(self.pose_path, "images.txt"))
|
||||||
|
# cameras = read_cameras_text(os.path.join(self.pose_path, "backup_cameras.txt"))
|
||||||
|
# images = read_images_text(os.path.join(self.pose_path, "backup_images.txt"))
|
||||||
|
|
||||||
|
face_points_sorted_path = os.path.join(self.pose_path, "face_points_sorted.txt")
|
||||||
|
print("face_points_sorted_path=", face_points_sorted_path)
|
||||||
|
#face_points = read_int_text(face_points_sorted_path)
|
||||||
|
face_points = read_indices_from_file(face_points_sorted_path)
|
||||||
|
# face_points = {}
|
||||||
|
camera_data = {}
|
||||||
|
|
||||||
|
for img in images.values():
|
||||||
|
if self.mask_image == img.name[:-4]:
|
||||||
|
camera = cameras[img.camera_id]
|
||||||
|
camera_data = {
|
||||||
|
"qvec": img.qvec,
|
||||||
|
"tvec": img.tvec,
|
||||||
|
"fx": camera.params[0],
|
||||||
|
"fy": camera.params[1],
|
||||||
|
"cx": camera.params[2],
|
||||||
|
"cy": camera.params[3],
|
||||||
|
"width": camera.width,
|
||||||
|
"height": camera.height,
|
||||||
|
"name": img.name[:-4]
|
||||||
|
}
|
||||||
|
|
||||||
|
# print(face_points)
|
||||||
|
self._flag_model(camera_data, face_points)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _mask_occlusion(self):
|
||||||
|
# 读取相机数据
|
||||||
|
cameras = read_cameras_text(os.path.join(self.pose_path, "cameras.txt"))
|
||||||
|
images = read_images_text(os.path.join(self.pose_path, "images.txt"))
|
||||||
|
|
||||||
|
camera_data = {}
|
||||||
|
|
||||||
|
countour_faces_dict = {}
|
||||||
|
visible_faces_dict = {}
|
||||||
|
edge_faces_dict = {}
|
||||||
|
delete_edge_faces_dict = {}
|
||||||
|
|
||||||
|
total_start = time.time()
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
for img in images.values():
|
||||||
|
camera = cameras[img.camera_id]
|
||||||
|
camera_data = {
|
||||||
|
"qvec": img.qvec,
|
||||||
|
"tvec": img.tvec,
|
||||||
|
"fx": camera.params[0],
|
||||||
|
"fy": camera.params[1],
|
||||||
|
"cx": camera.params[2],
|
||||||
|
"cy": camera.params[3],
|
||||||
|
"width": camera.width,
|
||||||
|
"height": camera.height,
|
||||||
|
"name": img.name[:-4]
|
||||||
|
}
|
||||||
|
img_name = img.name[:-4]
|
||||||
|
# if (img_name!="73_8" and img_name!="52_8" and img_name!="62_8"):
|
||||||
|
# if (img_name!="52_8" and img_name!="62_8"):
|
||||||
|
# if (img_name!="52_8"):
|
||||||
|
# continue
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
face_visibility, face_edge, face_delete_edge = self._flag_model(camera_data, None)
|
||||||
|
processing_time = time.time() - start_time
|
||||||
|
|
||||||
|
visible_faces = np.where(face_visibility)[0].tolist()
|
||||||
|
visible_faces_dict[img.name[:-4]] = visible_faces
|
||||||
|
edge_faces_dict[img.name[:-4]] = np.where(face_edge)[0].tolist()
|
||||||
|
delete_edge_faces_dict[img.name[:-4]] = np.where(face_delete_edge)[0].tolist()
|
||||||
|
n += 1
|
||||||
|
|
||||||
|
print(f"图像={img_name},耗时={processing_time:.2f}秒,可见面数={len(visible_faces)}")
|
||||||
|
|
||||||
|
total_time = time.time() - total_start
|
||||||
|
print(f"所有图像处理完成,总耗时: {total_time:.2f}秒")
|
||||||
|
print(f"平均每张图像耗时: {total_time/len(images):.2f}秒")
|
||||||
|
|
||||||
|
self.save_occlusion_data(visible_faces_dict, edge_faces_dict, delete_edge_faces_dict, self.asset_dir)
|
||||||
|
|
||||||
|
return {"result1": visible_faces_dict, "result2": edge_faces_dict, "result3": delete_edge_faces_dict}
|
||||||
|
|
||||||
def save_occlusion_data(self, result1: Dict[str, List[int]],
|
def save_occlusion_data(self, result1: Dict[str, List[int]],
|
||||||
result2: Dict[str, List[int]],
|
result2: Dict[str, List[int]],
|
||||||
result3: Dict[str, List[int]],
|
result3: Dict[str, List[int]],
|
||||||
result4: Dict[str, List[int]],
|
|
||||||
result5: Dict[str, List[int]],
|
|
||||||
base_path: str) -> None:
|
base_path: str) -> None:
|
||||||
"""
|
"""
|
||||||
保存遮挡数据到文件
|
保存遮挡数据到文件
|
||||||
@@ -2114,8 +2174,6 @@ class ModelProcessor:
|
|||||||
result3: 删除边面字典,包含图像名称和对应的删除边面列表
|
result3: 删除边面字典,包含图像名称和对应的删除边面列表
|
||||||
base_path: 基础文件路径
|
base_path: 基础文件路径
|
||||||
"""
|
"""
|
||||||
|
|
||||||
os.makedirs(base_path, exist_ok = True)
|
|
||||||
|
|
||||||
print(f"save_occlusion_data {base_path}, {len(result1)}, {len(result2)}, {len(result3)}")
|
print(f"save_occlusion_data {base_path}, {len(result1)}, {len(result2)}, {len(result3)}")
|
||||||
|
|
||||||
@@ -2138,20 +2196,10 @@ class ModelProcessor:
|
|||||||
delete_edge_faces_map: Dict[str, Set[int]] = {}
|
delete_edge_faces_map: Dict[str, Set[int]] = {}
|
||||||
for image_name, face_list in result3.items():
|
for image_name, face_list in result3.items():
|
||||||
delete_edge_faces_map[image_name] = set(face_list)
|
delete_edge_faces_map[image_name] = set(face_list)
|
||||||
|
|
||||||
delete_edge_faces_map2: Dict[str, Set[int]] = {}
|
|
||||||
for image_name, face_list in result4.items():
|
|
||||||
delete_edge_faces_map2[image_name] = set(face_list)
|
|
||||||
|
|
||||||
face_normal_visible_map: Dict[str, Set[int]] = {}
|
|
||||||
for image_name, face_list in result5.items():
|
|
||||||
face_normal_visible_map[image_name] = set(face_list)
|
|
||||||
|
|
||||||
# 保存 visible_faces_map
|
# 保存 visible_faces_map
|
||||||
try:
|
try:
|
||||||
file_name = "_visible_faces_map.txt"
|
with open(base_path + "/_visible_faces_map.txt", "w", encoding='utf-8') as map_file:
|
||||||
file_path = Path(base_path) / file_name
|
|
||||||
with open(file_path, "w", encoding='utf-8') as map_file:
|
|
||||||
for image_name, face_set in visible_faces_map.items():
|
for image_name, face_set in visible_faces_map.items():
|
||||||
# 写入图像名称和所有面ID,用空格分隔
|
# 写入图像名称和所有面ID,用空格分隔
|
||||||
line = image_name + " " + " ".join(str(face) for face in face_set) + "\n"
|
line = image_name + " " + " ".join(str(face) for face in face_set) + "\n"
|
||||||
@@ -2161,9 +2209,7 @@ class ModelProcessor:
|
|||||||
|
|
||||||
# 保存 face_visible_relative
|
# 保存 face_visible_relative
|
||||||
try:
|
try:
|
||||||
file_name = "_face_visible_relative.txt"
|
with open(base_path + "/_face_visible_relative.txt", "w", encoding='utf-8') as relative_file:
|
||||||
file_path = Path(base_path) / file_name
|
|
||||||
with open(file_path, "w", encoding='utf-8') as relative_file:
|
|
||||||
for face in face_visible_relative:
|
for face in face_visible_relative:
|
||||||
relative_file.write(str(face) + "\n")
|
relative_file.write(str(face) + "\n")
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
@@ -2171,9 +2217,7 @@ class ModelProcessor:
|
|||||||
|
|
||||||
# 保存 edge_faces_map
|
# 保存 edge_faces_map
|
||||||
try:
|
try:
|
||||||
file_name = "_edge_faces_map.txt"
|
with open(base_path + "/_edge_faces_map.txt", "w", encoding='utf-8') as map_file2:
|
||||||
file_path = Path(base_path) / file_name
|
|
||||||
with open(file_path, "w", encoding='utf-8') as map_file2:
|
|
||||||
for image_name, face_set in edge_faces_map.items():
|
for image_name, face_set in edge_faces_map.items():
|
||||||
line = image_name + " " + " ".join(str(face) for face in face_set) + "\n"
|
line = image_name + " " + " ".join(str(face) for face in face_set) + "\n"
|
||||||
map_file2.write(line)
|
map_file2.write(line)
|
||||||
@@ -2182,37 +2226,13 @@ class ModelProcessor:
|
|||||||
|
|
||||||
# 保存 delete_edge_faces_map
|
# 保存 delete_edge_faces_map
|
||||||
try:
|
try:
|
||||||
file_name = "_delete_edge_faces_map.txt"
|
with open(base_path + "/_delete_edge_faces_map.txt", "w", encoding='utf-8') as map_file3:
|
||||||
file_path = Path(base_path) / file_name
|
|
||||||
with open(file_path, "w", encoding='utf-8') as map_file3:
|
|
||||||
for image_name, face_set in delete_edge_faces_map.items():
|
for image_name, face_set in delete_edge_faces_map.items():
|
||||||
line = image_name + " " + " ".join(str(face) for face in face_set) + "\n"
|
line = image_name + " " + " ".join(str(face) for face in face_set) + "\n"
|
||||||
map_file3.write(line)
|
map_file3.write(line)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
print(f"Error writing delete_edge_faces_map file: {e}")
|
print(f"Error writing delete_edge_faces_map file: {e}")
|
||||||
|
|
||||||
# 保存 delete_edge_faces_map2
|
|
||||||
try:
|
|
||||||
file_name = "_delete_edge_faces_map2.txt"
|
|
||||||
file_path = Path(base_path) / file_name
|
|
||||||
with open(file_path, "w", encoding='utf-8') as map_file4:
|
|
||||||
for image_name, face_set in delete_edge_faces_map2.items():
|
|
||||||
line = image_name + " " + " ".join(str(face) for face in face_set) + "\n"
|
|
||||||
map_file4.write(line)
|
|
||||||
except IOError as e:
|
|
||||||
print(f"Error writing delete_edge_faces_map2 file: {e}")
|
|
||||||
|
|
||||||
# 保存 face_normal_visible_map
|
|
||||||
try:
|
|
||||||
file_name = "_face_normal_visible_map.txt"
|
|
||||||
file_path = Path(base_path) / file_name
|
|
||||||
with open(file_path, "w", encoding='utf-8') as map_file5:
|
|
||||||
for image_name, face_set in face_normal_visible_map.items():
|
|
||||||
line = image_name + " " + " ".join(str(face) for face in face_set) + "\n"
|
|
||||||
map_file5.write(line)
|
|
||||||
except IOError as e:
|
|
||||||
print(f"Error writing _face_normal_visible_map file: {e}")
|
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
|
|
||||||
print("process")
|
print("process")
|
||||||
|
|||||||
Reference in new issue
Block a user