Reputation: 764
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
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