Simon
Simon

Reputation: 764

Generic function to convert a cv::Mat into std::vector

I am wondering if there is a generic approach to convert any cv::Mat to a std::vector. For specific types e.g. uchar I can to something like:

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;
}

However, I would like to avoid duplicating my code for different types and have something like:

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);
  }
}
}

Which doesn't work since cv::Mat is templated over cv::Vec4f for instance. Of course I could do now something like

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

.. but for this I get an error message: note: candidate template ignored: could not match 'Mat_<Vec<type-parameter-0-0, cn> >' against 'cv::Mat'

Upvotes: 1

Views: 294

Answers (1)

Evg
Evg

Reputation: 26292

You can accept any Mat and constraint it using SFINAE.

For example:

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;
}

The first function will accept cv::Mat_<T> with any arithmetic T. The second one will accept cv::Mat_<T> with any T such that T::value_type is a valid type that is arithmetic (e.g., cv::Mat_<cv::Vec4f>).

You can add more constraints using SFINAE if needed.

Upvotes: 1

Related Questions