python版本:
python
import threading
import queue
import time
import abc
import cv2
import numpy as np
from typing import Dict, List, Optional, Any
# 全局常量配置
MAX_QUEUE_SIZE = 30 # 图像缓存队列最大长度(避免内存溢出)
DEFAULT_TIMEOUT = 0.1 # 队列操作超时时间(秒)
class BaseCamera(metaclass=abc.ABCMeta):
"""相机抽象基类:定义通用接口,所有具体相机需继承并实现抽象方法"""
def __init__(self, camera_id: str or int, **kwargs):
"""
初始化相机基类
:param camera_id: 相机唯一标识(如USB相机的0/1,工业相机的序列号)
:param kwargs: 相机额外参数(如分辨率、曝光时间、帧率等)
"""
self.camera_id = camera_id
self.kwargs = kwargs
# 线程安全状态控制
self._lock = threading.Lock()
self._initialized = False # 相机是否初始化完成
self._capturing = False # 相机是否正在采集
# 图像缓存队列(线程安全)
self._frame_queue = queue.Queue(maxsize=MAX_QUEUE_SIZE)
# 采集线程
self._capture_thread: Optional[threading.Thread] = None
@abc.abstractmethod
def init_camera(self) -> bool:
"""
初始化相机硬件(具体实现由子类完成)
:return: 初始化成功返回True,失败返回False
"""
pass
@abc.abstractmethod
def _capture_single_frame(self) -> Optional[np.ndarray]:
"""
采集单帧图像(具体实现由子类完成,内部调用)
:return: 图像数组(HWC格式),采集失败返回None
"""
pass
@abc.abstractmethod
def close_camera(self) -> None:
"""关闭相机,释放硬件资源(具体实现由子类完成)"""
pass
def start_capture(self) -> bool:
"""
启动相机采集线程
:return: 启动成功返回True,失败返回False
"""
with self._lock:
if not self._initialized:
print(f"[ERROR] 相机{self.camera_id}未初始化,无法启动采集")
return False
if self._capturing:
print(f"[WARNING] 相机{self.camera_id}已在采集状态")
return True
self._capturing = True
# 创建并启动采集线程
self._capture_thread = threading.Thread(
target=self._capture_loop,
name=f"Camera-{self.camera_id}-Capture",
daemon=True # 守护线程:主程序退出时自动终止
)
self._capture_thread.start()
print(f"[INFO] 相机{self.camera_id}采集线程已启动")
return True
def stop_capture(self) -> None:
"""停止相机采集线程(优雅停止,避免强制终止)"""
with self._lock:
if not self._capturing:
return
self._capturing = False
# 等待线程结束
if self._capture_thread and self._capture_thread.is_alive():
self._capture_thread.join(timeout=1.0)
print(f"[INFO] 相机{self.camera_id}采集线程已停止")
def _capture_loop(self) -> None:
"""采集循环(线程执行函数)"""
while True:
# 检查是否需要停止采集
with self._lock:
if not self._capturing:
break
try:
# 采集单帧图像
frame = self._capture_single_frame()
if frame is None:
time.sleep(0.001)
continue
# 将图像放入队列(包含时间戳和相机ID,方便上层处理)
frame_data = {
"camera_id": self.camera_id,
"timestamp": time.time(),
"frame": frame
}
# 队列满时丢弃最旧帧(也可选择阻塞或丢弃新帧)
if self._frame_queue.full():
try:
self._frame_queue.get_nowait()
except queue.Empty:
pass
self._frame_queue.put(frame_data, timeout=DEFAULT_TIMEOUT)
except Exception as e:
print(f"[ERROR] 相机{self.camera_id}采集异常: {str(e)}")
time.sleep(0.01)
def get_frame(self, timeout: float = DEFAULT_TIMEOUT) -> Optional[Dict[str, Any]]:
"""
获取最新帧(从队列中取出)
:param timeout: 队列等待超时时间
:return: 帧数据字典(camera_id/timestamp/frame),无数据返回None
"""
try:
return self._frame_queue.get(timeout=timeout)
except queue.Empty:
return None
def clear_queue(self) -> None:
"""清空图像队列"""
while not self._frame_queue.empty():
try:
self._frame_queue.get_nowait()
except queue.Empty:
break
def __del__(self):
"""析构函数:确保资源释放"""
self.stop_capture()
self.close_camera()
class USBCamera(BaseCamera):
"""USB相机实现类(基于OpenCV)"""
def __init__(self, camera_id: int, resolution: tuple = (640, 480), fps: int = 30, **kwargs):
"""
初始化USB相机
:param camera_id: USB相机索引(0/1/2...)
:param resolution: 分辨率 (width, height)
:param fps: 帧率
:param kwargs: 其他参数(如曝光时间:exposure=-1(自动))
"""
super().__init__(camera_id, resolution=resolution, fps=fps, **kwargs)
self._cap: Optional[cv2.VideoCapture] = None
def init_camera(self) -> bool:
"""初始化USB相机硬件"""
with self._lock:
if self._initialized:
return True
# 打开相机
self._cap = cv2.VideoCapture(self.camera_id)
if not self._cap.isOpened():
print(f"[ERROR] 无法打开USB相机{self.camera_id}")
return False
# 设置分辨率
width, height = self.kwargs["resolution"]
self._cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
self._cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
# 设置帧率
self._cap.set(cv2.CAP_PROP_FPS, self.kwargs["fps"])
# 设置曝光时间(可选)
if "exposure" in self.kwargs:
self._cap.set(cv2.CAP_PROP_EXPOSURE, self.kwargs["exposure"])
self._initialized = True
print(f"[INFO] USB相机{self.camera_id}初始化成功")
return True
def _capture_single_frame(self) -> Optional[np.ndarray]:
"""采集单帧图像"""
if not self._cap or not self._cap.isOpened():
return None
ret, frame = self._cap.read()
return frame if ret else None
def close_camera(self) -> None:
"""关闭USB相机"""
with self._lock:
if not self._initialized:
return
if self._cap:
self._cap.release()
self._cap = None
self._initialized = False
print(f"[INFO] USB相机{self.camera_id}已关闭")
class MockCamera(BaseCamera):
"""模拟相机实现类(生成随机图像,用于测试)"""
def __init__(self, camera_id: str, resolution: tuple = (640, 480), **kwargs):
super().__init__(camera_id, resolution=resolution, **kwargs)
self._width, self._height = resolution
def init_camera(self) -> bool:
"""模拟初始化(无硬件操作)"""
with self._lock:
if self._initialized:
return True
self._initialized = True
print(f"[INFO] 模拟相机{self.camera_id}初始化成功")
return True
def _capture_single_frame(self) -> Optional[np.ndarray]:
"""生成随机图像"""
frame = np.random.randint(0, 255, (self._height, self._width, 3), dtype=np.uint8)
# 绘制相机ID标识(方便测试区分)
cv2.putText(
frame, f"Camera: {self.camera_id}",
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2
)
return frame
def close_camera(self) -> None:
"""模拟关闭(无硬件操作)"""
with self._lock:
if not self._initialized:
return
self._initialized = False
print(f"[INFO] 模拟相机{self.camera_id}已关闭")
class CameraManager:
"""相机管理器:统一管理多个相机的生命周期"""
def __init__(self):
self._cameras: Dict[str or int, BaseCamera] = {} # 相机实例字典
self._lock = threading.Lock()
def add_camera(self, camera: BaseCamera) -> bool:
"""
添加相机到管理器
:param camera: 相机实例
:return: 添加成功返回True,重复ID返回False
"""
with self._lock:
if camera.camera_id in self._cameras:
print(f"[WARNING] 相机ID {camera.camera_id} 已存在,添加失败")
return False
self._cameras[camera.camera_id] = camera
print(f"[INFO] 相机{camera.camera_id}已添加到管理器")
return True
def init_all_cameras(self) -> bool:
"""初始化所有相机"""
with self._lock:
success_count = 0
for cam_id, camera in self._cameras.items():
if camera.init_camera():
success_count += 1
all_success = success_count == len(self._cameras)
print(f"[INFO] 相机初始化完成:成功{success_count}/{len(self._cameras)}")
return all_success
def start_all_capture(self) -> bool:
"""启动所有相机的采集线程"""
with self._lock:
success_count = 0
for cam_id, camera in self._cameras.items():
if camera.start_capture():
success_count += 1
all_success = success_count == len(self._cameras)
print(f"[INFO] 相机采集启动完成:成功{success_count}/{len(self._cameras)}")
return all_success
def stop_all_capture(self) -> None:
"""停止所有相机的采集线程"""
with self._lock:
for cam_id, camera in self._cameras.items():
camera.stop_capture()
print(f"[INFO] 所有相机采集已停止")
def close_all_cameras(self) -> None:
"""关闭所有相机,释放资源"""
with self._lock:
for cam_id, camera in self._cameras.items():
camera.close_camera()
self._cameras.clear()
print(f"[INFO] 所有相机已关闭并释放资源")
def get_camera(self, camera_id: str or int) -> Optional[BaseCamera]:
"""获取指定ID的相机实例"""
with self._lock:
return self._cameras.get(camera_id, None)
def get_all_frames(self, timeout: float = DEFAULT_TIMEOUT) -> Dict[str or int, Optional[Dict[str, Any]]]:
"""
获取所有相机的最新帧
:param timeout: 队列等待超时时间
:return: 键为相机ID,值为帧数据(无数据则为None)
"""
frames = {}
with self._lock:
for cam_id, camera in self._cameras.items():
frames[cam_id] = camera.get_frame(timeout=timeout)
return frames
def clear_all_queues(self) -> None:
"""清空所有相机的图像队列"""
with self._lock:
for cam_id, camera in self._cameras.items():
camera.clear_queue()
# -------------------------- 测试示例 --------------------------
def test_multi_camera_capture():
"""测试多相机采集"""
# 1. 创建相机管理器
manager = CameraManager()
# 2. 添加相机(可混合添加不同类型相机)
# 添加2个USB相机(若没有硬件,可替换为MockCamera)
# manager.add_camera(USBCamera(camera_id=0, resolution=(640, 480), fps=30))
# manager.add_camera(USBCamera(camera_id=1, resolution=(640, 480), fps=30))
# 添加2个模拟相机(用于测试)
manager.add_camera(MockCamera(camera_id="mock_0", resolution=(640, 480)))
manager.add_camera(MockCamera(camera_id="mock_1", resolution=(640, 480)))
try:
# 3. 初始化所有相机
if not manager.init_all_cameras():
print("[ERROR] 相机初始化失败,退出测试")
return
# 4. 启动所有相机采集
if not manager.start_all_capture():
print("[ERROR] 相机采集启动失败,退出测试")
return
# 5. 循环获取并显示图像
print("[INFO] 开始采集图像,按'q'退出...")
while True:
# 获取所有相机的最新帧
all_frames = manager.get_all_frames()
# 显示每个相机的图像
for cam_id, frame_data in all_frames.items():
if frame_data is None:
continue
frame = frame_data["frame"]
# 绘制时间戳(可选)
timestamp = time.strftime("%H:%M:%S", time.localtime(frame_data["timestamp"]))
cv2.putText(
frame, f"Time: {timestamp}",
(10, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2
)
cv2.imshow(f"Camera {cam_id}", frame)
# 按q退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
except KeyboardInterrupt:
print("[INFO] 接收到中断信号,停止采集")
except Exception as e:
print(f"[ERROR] 测试过程异常: {str(e)}")
finally:
# 6. 停止采集并释放资源
manager.stop_all_capture()
manager.close_all_cameras()
cv2.destroyAllWindows()
print("[INFO] 测试结束,资源已释放")
if __name__ == "__main__":
test_multi_camera_capture()
c++版本:
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <atomic>
#include <queue>
#include <map>
#include <vector>
#include <chrono>
#include <memory>
#include <stdexcept>
#include <ctime>
#include <opencv2/opencv.hpp>
// 全局常量配置
constexpr size_t MAX_QUEUE_SIZE = 30; // 队列最大长度
constexpr int QUEUE_TIMEOUT_MS = 100; // 队列操作超时(毫秒)
constexpr int CAPTURE_ERROR_DELAY_MS = 10; // 采集异常后延迟(毫秒)
// 线程安全队列模板类
template <typename T>
class ThreadSafeQueue {
public:
ThreadSafeQueue() = default;
~ThreadSafeQueue() = default;
// 禁止拷贝和移动(简化设计,也可按需实现)
ThreadSafeQueue(const ThreadSafeQueue&) = delete;
ThreadSafeQueue& operator=(const ThreadSafeQueue&) = delete;
ThreadSafeQueue(ThreadSafeQueue&&) = delete;
ThreadSafeQueue& operator=(ThreadSafeQueue&&) = delete;
// 入队(超时返回false,队列满时丢弃最旧元素)
bool push(const T& data, int timeout_ms = QUEUE_TIMEOUT_MS) {
std::unique_lock<std::mutex> lock(mtx_);
// 队列满时丢弃最旧元素
if (queue_.size() >= MAX_QUEUE_SIZE) {
if (!queue_.empty()) {
queue_.pop();
}
}
// 等待队列有空间(带超时)
if (cv_.wait_for(lock, std::chrono::milliseconds(timeout_ms),
[this]() { return queue_.size() < MAX_QUEUE_SIZE; })) {
queue_.push(data);
cv_.notify_one();
return true;
}
return false;
}
// 出队(超时返回false)
bool pop(T& data, int timeout_ms = QUEUE_TIMEOUT_MS) {
std::unique_lock<std::mutex> lock(mtx_);
if (cv_.wait_for(lock, std::chrono::milliseconds(timeout_ms),
[this]() { return !queue_.empty(); })) {
data = queue_.front();
queue_.pop();
return true;
}
return false;
}
// 清空队列
void clear() {
std::lock_guard<std::mutex> lock(mtx_);
while (!queue_.empty()) {
queue_.pop();
}
}
// 获取队列大小
size_t size() const {
std::lock_guard<std::mutex> lock(mtx_);
return queue_.size();
}
// 判断队列是否为空
bool empty() const {
std::lock_guard<std::mutex> lock(mtx_);
return queue_.empty();
}
private:
std::queue<T> queue_;
mutable std::mutex mtx_;
std::condition_variable cv_;
};
// 帧数据结构体(包含相机ID、时间戳、图像)
struct FrameData {
std::string camera_id; // 相机唯一标识
double timestamp; // 采集时间戳(秒)
cv::Mat frame; // 图像数据(深拷贝避免悬空引用)
// 构造函数(深拷贝Mat)
FrameData() {};
FrameData(std::string id, double ts, const cv::Mat& img)
: camera_id(std::move(id)), timestamp(ts), frame(img.clone()) {}
};
// 相机抽象基类
class BaseCamera {
public:
explicit BaseCamera(std::string camera_id)
: camera_id_(std::move(camera_id)),
initialized_(false),
capturing_(false) {}
virtual ~BaseCamera() {
stopCapture();
closeCamera(); // 调用虚函数,基类有默认实现
}
// 禁止拷贝,允许移动
BaseCamera(const BaseCamera&) = delete;
BaseCamera& operator=(const BaseCamera&) = delete;
BaseCamera(BaseCamera&&) = default;
BaseCamera& operator=(BaseCamera&&) = default;
// 纯虚函数:相机初始化
virtual bool initCamera() = 0;
// 纯虚函数:采集单帧图像
virtual cv::Mat captureSingleFrame() = 0;
// 虚函数:关闭相机(提供默认实现,子类可重写)
virtual void closeCamera() {
// 基类默认空实现,子类根据实际相机类型重写
std::cout << "[INFO] BaseCamera " << camera_id_ << " closed (default impl)!" << std::endl;
}
// 启动采集线程
bool startCapture() {
if (!initialized_) {
std::cerr << "[ERROR] Camera " << camera_id_ << " not initialized!" << std::endl;
return false;
}
if (capturing_) {
std::cerr << "[WARNING] Camera " << camera_id_ << " is already capturing!" << std::endl;
return true;
}
capturing_ = true;
// 创建采集线程(detach避免主线程join阻塞,通过capturing_控制退出)
capture_thread_ = std::thread(&BaseCamera::captureLoop, this);
capture_thread_.detach();
std::cout << "[INFO] Camera " << camera_id_ << " capture thread started!" << std::endl;
return true;
}
// 停止采集
void stopCapture() {
if (!capturing_) {
return;
}
capturing_ = false;
// 等待线程退出(给1秒时间)
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "[INFO] Camera " << camera_id_ << " capture thread stopped!" << std::endl;
}
// 获取最新帧(超时返回空Mat)
FrameData getFrame(int timeout_ms = QUEUE_TIMEOUT_MS) {
FrameData empty_frame("", 0.0, cv::Mat());
FrameData frame_data("", 0.0, cv::Mat());
if (frame_queue_.pop(frame_data, timeout_ms)) {
return frame_data;
}
return empty_frame;
}
// 清空帧队列
void clearQueue() {
frame_queue_.clear();
}
// 获取相机ID
std::string getCameraId() const { return camera_id_; }
// 判断是否初始化完成
bool isInitialized() const { return initialized_; }
// 判断是否正在采集
bool isCapturing() const { return capturing_; }
protected:
std::string camera_id_; // 相机ID
std::atomic<bool> initialized_; // 初始化状态(原子变量)
std::atomic<bool> capturing_; // 采集状态(原子变量)
ThreadSafeQueue<FrameData> frame_queue_; // 帧队列
std::thread capture_thread_; // 采集线程
// 采集循环(线程执行函数)
void captureLoop() {
while (capturing_) {
try {
// 采集单帧
cv::Mat frame = captureSingleFrame();
if (frame.empty()) {
std::this_thread::sleep_for(std::chrono::microseconds(1000));
continue;
}
// 构造帧数据(带时间戳)
double timestamp = std::chrono::duration_cast<std::chrono::duration<double>>(
std::chrono::system_clock::now().time_since_epoch()
).count();
FrameData frame_data(camera_id_, timestamp, frame);
// 入队
if (!frame_queue_.push(frame_data)) {
std::cerr << "[WARNING] Camera " << camera_id_ << " queue push timeout!" << std::endl;
}
}
catch (const std::exception & e) {
std::cerr << "[ERROR] Camera " << camera_id_ << " capture error: " << e.what() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(CAPTURE_ERROR_DELAY_MS));
}
catch (...) {
std::cerr << "[ERROR] Camera " << camera_id_ << " unknown capture error!" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(CAPTURE_ERROR_DELAY_MS));
}
}
}
// 设置初始化状态(子类调用)
void setInitialized(bool status) {
initialized_ = status;
}
};
// USB相机实现类(基于OpenCV)
class USBCamera : public BaseCamera {
public:
USBCamera(int camera_index, const cv::Size& resolution = cv::Size(640, 480), int fps = 30)
: BaseCamera(std::to_string(camera_index)),
camera_index_(camera_index),
resolution_(resolution),
fps_(fps),
cap_(nullptr) {}
~USBCamera() override {
// 析构函数无需重复调用closeCamera,基类析构会自动调用
}
// 初始化USB相机
bool initCamera() override {
if (initialized_) {
return true;
}
// 打开相机
cap_ = std::make_unique<cv::VideoCapture>(camera_index_);
if (!cap_->isOpened()) {
std::cerr << "[ERROR] Failed to open USB camera " << camera_id_ << std::endl;
cap_.reset();
return false;
}
// 设置参数
cap_->set(cv::CAP_PROP_FRAME_WIDTH, resolution_.width);
cap_->set(cv::CAP_PROP_FRAME_HEIGHT, resolution_.height);
cap_->set(cv::CAP_PROP_FPS, fps_);
// 可选:设置曝光(-1为自动)
if (exposure_ >= 0) {
cap_->set(cv::CAP_PROP_EXPOSURE, exposure_);
}
setInitialized(true);
std::cout << "[INFO] USB camera " << camera_id_ << " initialized!" << std::endl;
return true;
}
// 采集单帧
cv::Mat captureSingleFrame() override {
if (!cap_ || !cap_->isOpened() || !initialized_) {
return cv::Mat();
}
cv::Mat frame;
*cap_ >> frame;
return frame;
}
// 关闭相机(重写基类虚函数)
void closeCamera() override {
if (cap_) {
cap_->release();
cap_.reset();
}
setInitialized(false);
std::cout << "[INFO] USB camera " << camera_id_ << " closed!" << std::endl;
}
// 设置曝光时间(可选)
void setExposure(int exposure) {
exposure_ = exposure;
if (cap_ && initialized_) {
cap_->set(cv::CAP_PROP_EXPOSURE, exposure_);
}
}
private:
int camera_index_; // USB相机索引(0/1/2...)
cv::Size resolution_; // 分辨率
int fps_; // 帧率
int exposure_ = -1; // 曝光时间(-1自动)
std::unique_ptr<cv::VideoCapture> cap_; // OpenCV视频捕获对象
};
// 模拟相机实现类(生成随机图像,用于测试)
class MockCamera : public BaseCamera {
public:
MockCamera(const std::string& camera_id, const cv::Size& resolution = cv::Size(640, 480))
: BaseCamera(camera_id),
resolution_(resolution) {}
~MockCamera() override {
// 析构函数无需重复调用closeCamera,基类析构会自动调用
}
// 模拟初始化
bool initCamera() override {
if (initialized_) {
return true;
}
setInitialized(true);
std::cout << "[INFO] Mock camera " << camera_id_ << " initialized!" << std::endl;
return true;
}
// 生成随机图像
cv::Mat captureSingleFrame() override {
if (!initialized_) {
return cv::Mat();
}
// 生成随机图像
cv::Mat frame(resolution_, CV_8UC3);
cv::randu(frame, cv::Scalar(0, 0, 0), cv::Scalar(255, 255, 255));
// 绘制相机ID标识
cv::putText(frame, "Camera: " + camera_id_,
cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX,
1.0, cv::Scalar(0, 255, 0), 2);
return frame;
}
// 模拟关闭(重写基类虚函数)
void closeCamera() override {
setInitialized(false);
std::cout << "[INFO] Mock camera " << camera_id_ << " closed!" << std::endl;
}
private:
cv::Size resolution_; // 分辨率
};
// 相机管理器(统一管理多相机)
class CameraManager {
public:
CameraManager() = default;
~CameraManager() {
stopAllCapture();
closeAllCameras();
}
// 禁止拷贝和移动
CameraManager(const CameraManager&) = delete;
CameraManager& operator=(const CameraManager&) = delete;
CameraManager(CameraManager&&) = delete;
CameraManager& operator=(CameraManager&&) = delete;
// 添加相机(所有权转移)
bool addCamera(std::unique_ptr<BaseCamera> camera) {
if (!camera) {
std::cerr << "[ERROR] Null camera pointer!" << std::endl;
return false;
}
const std::string& cam_id = camera->getCameraId();
std::lock_guard<std::mutex> lock(mtx_);
if (cameras_.find(cam_id) != cameras_.end()) {
std::cerr << "[WARNING] Camera " << cam_id << " already exists!" << std::endl;
return false;
}
cameras_[cam_id] = std::move(camera);
std::cout << "[INFO] Camera " << cam_id << " added to manager!" << std::endl;
return true;
}
// 初始化所有相机
bool initAllCameras() {
std::lock_guard<std::mutex> lock(mtx_);
int success_count = 0;
for (auto& [cam_id, camera] : cameras_) {
if (camera->initCamera()) {
success_count++;
}
}
bool all_success = (success_count == cameras_.size());
std::cout << "[INFO] Camera init finished: " << success_count << "/" << cameras_.size() << " success!" << std::endl;
return all_success;
}
// 启动所有相机采集
bool startAllCapture() {
std::lock_guard<std::mutex> lock(mtx_);
int success_count = 0;
for (auto& [cam_id, camera] : cameras_) {
if (camera->startCapture()) {
success_count++;
}
}
bool all_success = (success_count == cameras_.size());
std::cout << "[INFO] Capture start finished: " << success_count << "/" << cameras_.size() << " success!" << std::endl;
return all_success;
}
// 停止所有相机采集
void stopAllCapture() {
std::lock_guard<std::mutex> lock(mtx_);
for (auto& [cam_id, camera] : cameras_) {
camera->stopCapture();
}
std::cout << "[INFO] All cameras capture stopped!" << std::endl;
}
// 关闭所有相机
void closeAllCameras() {
std::lock_guard<std::mutex> lock(mtx_);
for (auto& [cam_id, camera] : cameras_) {
camera->closeCamera();
}
cameras_.clear();
std::cout << "[INFO] All cameras closed and released!" << std::endl;
}
// 获取指定相机
BaseCamera* getCamera(const std::string & camera_id) {
std::lock_guard<std::mutex> lock(mtx_);
auto it = cameras_.find(camera_id);
return (it != cameras_.end()) ? it->second.get() : nullptr;
}
// 获取所有相机的最新帧
std::map<std::string, FrameData> getAllFrames(int timeout_ms = QUEUE_TIMEOUT_MS) {
std::map<std::string, FrameData> all_frames;
std::lock_guard<std::mutex> lock(mtx_);
for (auto& [cam_id, camera] : cameras_) {
FrameData frame = camera->getFrame(timeout_ms);
all_frames[cam_id] = frame;
}
return all_frames;
}
// 清空所有相机的队列
void clearAllQueues() {
std::lock_guard<std::mutex> lock(mtx_);
for (auto& [cam_id, camera] : cameras_) {
camera->clearQueue();
}
}
private:
std::map<std::string, std::unique_ptr<BaseCamera>> cameras_; // 相机集合
mutable std::mutex mtx_; // 管理器互斥锁
};
// 测试示例
int main() {
try {
// 1. 创建相机管理器
CameraManager manager;
// 2. 添加相机(模拟相机,替换为USBCamera(0)可测试真实USB相机)
manager.addCamera(std::make_unique<MockCamera>("mock_0", cv::Size(640, 480)));
manager.addCamera(std::make_unique<MockCamera>("mock_1", cv::Size(640, 480)));
// manager.addCamera(std::make_unique<USBCamera>(0, cv::Size(640, 480), 30)); // 真实USB相机
// 3. 初始化所有相机
if (!manager.initAllCameras()) {
std::cerr << "[ERROR] Camera init failed!" << std::endl;
return -1;
}
// 4. 启动所有相机采集
if (!manager.startAllCapture()) {
std::cerr << "[ERROR] Capture start failed!" << std::endl;
return -1;
}
// 5. 循环获取并显示图像
std::cout << "[INFO] Start capturing... Press 'q' to quit!" << std::endl;
while (true) {
// 获取所有相机的最新帧
auto all_frames = manager.getAllFrames();
// 显示每个相机的图像
for (auto& [cam_id, frame_data] : all_frames) {
if (frame_data.frame.empty()) {
continue;
}
// 绘制时间戳(格式化,避免换行)
std::time_t ts = static_cast<std::time_t>(frame_data.timestamp);
char time_buf[64];
std::strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", std::localtime(&ts));
std::string time_str(time_buf);
cv::putText(frame_data.frame, "Time: " + time_str,
cv::Point(10, 60), cv::FONT_HERSHEY_SIMPLEX,
1.0, cv::Scalar(0, 0, 255), 2);
// 显示窗口
cv::imshow("Camera " + cam_id, frame_data.frame);
}
// 按'q'退出(注意waitKey的延迟,避免CPU占用过高)
int key = cv::waitKey(1);
if (key == 'q' || key == 27) { // 27是ESC键
break;
}
}
// 6. 停止采集并释放资源
manager.stopAllCapture();
manager.closeAllCameras();
cv::destroyAllWindows();
std::cout << "[INFO] Test finished!" << std::endl;
}
catch (const std::exception & e) {
std::cerr << "[ERROR] Test exception: " << e.what() << std::endl;
return -1;
}
return 0;
}
运行结果:
