C++安防监控系统中shared_ptr传参后图像栈无数据问题求助
问题分析与解决思路
核心问题定位
你的代码存在多个致命逻辑错误,导致Save函数无法正常读取vector内的帧数据:
1. 多线程资源竞争与未同步
- 全局
Cap_Foscam摄像头对象被Get_New_frame、Display_Images_Real_Time和主线程同时操作,grab()与retrieve()混用会导致帧数据错乱。 - 全局
Image变量被多线程读写,无任何同步机制,会引发内存访问错误,导致存入vector的帧数据损坏。
2. VideoWriter实例冲突
你同时定义了全局和main函数局部两个Output变量:
- 全局
Output初始化时用的是固定的300x300分辨率,和摄像头实际分辨率不匹配。 Save函数调用的是全局Output,写入时因尺寸不匹配失败,看起来像vector内无数据。
3. 循环边界逻辑错误
Save函数内的循环条件y <= (size-1)存在风险:当vector为空时,size-1会变成-1,直接跳过循环,无任何输出。
4. 摄像头初始化无效
主线程内的重初始化代码定义了局部Cap_Foscam,对全局摄像头对象无任何影响,若初始摄像头未打开,会陷入死循环。
修复步骤
步骤1:解决多线程同步
使用std::mutex保护摄像头和帧数据的访问,确保同一时间只有一个线程操作:
std::mutex cam_mutex; // 访问摄像头/Image时加锁 std::lock_guard<std::mutex> lock(cam_mutex);
步骤2:统一VideoWriter实例
删除全局VideoWriter,在main中创建正确分辨率的实例,通过参数传递给Save函数:
// main函数内创建 VideoWriter Output("Output.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), 10, Size(width, height), true); // Save函数参数改为引用传递 int Save(std::shared_ptr<Temporary_Stacks> stacks_ptr, bool which_stack, VideoWriter& output)
步骤3:修正循环边界
将Save内的循环条件改为更安全的写法:
for (int y = 0; y < stacks_ptr->Temp_Stack0.size(); y++)
步骤4:修复摄像头初始化
直接操作全局摄像头对象,避免局部变量覆盖:
while (!Cap_Foscam.isOpened()) { Cap_Foscam.open(0); std::cout << "Connecting..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); // 避免频繁重试 }
步骤5:实现异步保存(按原计划)
若要让Save在独立线程运行,需:
- 用互斥锁保护vector的读写,避免主线程与保存线程冲突。
- 用
std::thread启动保存线程,注意参数传递需用std::ref传递VideoWriter引用:
std::thread save_thread(Save, Temporary_Stacks_ptr, which_Temp_Stack, std::ref(Output)); save_thread.detach(); // 或用join管理线程生命周期
修复后核心代码片段
#include <thread> #include <iostream> #include <vector> #include <opencv2/videoio/videoio.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/core/core.hpp> #include <opencv2/opencv.hpp> #include <memory> #include <mutex> #include <chrono> using namespace std; using namespace cv; std::mutex cam_mutex; int img_ctr = 0; const int Temp_Stack_Size = 15; bool which_Temp_Stack = 0; Mat Image; class Temporary_Stacks { public: std::vector<cv::Mat> Temp_Stack0; std::vector<cv::Mat> Temp_Stack1; }; std::shared_ptr<Temporary_Stacks> Temporary_Stacks_ptr = std::make_shared<Temporary_Stacks>(); cv::VideoCapture Cap_Foscam(0); int Save(std::shared_ptr<Temporary_Stacks> stacks_ptr, bool which_stack, VideoWriter& output) { std::lock_guard<std::mutex> lock(cam_mutex); if (!which_stack) { for (int y = 0; y < stacks_ptr->Temp_Stack0.size(); y++) { cout << "HOPES0" << endl; output.write(stacks_ptr->Temp_Stack0[y]); } stacks_ptr->Temp_Stack0.clear(); } else { for (int y = 0; y < stacks_ptr->Temp_Stack1.size(); y++) { cout << "HOPES1" << endl; output.write(stacks_ptr->Temp_Stack1[y]); } stacks_ptr->Temp_Stack1.clear(); } return which_stack ? 0 : 1; } void Display_Images_Real_Time() { while (1) { std::lock_guard<std::mutex> lock(cam_mutex); if (Cap_Foscam.isOpened() && !Image.empty()) { imshow("Foscam Real Time Feed", Image); } waitKey(1); } } int main() { while (!Cap_Foscam.isOpened()) { Cap_Foscam.open(0); std::cout << "Connecting..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); } int width = Cap_Foscam.get(CAP_PROP_FRAME_WIDTH); int height = Cap_Foscam.get(CAP_PROP_FRAME_HEIGHT); Temporary_Stacks_ptr->Temp_Stack0.reserve(Temp_Stack_Size); Temporary_Stacks_ptr->Temp_Stack1.reserve(Temp_Stack_Size); VideoWriter Output("Output.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), 10, Size(width, height), true); if (!Output.isOpened()) { cout << "Failed to create VideoWriter!" << endl; return -1; } std::thread Real_Time_Video(Display_Images_Real_Time); while (1) { std::lock_guard<std::mutex> lock(cam_mutex); if (!Cap_Foscam.grab()) { cout << "Grab failed!" << endl; std::this_thread::sleep_for(std::chrono::milliseconds(50)); continue; } if (Cap_Foscam.retrieve(Image)) { img_ctr++; cout << img_ctr << endl; if (img_ctr >= Temp_Stack_Size) { which_Temp_Stack = Save(Temporary_Stacks_ptr, which_Temp_Stack, Output); cout << "Saved" << endl; img_ctr = 0; } if (!which_Temp_Stack) { Temporary_Stacks_ptr->Temp_Stack0.push_back(Image.clone()); } else { Temporary_Stacks_ptr->Temp_Stack1.push_back(Image.clone()); } } std::this_thread::sleep_for(std::chrono::milliseconds(50)); } Real_Time_Video.join(); Output.release(); Cap_Foscam.release(); return 0; }
内容的提问来源于stack exchange,提问作者Johnson
相关产品推荐
相关产品推荐

