Skip to content

Commit

Permalink
Merge pull request #85 from pierotofy/cam
Browse files Browse the repository at this point in the history
Save cameras.json
  • Loading branch information
pierotofy authored Apr 24, 2024
2 parents 230eabc + 0b5d24f commit 4d70016
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 5 deletions.
22 changes: 22 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ set(OPENCV_DIR "OPENCV_DIR-NOTFOUND" CACHE PATH "Path to the OPENCV installation
set(OPENSPLAT_MAX_CUDA_COMPATIBILITY OFF CACHE BOOL "Build for maximum CUDA device compatibility")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

# Read version
file(READ "VERSION" APP_VERSION)

# Read git commit
set(GIT_REV "")
execute_process(COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE GIT_REV
ERROR_QUIET)
string(REGEX REPLACE "\n$" "" GIT_REV "${GIT_REV}")
if (NOT "${GIT_REV}" STREQUAL "")
set(DAPP_VERSION "${APP_VERSION} (git commit ${GIT_REV})")
set(DAPP_REVISION "${GIT_REV}")
else()
set(DAPP_VERSION "${APP_VERSION}")
set(DAPP_REVISION "dev")
endif()

message("OpenSplat Version: ${DAPP_VERSION}")
add_compile_options("-DAPP_VERSION=\"${DAPP_VERSION}\"")
add_compile_options("-DAPP_REVISION=\"${DAPP_REVISION}\"")

# Don't complain about the override from NANOFLANN_BUILD_EXAMPLES
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
# Use time-of-extraction for FetchContent'ed files modification time
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ cd build
./opensplat /path/to/banana -n 2000
```

The program will generate an output `splat.ply` file which can then be dragged and dropped in one of the many [viewers](https://github.com/MrNeRF/awesome-3D-gaussian-splatting?tab=readme-ov-file#viewers) such as https://playcanvas.com/viewer. You can also edit/cleanup the scene using https://playcanvas.com/supersplat/editor
The program will generate an output `splat.ply` file which can then be dragged and dropped in one of the many [viewers](https://github.com/MrNeRF/awesome-3D-gaussian-splatting?tab=readme-ov-file#viewers) such as https://playcanvas.com/viewer. You can also edit/cleanup the scene using https://playcanvas.com/supersplat/editor. The program will also output a `cameras.json` file in the same directory which can be used by some viewers.

To run on your own data, choose the path to an existing [COLMAP](https://colmap.github.io/), [OpenSfM](https://github.com/mapillary/OpenSfM), [ODM](https://github.com/OpenDroneMap/ODM) or [nerfstudio](https://docs.nerf.studio/quickstart/custom_dataset.html) project. The project must have sparse points included (random initialization is not supported, see https://github.com/pierotofy/OpenSplat/issues/7).

Expand Down
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.1.3
8 changes: 8 additions & 0 deletions constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,12 @@
#define PI 3.14159265358979323846
#define FLOAT_EPS 1e-9f

#ifndef APP_VERSION
#define APP_VERSION "dev"
#endif

#ifndef APP_REVISION
#define APP_REVISION "dev"
#endif

#endif
46 changes: 46 additions & 0 deletions input_data.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include <filesystem>
#include <nlohmann/json.hpp>
#include "input_data.hpp"
#include "cv_utils.hpp"

namespace fs = std::filesystem;
using namespace torch::indexing;
using json = nlohmann::json;

namespace ns{ InputData inputDataFromNerfStudio(const std::string &projectRoot); }
namespace cm{ InputData inputDataFromColmap(const std::string &projectRoot); }
Expand Down Expand Up @@ -145,3 +147,47 @@ std::tuple<std::vector<Camera>, Camera *> InputData::getCameras(bool validate, c
return std::make_tuple(cams, valCam);
}
}


void InputData::saveCameras(const std::string &filename, bool keepCrs){
json j = json::array();

for (size_t i = 0; i < cameras.size(); i++){
Camera &cam = cameras[i];

json camera = json::object();
camera["id"] = i;
camera["img_name"] = fs::path(cam.filePath).filename().string();
camera["width"] = cam.width;
camera["height"] = cam.height;
camera["fx"] = cam.fx;
camera["fy"] = cam.fy;

torch::Tensor R = cam.camToWorld.index({Slice(None, 3), Slice(None, 3)});
torch::Tensor T = cam.camToWorld.index({Slice(None, 3), Slice(3,4)}).squeeze();

// Flip z and y
R = torch::matmul(R, torch::diag(torch::tensor({1.0f, -1.0f, -1.0f})));

if (keepCrs) T = (T / scale) + translation;

std::vector<float> position(3);
std::vector<std::vector<float>> rotation(3, std::vector<float>(3));
for (int i = 0; i < 3; i++) {
position[i] = T[i].item<float>();
for (int j = 0; j < 3; j++) {
rotation[i][j] = R[i][j].item<float>();
}
}

camera["position"] = position;
camera["rotation"] = rotation;
j.push_back(camera);
}

std::ofstream of(filename);
of << j;
of.close();

std::cout << "Wrote " << filename << std::endl;
}
3 changes: 2 additions & 1 deletion input_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ struct Camera{
width(width), height(height), fx(fx), fy(fy), cx(cx), cy(cy),
k1(k1), k2(k2), k3(k3), p1(p1), p2(p2),
camToWorld(camToWorld), filePath(filePath) {}

torch::Tensor getIntrinsicsMatrix();
bool hasDistortionParameters();
std::vector<float> undistortionParameters();
Expand All @@ -57,6 +56,8 @@ struct InputData{
Points points;

std::tuple<std::vector<Camera>, Camera *> getCameras(bool validate, const std::string &valImage = "random");

void saveCameras(const std::string &filename, bool keepCrs);
};
InputData inputDataFromX(const std::string &projectRoot);

Expand Down
1 change: 0 additions & 1 deletion model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ torch::Tensor Model::forward(Camera& cam, int step){
const int height = static_cast<int>(static_cast<float>(cam.height) / scaleFactor);
const int width = static_cast<int>(static_cast<float>(cam.width) / scaleFactor);

// TODO: these can be moved to Camera and computed only once?
torch::Tensor R = cam.camToWorld.index({Slice(None, 3), Slice(None, 3)});
torch::Tensor T = cam.camToWorld.index({Slice(None, 3), Slice(3,4)});

Expand Down
11 changes: 10 additions & 1 deletion opensplat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
#include "input_data.hpp"
#include "utils.hpp"
#include "cv_utils.hpp"
#include "constants.hpp"
#include <cxxopts.hpp>

namespace fs = std::filesystem;
using namespace torch::indexing;

int main(int argc, char *argv[]){
cxxopts::Options options("opensplat", "Open Source 3D Gaussian Splats generator");
cxxopts::Options options("opensplat", "Open Source 3D Gaussian Splats generator - " APP_VERSION);
options.add_options()
("i,input", "Path to nerfstudio project", cxxopts::value<std::string>())
("o,output", "Path where to save output scene", cxxopts::value<std::string>()->default_value("splat.ply"))
Expand All @@ -37,6 +38,7 @@ int main(int argc, char *argv[]){
("split-screen-size", "Split gaussians that are larger than this percentage of screen space", cxxopts::value<float>()->default_value("0.05"))

("h,help", "Print usage")
("version", "Print version")
;
options.parse_positional({ "input" });
options.positional_help("[colmap/nerfstudio/opensfm/odm project path]");
Expand All @@ -50,11 +52,16 @@ int main(int argc, char *argv[]){
return EXIT_FAILURE;
}

if (result.count("version")){
std::cout << APP_VERSION << std::endl;
return EXIT_SUCCESS;
}
if (result.count("help") || !result.count("input")) {
std::cout << options.help() << std::endl;
return EXIT_SUCCESS;
}


const std::string projectRoot = result["input"].as<std::string>();
const std::string outputScene = result["output"].as<std::string>();
const int saveEvery = result["save-every"].as<int>();
Expand Down Expand Up @@ -94,6 +101,7 @@ int main(int argc, char *argv[]){

try{
InputData inputData = inputDataFromX(projectRoot);

parallel_for(inputData.cameras.begin(), inputData.cameras.end(), [&downScaleFactor](Camera &cam){
cam.loadImage(downScaleFactor);
});
Expand Down Expand Up @@ -146,6 +154,7 @@ int main(int argc, char *argv[]){
}
}

inputData.saveCameras((fs::path(outputScene).parent_path() / "cameras.json").string(), keepCrs);
model.save(outputScene);
// model.saveDebugPly("debug.ply");

Expand Down
8 changes: 7 additions & 1 deletion simple_trainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ using namespace torch::indexing;
namespace fs = std::filesystem;

int main(int argc, char **argv){
cxxopts::Options options("simple_trainer", "Test program for gsplat execution");
cxxopts::Options options("simple_trainer", "Test program for gsplat execution - " APP_VERSION);
options.add_options()
("cpu", "Force CPU execution")
("width", "Test image width", cxxopts::value<int>()->default_value("256"))
Expand All @@ -32,6 +32,7 @@ int main(int argc, char **argv){
("lr", "Learning rate", cxxopts::value<float>()->default_value("0.01"))
("render", "Save rendered images to folder", cxxopts::value<std::string>()->default_value(""))
("h,help", "Print usage")
("version", "Print version")
;
cxxopts::ParseResult result;
try {
Expand All @@ -48,6 +49,11 @@ int main(int argc, char **argv){
return EXIT_SUCCESS;
}

if (result.count("version")) {
std::cout << APP_VERSION << std::endl;
return EXIT_SUCCESS;
}

int width = result["width"].as<int>(),
height = result["height"].as<int>();
int numPoints = result["points"].as<int>();
Expand Down

0 comments on commit 4d70016

Please sign in to comment.