8000 Add frame impl for future rig support by B1ueber2y · Pull Request #2698 · colmap/colmap · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add frame impl for future rig support #2698

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

Merged
merged 46 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
2d8cb75
frame impl.
B1ueber2y Aug 9, 2024
350eb86
update.
B1ueber2y Aug 10, 2024
a370d99
formatting.
B1ueber2y Aug 10, 2024
bc2414c
update.
B1ueber2y Aug 10, 2024
2f79de6
update.
B1ueber2y Aug 10, 2024
6058852
formatting.
B1ueber2y Aug 10, 2024
873f627
update.
B1ueber2y Aug 10, 2024
b679281
Merge branch 'main' into features/frame
B1ueber2y Aug 10, 2024
bff7097
formatting.
B1ueber2y Aug 10, 2024
213715d
minor.
B1ueber2y Aug 10, 2024
ca7a58c
Merge branch 'main' into features/frame
B1ueber2y Aug 10, 2024
ab69299
Merge branch 'main' into features/frame
ahojnnes Aug 26, 2024
374bd9e
Merge branch 'main' into features/frame
B1ueber2y Aug 27, 2024
ba36423
Merge branch 'features/frame' of github.com:B1ueber2y/colmap into fea…
B1ueber2y Aug 27, 2024
8000
da433a1
update.
B1ueber2y Aug 27, 2024
fe58bc1
Merge branch 'main' into features/frame
B1ueber2y Sep 9, 2024
3beb4e2
Merge branch 'main' into features/frame
B1ueber2y Sep 10, 2024
3229804
cr
B1ueber2y Feb 3, 2025
c65d577
cr
B1ueber2y Feb 3, 2025
d6569a3
merge with main and add some TODOs
B1ueber2y Feb 3, 2025
24f1ce4
cr
B1ueber2y Feb 3, 2025
05d2ade
cr
B1ueber2y Feb 3, 2025
b2e5429
cr
B1ueber2y Feb 3, 2025
885593b
fix todos. make frame_from_world optional
B1ueber2y Feb 3, 2025
07cc0ef
include <optional>
B1ueber2y Feb 3, 2025
b68160d
cam_from_world_value in pycolmap
B1ueber2y Feb 3, 2025
63055e9
custom structures for sensor_t and data_t
B1ueber2y Feb 3, 2025
7c2959a
Merge branch 'main' into features/frame
B1ueber2y Feb 3, 2025
f94cced
cr.
B1ueber2y Feb 4, 2025
4e2f06c
remove the need of sensor_ids
B1ueber2y Feb 4, 2025
068ce06
improve comments
B1ueber2y Feb 4, 2025
0a65a4e
move add sensor to cc
B1ueber2y Feb 4, 2025
4b05f56
minor
B1ueber2y Feb 4, 2025
2be8a14
change the id in data_t from uint64_t to uint32_t
B1ueber2y Feb 4, 2025
355c0a2
fix
B1ueber2y Feb 4, 2025
05f7397
deprecate cam_from_world and always use frame pointer
B1ueber2y Feb 4, 2025
1e72385
minor
B1ueber2y Feb 4, 2025
e22e2cd
fix copy construction and assignment for Image class
B1ueber2y Feb 4, 2025
ed5aa77
minor fix
B1ueber2y Feb 4, 2025
2519bfa
make clang-tidy happy
B1ueber2y Feb 4, 2025
c14fdf6
improve code + add tests for frame.h
B1ueber2y Feb 4, 2025
83fabbd
format
B1ueber2y Feb 4, 2025
9ae245c
update
B1ueber2y Feb 5, 2025
1def428
Merge branch 'main' into features/frame
B1ueber2y Feb 5, 2025
37ce8e6
rename CamFromWorldValue to ComposeCamFromWorld
B1ueber2y Feb 5, 2025
2fa5baf
move RigCalibration to separate file at sensor/rig_calib.h
B1ueber2y Feb 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/colmap/scene/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ COLMAP_ADD_LIBRARY(
correspondence_graph.h correspondence_graph.cc
database.h database.cc
database_cache.h database_cache.cc
frame.h
image.h image.cc
point2d.h point2d.cc
point3d.h point3d.cc
Expand Down Expand Up @@ -84,6 +85,11 @@ COLMAP_ADD_TEST(
SRCS database_test.cc
LINK_LIBS colmap_scene
)
COLMAP_ADD_TEST(
NAME frame_test
SRCS frame_test.cc
LINK_LIBS colmap_scene
)
COLMAP_ADD_TEST(
NAME image_test
SRCS image_test.cc
Expand Down
206 changes: 206 additions & 0 deletions src/colmap/scene/frame.h
< 8000 td class="blob-num blob-num-addition empty-cell">
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// Copyright (c), ETH Zurich and UNC Chapel Hill.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#pragma once

#include "colmap/geometry/rigid3.h"
#include "colmap/sensor/rig_calib.h"
#include "colmap/util/types.h"

#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <tuple>
#include <vector>

namespace colmap {

struct data_t {
// Unique identifer of the sensor
sensor_t sensor_id;
// Unique identifier of the data (measurement)
// This can be image_t / imu_measurement_t (not supported yet)
uint32_t id;
constexpr data_t(const sensor_t& sensor_id, uint32_t id)
: sensor_id(sensor_id), id(id) {}

inline bool operator<(const data_t& other) const {
return std::tie(sensor_id, id) < std::tie(other.sensor_id, other.id);
}
inline bool operator==(const data_t& other) const {
return sensor_id == other.sensor_id && id == other.id;
}
inline bool operator!=(const data_t& other) const {
return !(*this == other);
}
};
constexpr data_t kInvalidDataId =
data_t(kInvalidSensorId, std::numeric_limits<uint32_t>::max());

class Frame {
public:
Frame() = default;

// Access the unique identifier of the frame
inline frame_t FrameId() const;
inline void SetFrameId(frame_t frame_id);

// Access data ids
inline std::set<data_t>& DataIds();
inline const std::set<data_t>& DataIds() const;
inline void AddData(data_t data_id);

// Check whether the data id is existent in the frame
inline bool HasData(data_t data_id) const;

// Access the rig calibration
inline const std::shared_ptr<class RigCalibration>& RigCalibration() const;
inline void SetRigCalibration(
std::shared_ptr<class RigCalibration> rig_calibration);
// Check if the frame has a non-trivial rig calibration
inline bool HasRigCalibration() const;

// Access the frame from world transformation
inline const Rigid3d& FrameFromWorld() const;
inline Rigid3d& FrameFromWorld();
inline const std::optional<Rigid3d>& MaybeFrameFromWorld() const;
inline std::optional<Rigid3d>& MaybeFrameFromWorld();
inline void SetFrameFromWorld(const Rigid3d& frame_from_world);
inline void SetFrameFromWorld(const std::optional<Rigid3d>& frame_from_world);
inline bool HasPose() const;
inline void ResetPose();

// Get the sensor from world transformation
inline Rigid3d SensorFromWorld(sensor_t sensor_id) const;

private:
frame_t frame_id_ = kInvalidFrameId;
std::set<data_t> data_ids_;

// Store the frame_from_world transformation and an optional rig calibration.
// If the rig calibration is a nullptr, the frame becomes a single sensor
// case, where rig modeling is no longer needed.
std::optional<Rigid3d> frame_from_world_;

// [Optional] Rig calibration
std::shared_ptr<class RigCalibration> rig_calibration_ = nullptr;
};

////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////

frame_t Frame::FrameId() const { return frame_id_; }

void Frame::SetFrameId(frame_t frame_id) { frame_id_ = frame_id; }

std::set<data_t>& Frame::DataIds() { return data_ids_; }

const std::set<data_t>& Frame::DataIds() const { return data_ids_; }

void Frame::AddData(data_t data_id) { data_ids_.insert(data_id); }

bool Frame::HasData(data_t data_id) const {
return data_ids_.find(data_id) != data_ids_.end();
}

const std::shared_ptr<class RigCalibration>& Frame::RigCalibration() const {
return rig_calibration_;
}

void Frame::SetRigCalibration(
std::shared_ptr<class RigCalibration> rig_calibration) {
rig_calibration_ = std::move(rig_calibration);
}

bool Frame::HasRigCalibration() const {
if (!rig_calibration_)
return false;
else
return rig_calibration_->NumSensors() > 1;
}

const Rigid3d& Frame::FrameFromWorld() const {
THROW_CHECK(frame_from_world_) << "Frame does not have a valid pose.";
return *frame_from_world_;
}

Rigid3d& Frame::FrameFromWorld() {
THROW_CHECK(frame_from_world_) << "Frame does not have a valid pose.";
return *frame_from_world_;
}

const std::optional<Rigid3d>& Frame::MaybeFrameFromWorld() const {
return frame_from_world_;
}

std::optional<Rigid3d>& Frame::MaybeFrameFromWorld() {
return frame_from_world_;
}

void Frame::SetFrameFromWorld(const Rigid3d& frame_from_world) {
frame_from_world_ = frame_from_world;
}

void Frame::SetFrameFromWorld(const std::optional<Rigid3d>& frame_from_world) {
frame_from_world_ = frame_from_world;
}

bool Frame::HasPose() const { return frame_from_world_.has_value(); }

void Frame::ResetPose() { frame_from_world_.reset(); }

Rigid3d Frame::SensorFromWorld(sensor_t sensor_id) const {
if (!HasRigCalibration() || rig_calibration_->IsRefSensor(sensor_id)) {
return FrameFromWorld();
}
THROW_CHECK(rig_calibration_->HasSensor(sensor_id));
return rig_calibration_->SensorFromRig(sensor_id) * FrameFromWorld();
}

} // namespace colmap

namespace std {

// [Reference]
// https://stackoverflow.com/questions/26705751/why-is-the-magic-number-in-boosthash-combine-specified-in-hex
template <>
struct hash<colmap::data_t> {
std::size_t operator()(const colmap::data_t& d) const noexcept {
size_t h1 =
std::hash<uint64_t>{}(std::hash<colmap::sensor_t>{}(d.sensor_id));
size_t h2 = std::hash<uint64_t>{}(d.id);
return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
}
};

} // namespace std
78 changes: 78 additions & 0 deletions src/colmap/scene/frame_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c), ETH Zurich and UNC Chapel Hill.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include "colmap/scene/frame.h"

#include <gtest/gtest.h>

namespace colmap {
namespace {

Rigid3d TestRigid3d() {
return Rigid3d(Eigen::Quaterniond::UnitRandom(), Eigen::Vector3d::Random());
}

TEST(Frame, Default) {
Frame frame;
EXPECT_EQ(frame.FrameId(), kInvalidFrameId);
EXPECT_FALSE(frame.HasPose());
EXPECT_FALSE(frame.HasRigCalibration());
}

TEST(Frame, SetUp) {
sensor_t s1(SensorType::IMU, 0);
sensor_t s2(SensorType::CAMERA, 0);
std::shared_ptr<RigCalibration> calib = std::make_shared<RigCalibration>();
calib->AddRefSensor(s1);
calib->AddSensor(s2, TestRigid3d());

Frame frame;
frame.AddData(data_t(s1, 2));
frame.AddData(data_t(s2, 5));
frame.SetRigCalibration(calib);
EXPECT_TRUE(frame.HasRigCalibration());
EXPECT_FALSE(frame.HasPose());
}

TEST(Frame, SetResetPose) {
Frame frame;
EXPECT_FALSE(frame.HasPose());
EXPECT_ANY_THROW(frame.FrameFromWorld());
frame.SetFrameFromWorld(Rigid3d());
EXPECT_TRUE(frame.HasPose());
EXPECT_EQ(frame.FrameFromWorld().rotation.coeffs(),
Eigen::Quaterniond::Identity().coeffs());
EXPECT_EQ(frame.FrameFromWorld().translation, Eigen::Vector3d::Zero());
frame.ResetPose();
EXPECT_FALSE(frame.HasPose());
EXPECT_ANY_THROW(frame.FrameFromWorld());
}

} // namespace
} // namespace colmap
42 changes: 41 additions & 1 deletion src/colmap/scene/image.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,47 @@ Image::Image()
name_(""),
camera_id_(kInvalidCameraId),
camera_ptr_(nullptr),
num_points3D_(0) {}
num_points3D_(0),
frame_(std::make_shared<class Frame>()) {}

Image::Image(const Image& other)
: image_id_(other.ImageId()),
name_(other.Name()),
camera_id_(other.CameraId()),
camera_ptr_(nullptr),
num_points3D_(other.NumPoints3D()),
points2D_(other.Points2D()) {
if (other.HasCameraPtr()) {
camera_ptr_ = other.CameraPtr();
}
if (other.HasNonTrivialFrame()) {
frame_ = other.Frame();
} else {
frame_ = std::make_shared<class Frame>();
frame_->SetFrameFromWorld(other.MaybeCamFromWorld());
}
}

Image& Image::operator=(const Image& other) {
if (this != &other) {
image_id_ = other.ImageId();
name_ = other.Name();
camera_id_ = other.CameraId();
camera_ptr_ = nullptr;
if (other.HasCameraPtr()) {
camera_ptr_ = other.CameraPtr();
}
num_points3D_ = other.NumPoints3D();
points2D_ = other.Points2D();
if (other.HasNonTrivialFrame()) {
frame_ = other.Frame();
} else {
frame_ = std::make_shared<class Frame>();
frame_->SetFrameFromWorld(other.MaybeCamFromWorld());
}
}
return *this;
}

void Image::SetPoints2D(const std::vector<Eigen::Vector2d>& points) {
THROW_CHECK(points2D_.empty());
Expand Down
Loading
Loading
0