由“Qt程序运行一段时间后崩溃”引发的“opancv库中Mat::clone()函数”在多线程下的注意事项...

  • 问题描述
    • 过程1:从相机中获取图像数据,然后存放到一个cv::Mat对象中(该对象是全局变量,用来交换数据)。由相机的回调函数自动调用。
    • 过程2:将上述的全局变量拷贝并转换qimg,放到Qt界面上显示。该过程由定时器调用。
    • 然后程序会在运行一段时间后,出现“程序异常结束。The process was ended forcefully.”。运行的时间长短不一。

1697577-20190924112259677-931213053.png

  • 问题解决与分析
    • 由于QtCreator的编译器选的是MSVC,而调试器选只有GDB(查了下好像需要CDB)。所以无法debug,只能一点点排查。
    • 测试定时器时间越短,出现问题越快。猜测是多线程下访问冲突。
      • 输出线程id查看,使用std::this_thread::get_id()获取当前线程的ID,发现相机写入Mat对象的过程的线程号 和 定时器调用的读取Mat对象的线程号不一样。这说明相机的SDK在获取图像数据的部分是创建了新的线程进行的。
      • 可是读写应该不冲突,所以看看opencv的Mat::clone()方法。
      inline
      Mat Mat::clone() const
      {
        Mat m;
        copyTo(m);
        return m;
      }
      // 噢 原来是调用的cv::copyTo方法,等等,上面有个const,这下明白了,在拷贝的时候是不允许修改值的,如果正在拷贝,此时相机写入线程正好获取了相机数据,准备写入,这时就发生了冲突。总之读写不能同时进行。
      //那么就是用互斥量将两者互斥,
      #include <mutex>
      std::mutex mtx;
      //在读(Mat::clone()) / 写  之前使用mtx.lock();,之后使用mtx.unlock(); 问题解决啦。
  • 最后测试是否真的是这个原因。声明一个槽函数,连接上某按钮的click动作。调用.clone()并且没有加锁。
void QtGuiApplication1::on_btnThread_clicked()
{
 auto myThread = [] {
  while (1) {
   if (!temp_forSave.empty()) {
    Mat lalala = temp_forSave.clone();
    std::cout << "在创建线程中复制\n";
   }
   std::cout << "创建线程" << std::this_thread::get_id() << "运行" << endl;
  }
 };
 std::thread a(myThread);
 a.join();
}
  • 正常运行时,点击按钮程序立即崩溃(毕竟该线程时while(1)地拷贝)。验证成功。

转载于:https://www.cnblogs.com/neoLin/p/11577345.html

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Python 调用一个接受 `cv::Mat` 数据的 C++ 函数,可以使用 `Boost.Python` 库。 假设有如下的 C++ 代码: ```cpp #include <opencv2/opencv.hpp> void process_image(cv::Mat image) { // 对图像进行处理 // ... } ``` 则需要使用 `Boost.Python` 来将 `process_image` 函数导出到 Python 。示例代码如下: ```cpp #include <boost/python.hpp> #include <opencv2/opencv.hpp> #include <numpy/arrayobject.h> using namespace boost::python; void process_image(cv::Mat image) { // 对图像进行处理 // ... } // 将 cv::Mat 转换为 numpy.ndarray PyObject* mat_to_ndarray(const cv::Mat& mat) { npy_intp dims[2] = { mat.rows, mat.cols }; int dtype = NPY_UINT8; int channels = mat.channels(); if (channels == 1) { dtype = NPY_UINT8; } else if (channels == 3) { dtype = NPY_UINT8; } else if (channels == 4) { dtype = NPY_UINT8; } PyObject* pyobj = PyArray_SimpleNewFromData(2, dims, dtype, mat.data); PyObject* capsule = PyCapsule_New((void*)mat.data, NULL, NULL); PyArray_SetBaseObject((PyArrayObject*)pyobj, capsule); return pyobj; } // 将 numpy.ndarray 转换为 cv::Mat cv::Mat ndarray_to_mat(PyObject* ndarray) { PyArrayObject* np_array = (PyArrayObject*)ndarray; int ndims = PyArray_NDIM(np_array); npy_intp* dims = PyArray_DIMS(np_array); int dtype = PyArray_TYPE(np_array); int channels = (dtype == NPY_UINT8) ? 1 : 3; if (ndims == 3) { channels = dims[2]; } cv::Mat mat(dims[0], dims[1], CV_MAKETYPE(dtype, channels), PyArray_DATA(np_array)); return mat.clone(); } BOOST_PYTHON_MODULE(my_module) { import_array(); // 初始化 NumPy // 导出 process_image 函数 def("process_image", process_image); // 导出 mat_to_ndarray 函数 def("mat_to_ndarray", mat_to_ndarray); // 导出 ndarray_to_mat 函数 def("ndarray_to_mat", ndarray_to_mat); } ``` 在 Python ,可以按照以下方式调用 C++ 函数 `process_image`: ```python import numpy as np import cv2 import my_module # 读取图像 image = cv2.imread("image.jpg") # 将 cv::Mat 转换为 numpy.ndarray image_array = my_module.mat_to_ndarray(image) # 调用 C++ 函数处理图像 my_module.process_image(image_array) ``` 注意:在使用 NumPy 数组时,需要先初始化 NumPy,可以使用 `import_array()` 函数进行初始化。同时,为了避免内存释放问题,需要在 `mat_to_ndarray` 函数使用 `PyCapsule_New` 函数创建一个新的 Python 对象,并将其作为 `numpy.ndarray` 的基础对象。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值