首页 > 解决方案 > 将 cv::Mat 转换为 std::vector 的通用函数

问题描述

我想知道是否有一种通用方法可以将任何 cv::Mat 转换为 std::vector。对于特定类型,例如 uchar 我可以这样:

std::vector<uchar> convert(const cv::Ma& mat)
{
std::vector<uchar> array;
if (mat.isContinuous()) {
  array.assign(mat.data, mat.data + mat.total());
} else {
  for (int i = 0; i < mat.rows; ++i) {
    array.insert(array.end(), mat.ptr<uchar>(i), mat.ptr<uchar>(i)+mat.cols);
  }
}
return array;
}

但是,我想避免为不同类型重复我的代码,并且有类似的东西:

template<typename T>
std::vector<T> convert(const cv::Mat_<T>& mat)
{
std::vector<T> array;
if (mat.isContinuous()) {
  array.assign(mat.data, mat.data + mat.total());
} else {
  for (int i = 0; i < mat.rows; ++i) {
    array.insert(array.end(), mat.ptr(i), mat.ptr(i)+mat.cols);
  }
}
}

例如,由于 cv::Mat 是通过 cv::Vec4f 模板化的,所以这不起作用。当然我现在可以做类似的事情

template<typename T, int C>
std::vector<T> convert(const cv::Mat_<cv::Vec<T,C>>& mat)

..但为此我收到一条错误消息:note: candidate template ignored: could not match 'Mat_<Vec<type-parameter-0-0, cn> >' against 'cv::Mat'

标签: c++opencvtemplates

解决方案


您可以接受任何Mat并使用 SFINAE 对其进行约束。

例如:

template<class Mat, std::enable_if_t<
         std::is_arithmetic_v<typename Mat::value_type>, int> = 0>
auto convert(const Mat& mat) {
    using T = typename Mat::value_type;
    std::vector<T> arr;
    // ...
    return arr;
}

template<class Mat, std::enable_if_t<
         std::is_arithmetic_v<typename Mat::value_type::value_type>, int> = 0>
auto convert(const Mat& mat) {
    using T = typename Mat::value_type::value_type;
    constexpr auto channels = typename Mat::value_type::channels; // = C
    std::vector<T> arr;
    // ...
    return arr;
}

第一个函数将接受cv::Mat_<T>任何算术T。第二个将接受cv::Mat_<T>任何T这样T::value_type的算术有效类型(例如,cv::Mat_<cv::Vec4f>)。

如果需要,您可以使用 SFINAE 添加更多约束。


推荐阅读