Compare commits

..

16 Commits

  1. 1
      .gitignore
  2. 9
      apps/TextureMesh/TextureMesh.cpp
  3. 71
      fill_all_empty_faces_v1.2.py
  4. 129
      libs/IO/OBJ.cpp
  5. 3
      libs/IO/OBJ.h
  6. 74
      libs/MVS/Mesh.cpp
  7. 10
      libs/MVS/Mesh.h
  8. 2
      libs/MVS/Scene.h
  9. 2572
      libs/MVS/SceneTexture.cpp
  10. 23
      libs/MVS/mask_face_occlusion.py

1
.gitignore vendored

@ -7,6 +7,7 @@
# Precompiled Headers # Precompiled Headers
*.gch *.gch
*.pch *.pch
*.pyc
# Compiled Dynamic libraries # Compiled Dynamic libraries
*.so *.so

9
apps/TextureMesh/TextureMesh.cpp

@ -94,9 +94,6 @@ 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
@ -166,8 +163,6 @@ 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
@ -1139,12 +1134,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::bUseExistingUV, OPT::strUVMeshFileName)) OPT::strInputFileName, OPT::strMeshFileName))
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,cList<String>(),true,OPT::bUseExistingUV); scene.mesh.Save(baseFileName+OPT::strExportType);
#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);

71
fill_all_empty_faces_v1.2.py

@ -323,7 +323,7 @@ def compute_regions_face_colors(
return regions_face_color return regions_face_color
def update_uv_map_and_indices( def update_uv_map_and_indices2(
uv_map: torch.Tensor, uv_map: torch.Tensor,
uvs: torch.Tensor, uvs: torch.Tensor,
face_uv_indices: torch.Tensor, face_uv_indices: torch.Tensor,
@ -394,6 +394,75 @@ def update_uv_map_and_indices(
return new_uv_map, uvs_updated, face_uv_indices return new_uv_map, uvs_updated, face_uv_indices
def update_uv_map_and_indices(
uv_map: torch.Tensor,
uvs: torch.Tensor,
face_uv_indices: torch.Tensor,
regions: List[Tuple[set, set]],
regions_face_color: Dict[int, torch.Tensor],
device: str
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
"""
根据计算得到的区域颜色更新UV贴图及对应的UV坐标并批量更新face_uv_indices
"""
total_regions = len(regions_face_color)
# 1. 在CPU上创建新的UV贴图
new_height = int(uv_map.shape[0] + uv_map.shape[0] / 2)
new_width = uv_map.shape[1]
# 将原始UV贴图移到CPU
uv_map_cpu = uv_map.cpu().numpy()
# 创建新的UV贴图(在CPU上)
new_uv_map_cpu = np.zeros((new_height, new_width, 3), dtype=np.uint8)
new_uv_map_cpu[:uv_map.shape[0], :, :] = uv_map_cpu
# 2. 在CPU上创建颜色块
grid_size = new_width // 3
for i, (region_index, color) in enumerate(regions_face_color.items()):
all_c = i // grid_size
all_r = i % grid_size
# 计算3x3颜色块的位置
for dr in range(3):
for dc in range(3):
r = all_r * 3 + dr
c = all_c * 3 + dc + uv_map.shape[0] # 偏移到下半部分
if r < new_width and c < new_height:
new_uv_map_cpu[c, r, :] = color.cpu().numpy()
# 3. 更新UV坐标
uvs[:, 1] = uvs[:, 1] * (2 / 3) + 1 / 3
# 计算新的UV坐标
new_uvs = []
for i, (region_index, _) in enumerate(sorted(regions_face_color.items(), key=lambda x: x[0])):
r = (i % grid_size) * 3 + 1
c = uv_map.shape[0] + (i // grid_size) * 3 + 1
u_new = r / (new_width - 1)
v_new = (new_height - 1 - c) / (new_height - 1)
new_uvs.append([u_new, v_new])
new_uvs_tensor = torch.tensor(new_uvs, device=device)
uvs_updated = torch.cat([uvs, new_uvs_tensor], dim=0)
uv_coordinates_start = uvs_updated.shape[0] - total_regions
# 4. 批量更新face_uv_indices
for i, (region_index, _) in enumerate(sorted(regions_face_color.items(), key=lambda x: x[0])):
region_faces_indexes = torch.tensor(list(regions[region_index][0]), device=device)
face_uv_indices[region_faces_indexes] = torch.full(
(1, 3), uv_coordinates_start + i,
device=device, dtype=face_uv_indices.dtype
)
# 将结果转回GPU
new_uv_map = torch.from_numpy(new_uv_map_cpu).to(device)
return new_uv_map, uvs_updated, face_uv_indices
def group_regions_by_y_axis( def group_regions_by_y_axis(
regions: List[Tuple[set, set]], regions: List[Tuple[set, set]],
vertices: torch.Tensor, vertices: torch.Tensor,

129
libs/IO/OBJ.cpp

@ -48,7 +48,6 @@ 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;
@ -131,7 +130,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, bool bUseExistingUV) const bool ObjModel::Save(const String& fileName, unsigned precision, bool texLossless) const
{ {
if (vertices.empty()) if (vertices.empty())
return false; return false;
@ -141,9 +140,6 @@ 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;
@ -273,129 +269,6 @@ 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)
{ {

3
libs/IO/OBJ.h

@ -93,10 +93,9 @@ 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, bool bUseExistingUV=false) const; bool Save(const String& fileName, unsigned precision=6, bool texLossless=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);

74
libs/MVS/Mesh.cpp

@ -1191,14 +1191,15 @@ 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 bLoadUV) bool Mesh::Load(const String& fileName)
{ {
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, bLoadUV); ret = LoadOBJ(fileName);
else if (ext == _T(".gltf") || ext == _T(".glb")) else
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);
@ -1207,43 +1208,6 @@ bool Mesh::Load(const String& fileName, bool bLoadUV)
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)
{ {
@ -1338,28 +1302,16 @@ 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 bLoadUV) bool Mesh::LoadOBJ(const String& fileName)
{ {
ASSERT(!fileName.empty()); ASSERT(!fileName.empty());
Release(); Release();
// open and parse OBJ file // open and parse OBJ file
ObjModel model; ObjModel model;
if (bLoadUV) if (!model.Load(fileName)) {
{ DEBUG_EXTRA("error: invalid OBJ file");
if (!model.LoadUV(fileName, faceTexcoords, true)) { return false;
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()) {
@ -1388,13 +1340,11 @@ bool Mesh::LoadOBJ(const String& fileName, bool bLoadUV)
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)
@ -1495,13 +1445,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, bool bUseExistingUV) const bool Mesh::Save(const String& fileName, const cList<String>& comments, bool bBinary) 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, bUseExistingUV); ret = SaveOBJ(fileName);
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"));
@ -1588,7 +1538,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, bool bUseExistingUV) const bool Mesh::SaveOBJ(const String& fileName) const
{ {
ASSERT(!fileName.empty()); ASSERT(!fileName.empty());
Util::ensureFolder(fileName); Util::ensureFolder(fileName);
@ -1647,7 +1597,7 @@ bool Mesh::SaveOBJ(const String& fileName, bool bUseExistingUV) const
pMaterial->diffuse_map = texturesDiffuse[idxTexture]; pMaterial->diffuse_map = texturesDiffuse[idxTexture];
} }
return model.Save(fileName, 6U, true, bUseExistingUV); return model.Save(fileName, 6U, true);
} }
// export the mesh as a GLTF file // export the mesh as a GLTF file
template <typename T> template <typename T>

10
libs/MVS/Mesh.h

@ -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 bLoadUV=false); bool Load(const String& fileName);
bool Save(const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true, bool bUseExistingUV=false) const; bool Save(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; 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,15 +271,13 @@ 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 bLoadUV); bool LoadOBJ(const String& fileName);
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, bool bUseExistingUV) const; bool SaveOBJ(const String& fileName) 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

2
libs/MVS/Scene.h

@ -169,7 +169,7 @@ public:
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 = "", bool bUseExistingUV = false, const std::string& strUVMeshFileName = ""); const std::string& inputFileName = "", const std::string& meshFileName = "");
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);

2572
libs/MVS/SceneTexture.cpp

File diff suppressed because it is too large Load Diff

23
libs/MVS/mask_face_occlusion.py

@ -4,7 +4,8 @@ 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
@ -33,6 +34,7 @@ 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"]
@ -2174,6 +2176,8 @@ 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)}")
@ -2197,9 +2201,12 @@ class ModelProcessor:
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)
# 保存 visible_faces_map # 保存 visible_faces_map
try: try:
with open(base_path + "/_visible_faces_map.txt", "w", encoding='utf-8') as map_file: file_name = "_visible_faces_map.txt"
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"
@ -2209,7 +2216,9 @@ class ModelProcessor:
# 保存 face_visible_relative # 保存 face_visible_relative
try: try:
with open(base_path + "/_face_visible_relative.txt", "w", encoding='utf-8') as relative_file: file_name = "_face_visible_relative.txt"
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:
@ -2217,7 +2226,9 @@ class ModelProcessor:
# 保存 edge_faces_map # 保存 edge_faces_map
try: try:
with open(base_path + "/_edge_faces_map.txt", "w", encoding='utf-8') as map_file2: file_name = "_edge_faces_map.txt"
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)
@ -2226,7 +2237,9 @@ class ModelProcessor:
# 保存 delete_edge_faces_map # 保存 delete_edge_faces_map
try: try:
with open(base_path + "/_delete_edge_faces_map.txt", "w", encoding='utf-8') as map_file3: file_name = "_delete_edge_faces_map.txt"
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)

Loading…
Cancel
Save