Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the textures loading in .glb file #5443

Merged
merged 12 commits into from
Aug 26, 2022
23 changes: 23 additions & 0 deletions cpp/open3d/io/ImageIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,28 @@ bool WriteImage(const std::string &filename,
return map_itr->second(filename, image, quality);
}

std::shared_ptr<geometry::Image> CreateImageFromMemory(
const std::string &image_format,
const unsigned char *image_data_ptr,
size_t image_data_size) {
auto image = std::make_shared<geometry::Image>();
ReadImageFromMemroy(image_format, image_data_ptr, image_data_size, *image);
return image;
}

bool ReadImageFromMemroy(const std::string &image_format,
const unsigned char *image_data_ptr,
size_t image_data_size,
geometry::Image &image) {
// Just support .png for now
// To do: .jpg
if (image_format == "png") {
return ReadPNGFromMemory(image_data_ptr, image_data_size, image);
} else {
utility::LogWarning("The format of {} is not supported", image_format);
return false;
}
}

} // namespace io
} // namespace open3d
19 changes: 19 additions & 0 deletions cpp/open3d/io/ImageIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,25 @@ namespace io {
std::shared_ptr<geometry::Image> CreateImageFromFile(
const std::string &filename);

/// Factory function to create an image from memory.
std::shared_ptr<geometry::Image> CreateImageFromMemory(
const std::string &image_format,
const unsigned char *image_data_ptr,
size_t image_data_size);

/// The general entrance for reading an Image from a file
/// The function calls read functions based on the extension name of filename.
/// \return return true if the read function is successful, false otherwise.
bool ReadImage(const std::string &filename, geometry::Image &image);

/// The general entrance for reading an Image from memory
/// The function calls read functions based on format of image.
/// \return return true if the read function is successful, false otherwise.
bool ReadImageFromMemroy(const std::string &image_format,
const unsigned char *image_data_ptr,
size_t image_data_size,
geometry::Image &image);

constexpr int kOpen3DImageIODefaultQuality = -1;

/// The general entrance for writing an Image to a file
Expand Down Expand Up @@ -71,5 +85,10 @@ bool WriteImageToJPG(const std::string &filename,
const geometry::Image &image,
int quality = kOpen3DImageIODefaultQuality);

/// The general entrance for reading an Image from memory
bool ReadPNGFromMemory(const unsigned char *image_data_ptr,
size_t image_data_size,
geometry::Image &image);

} // namespace io
} // namespace open3d
62 changes: 43 additions & 19 deletions cpp/open3d/io/file_format/FileASSIMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
// IN THE SOFTWARE.
// ----------------------------------------------------------------------------

#include <png.h>

#include <fstream>
#include <numeric>
#include <vector>
Expand Down Expand Up @@ -77,34 +79,56 @@ struct TextureImages {
};

void LoadTextures(const std::string& filename,
aiMaterial* mat,
const aiScene* scene,
const aiMaterial* mat,
TextureImages& maps) {
// Retrieve textures
std::string base_path =
utility::filesystem::GetFileParentDirectory(filename);

auto texture_loader = [&base_path, &mat](
auto texture_loader = [&base_path, &scene, &mat](
aiTextureType type,
std::shared_ptr<geometry::Image>& img) {
if (mat->GetTextureCount(type) > 0) {
aiString path;
mat->GetTexture(type, 0, &path);
std::string strpath(path.C_Str());
// normalize path separators
auto p_win = strpath.find("\\");
while (p_win != std::string::npos) {
strpath[p_win] = '/';
p_win = strpath.find("\\", p_win + 1);
}
// if absolute path convert to relative to base path
if (strpath.length() > 1 &&
(strpath[0] == '/' || strpath[1] == ':')) {
strpath = utility::filesystem::GetFileNameWithoutDirectory(
strpath);
// If the texture is an embedded texture, use `GetEmbeddedTexture`.
// To do: support .jpg
if (auto texture = scene->GetEmbeddedTexture(path.C_Str())) {
if (texture->CheckFormat("png")) {
auto image = io::CreateImageFromMemory(
"png",
reinterpret_cast<const unsigned char*>(
texture->pcData),
texture->mWidth);
if (image->HasData()) {
img = image;
}
} else {
utility::LogWarning(
"This format of image is not supported.");
}

}
auto image = io::CreateImageFromFile(base_path + strpath);
if (image->HasData()) {
img = image;
// Else, build the path to it.
else {
std::string strpath(path.C_Str());
// Normalize path separators.
auto p_win = strpath.find("\\");
while (p_win != std::string::npos) {
strpath[p_win] = '/';
p_win = strpath.find("\\", p_win + 1);
}
// If absolute path convert to relative to base path.
if (strpath.length() > 1 &&
(strpath[0] == '/' || strpath[1] == ':')) {
strpath = utility::filesystem::GetFileNameWithoutDirectory(
strpath);
}
auto image = io::CreateImageFromFile(base_path + strpath);
if (image->HasData()) {
img = image;
}
}
}
};
Expand Down Expand Up @@ -254,7 +278,7 @@ bool ReadTriangleMeshUsingASSIMP(

// Retrieve textures
TextureImages maps;
LoadTextures(filename, mat, maps);
LoadTextures(filename, scene, mat, maps);
mesh_material.albedo = maps.albedo;
mesh_material.normalMap = maps.normal;
mesh_material.ambientOcclusion = maps.ao;
Expand Down Expand Up @@ -413,7 +437,7 @@ bool ReadModelUsingAssimp(const std::string& filename,

// Retrieve textures
TextureImages maps;
LoadTextures(filename, mat, maps);
LoadTextures(filename, scene, mat, maps);
o3d_mat.albedo_img = maps.albedo;
o3d_mat.normal_img = maps.normal;
o3d_mat.ao_img = maps.ao;
Expand Down
30 changes: 30 additions & 0 deletions cpp/open3d/io/file_format/FilePNG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,35 @@ bool WriteImageToPNG(const std::string &filename,
return true;
}

bool ReadPNGFromMemory(const unsigned char *image_data_ptr,
size_t image_data_size,
geometry::Image &image) {
png_image pngimage;
memset(&pngimage, 0, sizeof(pngimage));
pngimage.version = PNG_IMAGE_VERSION;
if (png_image_begin_read_from_memory(&pngimage, image_data_ptr,
image_data_size) == 0) {
utility::LogWarning("Read PNG failed: unable to parse header.");
return false;
}

// Clear colormap flag if necessary to ensure libpng expands the colo
// indexed pixels to full color
if (pngimage.format & PNG_FORMAT_FLAG_COLORMAP) {
pngimage.format &= ~PNG_FORMAT_FLAG_COLORMAP;
}

image.Prepare(pngimage.width, pngimage.height,
PNG_IMAGE_SAMPLE_CHANNELS(pngimage.format),
PNG_IMAGE_SAMPLE_COMPONENT_SIZE(pngimage.format));

if (png_image_finish_read(&pngimage, NULL, image.data_.data(), 0, NULL) ==
0) {
utility::LogWarning("PNG error: {}", pngimage.message);
return false;
}
return true;
}

} // namespace io
} // namespace open3d