【问题标题】:Generic function to convert a cv::Mat into std::vector将 cv::Mat 转换为 std::vector 的通用函数
【发布时间】:2020-01-08 15:12:24
【问题描述】:

我想知道是否有一种通用方法可以将任何 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_&lt;Vec&lt;type-parameter-0-0, cn&gt; &gt;' against 'cv::Mat'

【问题讨论】:

  • 标量矩阵和向量矩阵是不同的东西。您希望如何将后者转换为向量?
  • 是的,确实这些是不同的东西,但它们仍然可以排列成一个大小为 rows*cols*depth 的标量向量。
  • 所以你想“扁平化”向量矩阵?例如,您是否需要对矩阵矩阵进行泛化?
  • 没错,我想把它展平。嗯,如果我们将向量视为 矩阵,那么输入就是一种矩阵矩阵。为什么要问?
  • 使用模板,您可以编写一个非常通用的解决方案。所以我想了解你是需要它还是cv::Mat_&lt;cv::Vec&lt;T,C&gt;&gt;是你唯一关心的类型。

标签: c++ opencv templates


【解决方案1】:

您可以接受任何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_&lt;T&gt; 与任何算术T。第二个将接受cv::Mat_&lt;T&gt; 和任何T,这样T::value_type 是算术的有效类型(例如,cv::Mat_&lt;cv::Vec4f&gt;)。

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

【讨论】:

  • 好的,我知道这是怎么回事。是的,这非常有帮助。但它还不能很好地工作,因为我得到一个 ` 候选模板被忽略:替换失败 [with Mat = cv::Mat]: no member named 'value_type' in 'cv::Mat'`
  • @Simon,对于cv::Mat,您需要单独的重载,因为它没有value_type 成员类型。 cv::Matcv::Mat_&lt;T&gt; 在这方面完全不同。
  • @Simon 例如,您可以让第一个重载采用cv::Mat,第二个采用cv::Mat_。然后第二个重载可以调用另一个具有两个重载的函数,一个用于算术类型,另一个用于cv::Vec 类型。
  • @Simon,注意cv::Mat 不能在cv::Vec4f 上进行模板化。
  • @Simon 你不能直接做。您需要有关元素类型的其他信息 (T)。 Mat 有一个type() 成员函数,它以int 的形式返回类型,这样DataType&lt;T&gt;::type 就等于它(Mat_ 将在构造函数中将DataType&lt;T&gt;::type 传递给Mat)。您不能简单地“反转”DataType,因为T 是编译时数量,但type() 是运行时数量。您可以做的是编写一些模板函数并在一系列if 语句中调用它,每个语句对应一种支持的数据类型。如果对类型有一些限制,可以合理简化。
猜你喜欢
  • 1970-01-01
  • 2017-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-01
  • 2017-10-26
  • 2012-04-19
  • 1970-01-01
相关资源
最近更新 更多