|
|
|
@ -40,6 +40,7 @@ |
|
|
|
#include <pybind11/embed.h> |
|
|
|
#include <pybind11/embed.h> |
|
|
|
#include <pybind11/stl.h> |
|
|
|
#include <pybind11/stl.h> |
|
|
|
#include "ConfigEnv.h" |
|
|
|
#include "ConfigEnv.h" |
|
|
|
|
|
|
|
#include "cuda/MeshTextureCUDA.h" |
|
|
|
|
|
|
|
|
|
|
|
namespace py = pybind11; |
|
|
|
namespace py = pybind11; |
|
|
|
|
|
|
|
|
|
|
|
@ -73,6 +74,7 @@ using namespace MVS; |
|
|
|
#define MASK_FACE_OCCLUSION |
|
|
|
#define MASK_FACE_OCCLUSION |
|
|
|
// #define DISPLAY_DEMO
|
|
|
|
// #define DISPLAY_DEMO
|
|
|
|
#define CACHE_MASK |
|
|
|
#define CACHE_MASK |
|
|
|
|
|
|
|
#define USE_CUDA |
|
|
|
|
|
|
|
|
|
|
|
// inference algorithm
|
|
|
|
// inference algorithm
|
|
|
|
#if TEXOPT_INFERENCE == TEXOPT_INFERENCE_LBP |
|
|
|
#if TEXOPT_INFERENCE == TEXOPT_INFERENCE_LBP |
|
|
|
@ -6078,7 +6080,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT |
|
|
|
LabelArr labels; |
|
|
|
LabelArr labels; |
|
|
|
|
|
|
|
|
|
|
|
// 为每个面片单独决定是否使用虚拟面算法
|
|
|
|
// 为每个面片单独决定是否使用虚拟面算法
|
|
|
|
Mesh::FaceIdxArr virtualFacesI; // 使用虚拟面算法的面片
|
|
|
|
// Mesh::FaceIdxArr virtualFacesI; // 使用虚拟面算法的面片
|
|
|
|
Mesh::FaceIdxArr perFaceFaces; // 使用逐面算法的面片
|
|
|
|
Mesh::FaceIdxArr perFaceFaces; // 使用逐面算法的面片
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
@ -6104,12 +6106,9 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT |
|
|
|
// construct and use virtual faces for patch creation instead of actual mesh faces;
|
|
|
|
// construct and use virtual faces for patch creation instead of actual mesh faces;
|
|
|
|
// the virtual faces are composed of coplanar triangles sharing same views
|
|
|
|
// the virtual faces are composed of coplanar triangles sharing same views
|
|
|
|
if (bUseVirtualFaces) { |
|
|
|
if (bUseVirtualFaces) { |
|
|
|
|
|
|
|
|
|
|
|
Mesh::FaceIdxArr mapFaceToVirtualFace(faces.size()); // for each mesh face ID, store the virtual face ID witch contains it
|
|
|
|
Mesh::FaceIdxArr mapFaceToVirtualFace(faces.size()); // for each mesh face ID, store the virtual face ID witch contains it
|
|
|
|
|
|
|
|
|
|
|
|
// 标记使用虚拟面算法的面片
|
|
|
|
// 标记使用虚拟面算法的面片
|
|
|
|
std::vector<bool> isVirtualFace(faces.size(), true); |
|
|
|
std::vector<bool> isVirtualFace(faces.size(), true); |
|
|
|
|
|
|
|
|
|
|
|
// 1) create FaceToVirtualFaceMap
|
|
|
|
// 1) create FaceToVirtualFaceMap
|
|
|
|
FaceDataViewArr virtualFacesDatas; |
|
|
|
FaceDataViewArr virtualFacesDatas; |
|
|
|
VirtualFaceIdxsArr virtualFaces; // stores each virtual face as an array of mesh face ID
|
|
|
|
VirtualFaceIdxsArr virtualFaces; // stores each virtual face as an array of mesh face ID
|
|
|
|
@ -6117,7 +6116,9 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT |
|
|
|
// CreateVirtualFaces3(facesDatas, virtualFacesDatas, virtualFaces, minCommonCameras);
|
|
|
|
// CreateVirtualFaces3(facesDatas, virtualFacesDatas, virtualFaces, minCommonCameras);
|
|
|
|
// CreateVirtualFaces4(facesDatas, virtualFacesDatas, virtualFaces, mapFaceToVirtualFace, minCommonCameras);
|
|
|
|
// CreateVirtualFaces4(facesDatas, virtualFacesDatas, virtualFaces, mapFaceToVirtualFace, minCommonCameras);
|
|
|
|
// CreateVirtualFaces6(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
|
|
|
// CreateVirtualFaces6(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras);
|
|
|
|
|
|
|
|
TD_TIMER_STARTD(); |
|
|
|
CreateVirtualFaces7(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); |
|
|
|
CreateVirtualFaces7(facesDatas, virtualFacesDatas, virtualFaces, isVirtualFace, minCommonCameras); |
|
|
|
|
|
|
|
DEBUG_EXTRA("CreateVirtualFaces7 completed: %s", TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
|
|
|
|
|
|
|
size_t controlCounter(0); |
|
|
|
size_t controlCounter(0); |
|
|
|
FOREACH(idxVF, virtualFaces) { |
|
|
|
FOREACH(idxVF, virtualFaces) { |
|
|
|
@ -6137,7 +6138,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
printf("perFaceFaces.size = %d\n", perFaceFaces.size()); |
|
|
|
// printf("perFaceFaces.size = %d\n", perFaceFaces.size());
|
|
|
|
|
|
|
|
|
|
|
|
ASSERT(controlCounter == faces.size()); |
|
|
|
ASSERT(controlCounter == faces.size()); |
|
|
|
// 2) create function to find virtual faces neighbors
|
|
|
|
// 2) create function to find virtual faces neighbors
|
|
|
|
@ -8154,7 +8155,20 @@ void MeshTexture::LocalSeamLeveling3() |
|
|
|
// extract image
|
|
|
|
// extract image
|
|
|
|
const Image8U3& image0(images[texturePatch.label].image); |
|
|
|
const Image8U3& image0(images[texturePatch.label].image); |
|
|
|
Image32F3 image, imageOrg; |
|
|
|
Image32F3 image, imageOrg; |
|
|
|
|
|
|
|
#ifdef USE_CUDA |
|
|
|
|
|
|
|
if (MeshTextureCUDA::ConvertToCUDA(image0(texturePatch.rect), image, 1.0/255.0)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// printf("ConvertToCUDA Successed!\n");
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
image0(texturePatch.rect).convertTo(image, CV_32FC3, 1.0/255.0); |
|
|
|
image0(texturePatch.rect).convertTo(image, CV_32FC3, 1.0/255.0); |
|
|
|
|
|
|
|
// printf("ConvertToCUDA Failed!\n");
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
image0(texturePatch.rect).convertTo(image, CV_32FC3, 1.0/255.0); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
image.copyTo(imageOrg); |
|
|
|
image.copyTo(imageOrg); |
|
|
|
// render patch coverage
|
|
|
|
// render patch coverage
|
|
|
|
Image8U mask(image.size()); { |
|
|
|
Image8U mask(image.size()); { |
|
|
|
@ -8252,11 +8266,43 @@ void MeshTexture::LocalSeamLeveling3() |
|
|
|
} |
|
|
|
} |
|
|
|
// make sure the border is continuous and
|
|
|
|
// make sure the border is continuous and
|
|
|
|
// keep only the exterior tripe of the given size
|
|
|
|
// keep only the exterior tripe of the given size
|
|
|
|
|
|
|
|
#ifdef USE_CUDA |
|
|
|
|
|
|
|
if (MeshTextureCUDA::ProcessMaskCUDA(mask, 20)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// printf("Success ProcessMaskCUDA!\n");
|
|
|
|
|
|
|
|
// 成功使用CUDA加速
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// 回退到CPU版本
|
|
|
|
|
|
|
|
// printf("Failed ProcessMaskCUDA!\n");
|
|
|
|
ProcessMask(mask, 20); |
|
|
|
ProcessMask(mask, 20); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
ProcessMask(mask, 20); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
// compute texture patch blending
|
|
|
|
// compute texture patch blending
|
|
|
|
|
|
|
|
#ifdef USE_CUDA |
|
|
|
|
|
|
|
if (MeshTextureCUDA::PoissonBlendCUDA(image, imageOrg, mask, 1.0f)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// printf("Success PoissonBlendCUDA!");
|
|
|
|
|
|
|
|
// 成功使用CUDA加速
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// 回退到CPU版本
|
|
|
|
|
|
|
|
// printf("Failed PoissonBlendCUDA!");
|
|
|
|
|
|
|
|
PoissonBlending(imageOrg, image, mask, 1.0f); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#else |
|
|
|
PoissonBlending(imageOrg, image, mask); |
|
|
|
PoissonBlending(imageOrg, image, mask); |
|
|
|
|
|
|
|
#endif |
|
|
|
// apply color correction to the patch image
|
|
|
|
// apply color correction to the patch image
|
|
|
|
cv::Mat imagePatch(image0(texturePatch.rect)); |
|
|
|
cv::Mat imagePatch(image0(texturePatch.rect)); |
|
|
|
|
|
|
|
#ifdef TEXOPT_USE_OPENMP |
|
|
|
|
|
|
|
#pragma omp parallel for collapse(2) |
|
|
|
|
|
|
|
#endif |
|
|
|
for (int r=0; r<image.rows; ++r) { |
|
|
|
for (int r=0; r<image.rows; ++r) { |
|
|
|
for (int c=0; c<image.cols; ++c) { |
|
|
|
for (int c=0; c<image.cols; ++c) { |
|
|
|
if (mask(r,c) == empty) |
|
|
|
if (mask(r,c) == empty) |
|
|
|
@ -8372,6 +8418,8 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOG_OUT() << "First loop completed" << std::endl; |
|
|
|
LOG_OUT() << "First loop completed" << std::endl; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TD_TIMER_STARTD(); |
|
|
|
// perform seam leveling
|
|
|
|
// perform seam leveling
|
|
|
|
if (texturePatches.size() > 2 && (bGlobalSeamLeveling || bLocalSeamLeveling)) { |
|
|
|
if (texturePatches.size() > 2 && (bGlobalSeamLeveling || bLocalSeamLeveling)) { |
|
|
|
// create seam vertices and edges
|
|
|
|
// create seam vertices and edges
|
|
|
|
@ -8381,16 +8429,18 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel |
|
|
|
if (bGlobalSeamLeveling) { |
|
|
|
if (bGlobalSeamLeveling) { |
|
|
|
TD_TIMER_STARTD(); |
|
|
|
TD_TIMER_STARTD(); |
|
|
|
GlobalSeamLeveling3(); |
|
|
|
GlobalSeamLeveling3(); |
|
|
|
DEBUG_ULTIMATE("\tglobal seam leveling completed (%s)", TD_TIMER_GET_FMT().c_str()); |
|
|
|
DEBUG_EXTRA("\tglobal seam leveling completed (%s)", TD_TIMER_GET_FMT().c_str()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// perform local seam leveling
|
|
|
|
// perform local seam leveling
|
|
|
|
if (bLocalSeamLeveling) { |
|
|
|
if (bLocalSeamLeveling) { |
|
|
|
TD_TIMER_STARTD(); |
|
|
|
TD_TIMER_STARTD(); |
|
|
|
LocalSeamLeveling(); |
|
|
|
// LocalSeamLeveling();
|
|
|
|
DEBUG_ULTIMATE("\tlocal seam leveling completed (%s)", TD_TIMER_GET_FMT().c_str()); |
|
|
|
LocalSeamLeveling3(); |
|
|
|
|
|
|
|
DEBUG_EXTRA("\tlocal seam leveling completed (%s)", TD_TIMER_GET_FMT().c_str()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
DEBUG_EXTRA("seam (%s)", TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
|
|
|
|
|
|
|
// merge texture patches with overlapping rectangles
|
|
|
|
// merge texture patches with overlapping rectangles
|
|
|
|
for (unsigned i=0; i<texturePatches.size()-1; ++i) { |
|
|
|
for (unsigned i=0; i<texturePatches.size()-1; ++i) { |
|
|
|
@ -9635,12 +9685,12 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi |
|
|
|
dict3 = result["result3"].cast<py::dict>(); |
|
|
|
dict3 = result["result3"].cast<py::dict>(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
printf("dict1 size=%d, dict2 size=%d, dict3 size=%d\n", dict1.size(), dict2.size(), dict3.size()); |
|
|
|
// printf("dict1 size=%d, dict2 size=%d, dict3 size=%d\n", dict1.size(), dict2.size(), dict3.size());
|
|
|
|
|
|
|
|
|
|
|
|
// 处理返回的可见面字典
|
|
|
|
// 处理返回的可见面字典
|
|
|
|
for (auto item : dict1) { |
|
|
|
for (auto item : dict1) { |
|
|
|
std::string image_name = item.first.cast<std::string>(); |
|
|
|
std::string image_name = item.first.cast<std::string>(); |
|
|
|
printf("dict1 mask image name=%s\n", image_name.c_str()); |
|
|
|
// printf("dict1 mask image name=%s\n", image_name.c_str());
|
|
|
|
py::list visible_faces = item.second.cast<py::list>(); |
|
|
|
py::list visible_faces = item.second.cast<py::list>(); |
|
|
|
|
|
|
|
|
|
|
|
std::unordered_set<int> face_set; |
|
|
|
std::unordered_set<int> face_set; |
|
|
|
@ -9657,7 +9707,7 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi |
|
|
|
|
|
|
|
|
|
|
|
for (auto item : dict2) { |
|
|
|
for (auto item : dict2) { |
|
|
|
std::string image_name = item.first.cast<std::string>(); |
|
|
|
std::string image_name = item.first.cast<std::string>(); |
|
|
|
printf("dict2 mask image name=%s\n", image_name.c_str()); |
|
|
|
// printf("dict2 mask image name=%s\n", image_name.c_str());
|
|
|
|
py::list edge_faces = item.second.cast<py::list>(); |
|
|
|
py::list edge_faces = item.second.cast<py::list>(); |
|
|
|
|
|
|
|
|
|
|
|
std::unordered_set<int> face_set; |
|
|
|
std::unordered_set<int> face_set; |
|
|
|
@ -9669,7 +9719,7 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi |
|
|
|
|
|
|
|
|
|
|
|
for (auto item : dict3) { |
|
|
|
for (auto item : dict3) { |
|
|
|
std::string image_name = item.first.cast<std::string>(); |
|
|
|
std::string image_name = item.first.cast<std::string>(); |
|
|
|
printf("dict3 mask image name=%s\n", image_name.c_str()); |
|
|
|
// printf("dict3 mask image name=%s\n", image_name.c_str());
|
|
|
|
py::list delete_edge_faces = item.second.cast<py::list>(); |
|
|
|
py::list delete_edge_faces = item.second.cast<py::list>(); |
|
|
|
|
|
|
|
|
|
|
|
std::unordered_set<int> face_set; |
|
|
|
std::unordered_set<int> face_set; |
|
|
|
@ -9762,7 +9812,6 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi |
|
|
|
texture.GenerateTexture(bGlobalSeamLeveling, bLocalSeamLeveling, nTextureSizeMultiple, nRectPackingHeuristic, colEmpty, fSharpnessWeight, maxTextureSize, baseFileName, bOriginFaceview); |
|
|
|
texture.GenerateTexture(bGlobalSeamLeveling, bLocalSeamLeveling, nTextureSizeMultiple, nRectPackingHeuristic, colEmpty, fSharpnessWeight, maxTextureSize, baseFileName, bOriginFaceview); |
|
|
|
DEBUG_EXTRA("Generating texture atlas and image completed: %u patches, %u image size, %u textures (%s)", texture.texturePatches.size(), mesh.texturesDiffuse[0].width(), mesh.texturesDiffuse.size(), TD_TIMER_GET_FMT().c_str()); |
|
|
|
DEBUG_EXTRA("Generating texture atlas and image completed: %u patches, %u image size, %u textures (%s)", texture.texturePatches.size(), mesh.texturesDiffuse[0].width(), mesh.texturesDiffuse.size(), TD_TIMER_GET_FMT().c_str()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef DISPLAY_DEMO |
|
|
|
#ifdef DISPLAY_DEMO |
|
|
|
try { |
|
|
|
try { |
|
|
|
py::scoped_interpreter guard{}; // 自动管理解释器生命周期
|
|
|
|
py::scoped_interpreter guard{}; // 自动管理解释器生命周期
|
|
|
|
|