58 if (running_.exchange(
true))
64 std::cerr <<
"Invalid number of cameras: " << num_cams <<
" (max: " <<
MAX_CAMERA_COUNT <<
")" << std::endl;
65 running_.store(
false, std::memory_order_release);
71 expected_mask_ = (1u << num_cams_) -1;
73 fusion_thread_ = std::thread(&CameraQueueFusion::fusionLoop,
this);
74 fusion_thread_.detach();
98 std::cerr <<
"Camera ID out of range: " << cam_id
103 camera_ready_mask_.fetch_or(1u << cam_id);
128 std::lock_guard<std::mutex> lock(fusion_mutex_);
130 if (fused_frames_.empty())
136 auto it = std::find_if(fused_frames_.begin(), fused_frames_.end(),
137 [timestamp_cutoff](
const auto &frame)
139 return frame.timestamp > timestamp_cutoff;
143 if (it == fused_frames_.begin())
149 out.insert(out.end(),
150 std::make_move_iterator(fused_frames_.begin()),
151 std::make_move_iterator(it));
154 fused_frames_.erase(fused_frames_.begin(), it);
177void CameraQueueFusion::fusionLoop()
179 using namespace std::chrono;
180 const auto timeout = 1us;
181 const auto init_check_interval = 50us;
182 const auto kMinLoopPeriod = std::chrono::duration<double, std::milli>(
fusion_rate_dt_ms);
191 std::cerr <<
"Camera fusion waiting for CameraManager initialization..." << std::endl;
193 std::this_thread::sleep_for(init_check_interval);
204 std::unique_lock<std::mutex> lk(cv_mtx_);
205 bool all_cameras_ready = cv_.wait_for(lk, kMinLoopPeriod, [
this]
206 {
return ((camera_ready_mask_.load() & expected_mask_) == expected_mask_) || !
main_running; });
216 std::cerr <<
"Camera fusion timeout - processing available cameras (ready mask: 0x"
217 << std::hex << camera_ready_mask_.load()
218 <<
", expected: 0x" << expected_mask_ << std::dec <<
")" << std::endl;
222 std::vector<ov_core::CameraData> batch;
224 for (
const auto &cam :
voxl::CameraManager::
getInstance().getAllCameras())
226 ov_core::CameraData msg;
227 while (cam->popCameraData(msg))
229 batch.push_back(std::move(msg));
236 std::sort(batch.begin(), batch.end(),
237 [](
const auto &a,
const auto &b)
239 return a.timestamp < b.timestamp;
244 std::vector<ov_core::CameraData> merged;
245 merged.reserve(batch.size());
247 for (
auto &msg : batch)
249 if (!merged.empty() && msg.timestamp == merged.back().timestamp)
252 merged.back().sensor_ids.insert(merged.back().sensor_ids.end(),
253 msg.sensor_ids.begin(), msg.sensor_ids.end());
254 merged.back().images.insert(merged.back().images.end(),
255 msg.images.begin(), msg.images.end());
256 merged.back().masks.insert(merged.back().masks.end(),
257 msg.masks.begin(), msg.masks.end());
258 merged.back().img_frames.insert(merged.back().img_frames.end(),
259 msg.img_frames.begin(), msg.img_frames.end());
263 merged.push_back(std::move(msg));
267 std::lock_guard<std::mutex> lock(fusion_mutex_);
268 fused_frames_.insert(fused_frames_.end(),
269 std::make_move_iterator(merged.begin()),
270 std::make_move_iterator(merged.end()));
273 camera_ready_mask_.store(0, std::memory_order_release);
Camera management system for VOXL OpenVINS.
Camera queue fusion system for VOXL OpenVINS.
constexpr size_t MAX_CAMERA_COUNT
Maximum number of cameras supported.
float fusion_rate_dt_ms
Fusion rate in milliseconds.
volatile int main_running
Main process running flag.
int en_debug
Enable debug output.
Camera queue fusion system for multi-camera synchronization.
static CameraQueueFusion & getInstance()
Get singleton instance.
void start(size_t num_cams)
Start the fusion system.
void markCameraReady(size_t cam_id)
Mark a camera as ready with new data.
bool getSortedBatch(double timestamp_cutoff, std::vector< ov_core::CameraData > &out)
Get sorted batch of camera data.
static CameraManager & getInstance()
Get the singleton instance of the CameraManager.
Main namespace for VOXL OpenVINS server components.