Skip to content

Commit

Permalink
Merge pull request #1821 from tommatterson/vdb_tool_use_pdal
Browse files Browse the repository at this point in the history
Added feature to read points into vdb_tool using PDAL
  • Loading branch information
danrbailey authored Oct 30, 2024
2 parents e8854bc + ced3af8 commit ae6b1a1
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 5 deletions.
1 change: 1 addition & 0 deletions ci/install_windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ $vcpkgPackages = @(
"zlib",
"libpng",
"openexr",
"pdal",
"tbb",
"gtest",
"cppunit",
Expand Down
15 changes: 15 additions & 0 deletions openvdb_cmd/vdb_tool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ option(OPENVDB_TOOL_NANO_USE_BLOSC "Compile NanoVDB with Blosc compression suppo
option(OPENVDB_TOOL_USE_PNG "Compile with PNG support" OFF)
option(OPENVDB_TOOL_USE_EXR "Compile with EXR support" OFF)
option(OPENVDB_TOOL_USE_JPG "Compile with JPG support" OFF)
option(OPENVDB_TOOL_USE_PDAL "Compile with extended points support" OFF)
option(OPENVDB_TOOL_USE_ABC "Compile with Alembic support" OFF)
option(OPENVDB_TOOL_USE_ALL "Compile with all optional components" OFF)
if(OPENVDB_TOOL_USE_ALL)
Expand All @@ -42,6 +43,8 @@ if(OPENVDB_TOOL_USE_ALL)
set(OPENVDB_TOOL_USE_EXR ON)
set(OPENVDB_TOOL_USE_JPG ON)
set(OPENVDB_TOOL_USE_ABC ON)
set(OPENVDB_TOOL_USE_PDAL ON)

endif()

if(OPENVDB_TOOL_USE_NANO)
Expand Down Expand Up @@ -83,6 +86,18 @@ if(OPENVDB_TOOL_USE_PNG)
target_link_libraries(vdb_tool_common INTERFACE png)
endif()

if(OPENVDB_TOOL_USE_PDAL)
target_compile_definitions(vdb_tool_common INTERFACE "VDB_TOOL_USE_PDAL")
if(WIN32)
find_package(libdpal CONFIG REQUIRED)
else()
find_package(PDAL REQUIRED)
endif()
message(STATUS "PDAL: ${PDAL_LIBRARIES} ${PDAL_INCLUDE_DIRS}")
target_link_libraries(vdb_tool_common INTERFACE ${PDAL_LIBRARIES})
target_include_directories(vdb_tool_common INTERFACE ${PDAL_INCLUDE_DIRS})
endif()

if(OPENVDB_TOOL_USE_JPG)
target_compile_definitions(vdb_tool_common INTERFACE "VDB_TOOL_USE_JPG")
find_package(JPEG REQUIRED)
Expand Down
95 changes: 93 additions & 2 deletions openvdb_cmd/vdb_tool/include/Geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@
#include <Alembic/Util/All.h>
#endif

#ifdef VDB_TOOL_USE_PDAL
#include "pdal/pdal.hpp"
#include "pdal/PipelineManager.hpp"
#include "pdal/PipelineReaderJSON.hpp"
#include "pdal/util/FileUtils.hpp"
#include <sstream>
#endif

#if defined(_WIN32)
#include <io.h>
#else
Expand Down Expand Up @@ -82,9 +90,13 @@ class Geometry
const std::vector<Vec3s>& vtx() const { return mVtx; }
const std::vector<Vec3I>& tri() const { return mTri; }
const std::vector<Vec4I>& quad() const { return mQuad; }
const std::vector<Vec3s>& rgb() const { return mRGB; }

std::vector<Vec3s>& vtx() { return mVtx; }
std::vector<Vec3I>& tri() { return mTri; }
std::vector<Vec4I>& quad() { return mQuad; }
std::vector<Vec3s>& rgb() { return mRGB; }

const BBoxT& bbox() const;

void clear();
Expand All @@ -108,6 +120,7 @@ class Geometry
void readPTS(const std::string &fileName);
void readGEO(const std::string &fileName);
void readABC(const std::string &fileName);
void readPDAL(const std::string &fileName);
void readVDB(const std::string &fileName);
void readNVDB(const std::string &fileName);

Expand Down Expand Up @@ -138,6 +151,7 @@ class Geometry
std::vector<PosT> mVtx;
std::vector<Vec3I> mTri;
std::vector<Vec4I> mQuad;
std::vector<Vec3s> mRGB;
mutable BBoxT mBBox;
std::string mName;

Expand Down Expand Up @@ -393,8 +407,16 @@ void Geometry::read(const std::string &fileName)
this->readGEO(fileName);
break;
default:
throw std::invalid_argument("Geometry::read: File \""+fileName+"\" has an invalid extension");
break;
#if VDB_TOOL_USE_PDAL
pdal::StageFactory factory;
const std::string driver = factory.inferReaderDriver(fileName);
if (driver != "") {
this->readPDAL(fileName);
break;
}
#endif
throw std::invalid_argument("Geometry::read: File \""+fileName+"\" has an invalid extension");
break;
}
}// Geometry::read

Expand Down Expand Up @@ -442,6 +464,61 @@ void Geometry::readOBJ(std::istream &is)
mBBox = BBoxT();//invalidate BBox
}// Geometry::readOBJ

void Geometry::readPDAL(const std::string &fileName)
{
#if VDB_TOOL_USE_PDAL
if (!pdal::FileUtils::fileExists(fileName)) throw std::invalid_argument("Error opening file \""+fileName+"\" - it doesn't exist!");

pdal::StageFactory factory;
std::string type = factory.inferReaderDriver(fileName);
std::string pipelineJson = R"({
"pipeline" : [
{
"type" : ")" + type + R"(",
"filename" : ")" + fileName + R"("
}
]
})";

Vec3f p;
Vec3s rgb;
try {
pdal::PipelineManager manager;
std::stringstream s(pipelineJson);
manager.readPipeline(s);
manager.execute(pdal::ExecMode::Standard);

for (const std::shared_ptr<pdal::PointView>& view : manager.views()) {
bool hasColor = false;
if (view->hasDim(pdal::Dimension::Id::Red) && view->hasDim(pdal::Dimension::Id::Green) && view->hasDim(pdal::Dimension::Id::Blue))
hasColor = true;
for (const pdal::PointRef& point : *view) {
p[0] = point.getFieldAs<float>(pdal::Dimension::Id::X);
p[1] = point.getFieldAs<float>(pdal::Dimension::Id::Y);
p[2] = point.getFieldAs<float>(pdal::Dimension::Id::Z);
mVtx.push_back(p);
if (hasColor) {
rgb[0] = point.getFieldAs<float>(pdal::Dimension::Id::Red);
rgb[1] = point.getFieldAs<float>(pdal::Dimension::Id::Green);
rgb[2] = point.getFieldAs<float>(pdal::Dimension::Id::Blue);
mRGB.push_back(rgb);
}
}
}

}
catch (const pdal::pdal_error& e) {
throw std::runtime_error("PDAL failed: " + std::string(e.what()));
}
catch (const std::exception& e) {
throw std::runtime_error("Reading file failed: " + std::string(e.what()));
}
#else
throw std::runtime_error("Cannot read file \"" + fileName + "\". PDAL support is not enabled in this build, please recompile with PDAL support");
#endif
mBBox = BBoxT(); //invalidate BBox
}// Geometry::readPDAL

void Geometry::readPLY(const std::string &fileName)
{
if (fileName == "stdin.ply") {
Expand Down Expand Up @@ -753,6 +830,8 @@ void Geometry::readPTS(const std::string &fileName)
if (!infile.is_open()) throw std::runtime_error("Error opening particle file \""+fileName+"\"");
std::string line;
std::istringstream iss;
bool readColor = false;
Vec3s rgb;
while(std::getline(infile, line)) {
const size_t n = mVtx.size(), m = std::stoi(line);
mVtx.resize(n + m);
Expand All @@ -764,6 +843,18 @@ void Geometry::readPTS(const std::string &fileName)
if (!(iss >> p[0] >> p[1] >> p[2])) {;//ignore intensity, r, g, b
throw std::invalid_argument("Geometry::readPTS: error parsing line: \""+line+"\"");
}
if (readColor) {
if (!(iss >> i) ) { // converting intensity to a multiplier on rgb might be appropriate, but i can't find a good spec for it
readColor = false;
continue;
}
if (!(iss >> rgb[0] >> rgb[1] >> rgb[2])) {
readColor = false;
continue;
}
mRGB.push_back(rgb/255.0);
}

}// loop over points
}// loop over scans
mBBox = BBoxT();//invalidate BBox
Expand Down
49 changes: 46 additions & 3 deletions openvdb_cmd/vdb_tool/include/Tool.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <openvdb/tools/Mask.h> // for tools::interiorMask()
#include <openvdb/tools/MultiResGrid.h>
#include <openvdb/tools/SignedFloodFill.h>
#include <openvdb/tools/PointIndexGrid.h>
#include <openvdb/points/PointConversion.h>
#include <openvdb/points/PointCount.h>

Expand All @@ -69,6 +70,10 @@
#include <png.h>
#endif

#ifdef VDB_TOOL_USE_PDAL
#include <pdal/pdal.hpp>
#endif

#ifdef VDB_TOOL_USE_JPG
#include <jpeglib.h>
#endif
Expand Down Expand Up @@ -969,6 +974,14 @@ void Tool::read()
this->readNVDB(fileName);
break;
default:
#if VDB_TOOL_USE_PDAL
pdal::StageFactory factory;
if (factory.inferReaderDriver(fileName) != "")
{
this->readGeo(fileName);
break;
}
#endif
throw std::invalid_argument("File \""+fileName+"\" has an invalid extension");
break;
}
Expand Down Expand Up @@ -1421,26 +1434,56 @@ void Tool::pointsToVdb()
const int bits = mParser.get<int>("bits");
std::string grid_name = mParser.get<std::string>("name");
using GridT = points::PointDataGrid;
using IdGridT = tools::PointIndexGrid;
if (mParser.verbose) mTimer.start("Points to VDB");
auto it = this->getGeom(age);
Points points((*it)->vtx());
const float voxelSize = points::computeVoxelSize(points, pointsPerVoxel);
auto xform = math::Transform::createLinearTransform(voxelSize);

GridT::Ptr grid;
IdGridT::Ptr indexGrid;

points::PointAttributeVector<openvdb::Vec3s> positionsWrapper((*it)->vtx());
openvdb::NamePair rgbAttribute ;
switch (bits) {
case 8:
grid = points::createPointDataGrid<points::FixedPointCodec</*1-byte=*/true>, GridT>((*it)->vtx(), *xform);
indexGrid = tools::createPointIndexGrid<tools::PointIndexGrid>(positionsWrapper, *xform);
grid = points::createPointDataGrid<points::FixedPointCodec</*1-byte=*/true>, GridT>(*indexGrid, positionsWrapper, *xform);
openvdb::points::TypedAttributeArray<Vec3s, points::NullCodec>::registerType();
rgbAttribute =
openvdb::points::TypedAttributeArray<Vec3s, points::NullCodec>::attributeType();
openvdb::points::appendAttribute(grid->tree(), "Cd", rgbAttribute);
break;
case 16:
grid = points::createPointDataGrid<points::FixedPointCodec</*1-byte=*/false>, GridT>((*it)->vtx(), *xform);
indexGrid = tools::createPointIndexGrid<tools::PointIndexGrid>(positionsWrapper, *xform);
grid = points::createPointDataGrid<points::FixedPointCodec</*1-byte=*/false>, GridT>(*indexGrid, positionsWrapper, *xform);
openvdb::points::TypedAttributeArray<Vec3s, points::NullCodec>::registerType();
rgbAttribute =
openvdb::points::TypedAttributeArray<Vec3s, points::NullCodec>::attributeType();
openvdb::points::appendAttribute(grid->tree(), "Cd", rgbAttribute);
break;
case 32:
grid = points::createPointDataGrid<points::NullCodec, GridT>((*it)->vtx(), *xform);
indexGrid = tools::createPointIndexGrid<tools::PointIndexGrid>(positionsWrapper, *xform);
grid = points::createPointDataGrid<points::NullCodec, GridT>(*indexGrid, positionsWrapper, *xform);

openvdb::points::TypedAttributeArray<Vec3s, points::NullCodec>::registerType();
rgbAttribute =
openvdb::points::TypedAttributeArray<Vec3s, points::NullCodec>::attributeType();
openvdb::points::appendAttribute(grid->tree(), "Cd", rgbAttribute);
break;
default:
throw std::invalid_argument("pointsToVdb: unsupported bit-width: "+std::to_string(bits));
}

if ((*it)->rgb().size() == (*it)->vtx().size()) {

points::PointAttributeVector<Vec3s> rgbWrapper((*it)->rgb());
points::populateAttribute<openvdb::points::PointDataTree,
openvdb::tools::PointIndexTree, openvdb::points::PointAttributeVector<Vec3s>>(
grid->tree(), indexGrid->tree(), "Cd", rgbWrapper);

}
if (grid_name.empty()) grid_name = "points2vdb_"+(*it)->getName();
grid->setName(grid_name);
mGrid.push_back(grid);
Expand Down
24 changes: 24 additions & 0 deletions openvdb_cmd/vdb_tool/src/unittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,30 @@ TEST_F(Test_vdb_tool, Geometry)

EXPECT_EQ(openvdb::Vec4I(0,1,2,3), geo.quad()[0]);
}
#ifdef VDB_TOOL_USE_PDAL
{// read from PDAL-supported ASCII format file
// (NOTE: PDAL also supports other formats e.g. LAS, LAZ, E57, Draco, FBX, NumPy, OBJ,…)

// write a test file
std::ofstream os("data/test.txt");
os << "X,Y,Z\n";
for (size_t i=0; i<geo.vtxCount(); ++i) {
os << geo.vtx()[i][0] << "," << geo.vtx()[i][1] << "," << geo.vtx()[i][2] << "\n";
}
os.close();

// read the test file
openvdb::vdb_tool::Geometry geo2;
geo2.read("data/test.txt");
EXPECT_EQ(4, geo2.vtxCount());

EXPECT_EQ(openvdb::Vec3f(1,2,3), geo.vtx()[0]);
EXPECT_EQ(openvdb::Vec3f(4,5,6), geo.vtx()[1]);
EXPECT_EQ(openvdb::Vec3f(7,8,9), geo.vtx()[2]);
EXPECT_EQ(openvdb::Vec3f(10,11,12), geo.vtx()[3]);

}
#endif
}// Geometry

TEST_F(Test_vdb_tool, Memory)
Expand Down

0 comments on commit ae6b1a1

Please sign in to comment.