From e5fbb4f5d2a0e04e5296bb1eb4b187ab1d163800 Mon Sep 17 00:00:00 2001 From: Vladislav Sovrasov Date: Fri, 14 Jul 2017 20:17:09 +0300 Subject: [PATCH] Merge pull request #9034 from sovrasov:mats_from_initializer_list Add constructors taking initializer_list for some of OpenCV data types (#9034) * Add a constructor taking initializer_list for Matx * Add a constructor taking initializer list for Mat and Mat_ * Add one more method to initialize Mat to the corresponding tutorial * Add a note how to initialize Matx * CV_CXX_11->CV_CXX11 --- .../mat_the_basic_image_container.markdown | 4 +- modules/core/include/opencv2/core/cvdef.h | 12 +++--- modules/core/include/opencv2/core/mat.hpp | 10 +++++ modules/core/include/opencv2/core/mat.inl.hpp | 19 +++++++++ modules/core/include/opencv2/core/matx.hpp | 46 ++++++++++++++++++++-- modules/core/include/opencv2/core/utility.hpp | 4 +- modules/core/test/test_mat.cpp | 28 ++++++++++++- .../how_to_use_OpenCV_parallel_for_.cpp | 2 +- .../mat_the_basic_image_container.cpp | 8 +++- 9 files changed, 118 insertions(+), 15 deletions(-) diff --git a/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown b/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown index 9e290b8..637e4bc 100644 --- a/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown +++ b/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown @@ -192,10 +192,12 @@ object in multiple ways: ![](images/MatBasicContainerOut3.png) -- For small matrices you may use comma separated initializers: +- For small matrices you may use comma separated initializers or initializer lists (C++11 support is required in the last case): @snippet mat_the_basic_image_container.cpp comma + @snippet mat_the_basic_image_container.cpp list + ![](images/MatBasicContainerOut6.png) - Create a new header for an existing *Mat* object and @ref cv::Mat::clone or @ref cv::Mat::copyTo it. diff --git a/modules/core/include/opencv2/core/cvdef.h b/modules/core/include/opencv2/core/cvdef.h index b128d25..18a2ec6 100644 --- a/modules/core/include/opencv2/core/cvdef.h +++ b/modules/core/include/opencv2/core/cvdef.h @@ -357,13 +357,13 @@ Cv64suf; /****************************************************************************************\ * C++ 11 * \****************************************************************************************/ -#ifndef CV_CXX_11 -# if __cplusplus >= 201103L || defined(_MSC_VER) && _MSC_VER >= 1600 -# define CV_CXX_11 1 +#ifndef CV_CXX11 +# if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600) +# define CV_CXX11 1 # endif #else -# if CV_CXX_11 == 0 -# undef CV_CXX_11 +# if CV_CXX11 == 0 +# undef CV_CXX11 # endif #endif @@ -373,7 +373,7 @@ Cv64suf; \****************************************************************************************/ #ifndef CV_CXX_MOVE_SEMANTICS -# if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(_MSC_VER) && _MSC_VER >= 1600 +# if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(_MSC_VER) && _MSC_VER >= 1600) # define CV_CXX_MOVE_SEMANTICS 1 # elif defined(__clang) # if __has_feature(cxx_rvalue_references) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index 97a9926..722d5db 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -981,6 +981,12 @@ public: */ template explicit Mat(const std::vector<_Tp>& vec, bool copyData=false); +#ifdef CV_CXX11 + /** @overload + */ + template explicit Mat(const std::initializer_list<_Tp> list); +#endif + #ifdef CV_CXX_STD_ARRAY /** @overload */ @@ -2170,6 +2176,10 @@ public: explicit Mat_(const Point3_::channel_type>& pt, bool copyData=true); explicit Mat_(const MatCommaInitializer_<_Tp>& commaInitializer); +#ifdef CV_CXX11 + Mat_(std::initializer_list<_Tp> values); +#endif + #ifdef CV_CXX_STD_ARRAY template explicit Mat_(const std::array<_Tp, _Nm>& arr, bool copyData=false); #endif diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index 3006a1f..405d095 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -570,6 +570,18 @@ Mat::Mat(const std::vector<_Tp>& vec, bool copyData) Mat((int)vec.size(), 1, DataType<_Tp>::type, (uchar*)&vec[0]).copyTo(*this); } +#ifdef CV_CXX11 +template inline +Mat::Mat(const std::initializer_list<_Tp> list) + : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows((int)list.size()), + cols(1), data(0), datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) +{ + if(list.size() == 0) + return; + Mat((int)list.size(), 1, DataType<_Tp>::type, (uchar*)list.begin()).copyTo(*this); +} +#endif + #ifdef CV_CXX_STD_ARRAY template inline Mat::Mat(const std::array<_Tp, _Nm>& arr, bool copyData) @@ -1573,6 +1585,13 @@ Mat_<_Tp>::Mat_(const std::vector<_Tp>& vec, bool copyData) : Mat(vec, copyData) {} +#ifdef CV_CXX11 +template inline +Mat_<_Tp>::Mat_(std::initializer_list<_Tp> list) + : Mat(list) +{} +#endif + #ifdef CV_CXX_STD_ARRAY template template inline Mat_<_Tp>::Mat_(const std::array<_Tp, _Nm>& arr, bool copyData) diff --git a/modules/core/include/opencv2/core/matx.hpp b/modules/core/include/opencv2/core/matx.hpp index 56a2a93..6469962 100644 --- a/modules/core/include/opencv2/core/matx.hpp +++ b/modules/core/include/opencv2/core/matx.hpp @@ -53,6 +53,10 @@ #include "opencv2/core/traits.hpp" #include "opencv2/core/saturate.hpp" +#ifdef CV_CXX11 +#include +#endif + namespace cv { @@ -77,12 +81,21 @@ If you need a more flexible type, use Mat . The elements of the matrix M are acc M(i,j) notation. Most of the common matrix operations (see also @ref MatrixExpressions ) are available. To do an operation on Matx that is not implemented, you can easily convert the matrix to Mat and backwards: -@code +@code{.cpp} Matx33f m(1, 2, 3, 4, 5, 6, 7, 8, 9); cout << sum(Mat(m*m.t())) << endl; - @endcode +@endcode +Except of the plain constructor which takes a list of elements, Matx can be initialized from a C-array: +@code{.cpp} + float values[] = { 1, 2, 3}; + Matx31f m(values); +@endcode +In case if C++11 features are avaliable, std::initializer_list can be also used to initizlize Matx: +@code{.cpp} + Matx31f m = { 1, 2, 3}; +@endcode */ template class Matx { @@ -125,6 +138,10 @@ public: _Tp v12, _Tp v13, _Tp v14, _Tp v15); //!< 1x16, 4x4 or 16x1 matrix explicit Matx(const _Tp* vals); //!< initialize from a plain array +#ifdef CV_CXX11 + Matx(std::initializer_list<_Tp>); //!< initialize from an initializer list +#endif + static Matx all(_Tp alpha); static Matx zeros(); static Matx ones(); @@ -327,6 +344,10 @@ public: Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13); //!< 14-element vector constructor explicit Vec(const _Tp* values); +#ifdef CV_CXX11 + Vec(std::initializer_list<_Tp>); +#endif + Vec(const Vec<_Tp, cn>& v); static Vec all(_Tp alpha); @@ -616,6 +637,19 @@ Matx<_Tp, m, n>::Matx(const _Tp* values) for( int i = 0; i < channels; i++ ) val[i] = values[i]; } +#ifdef CV_CXX11 +template inline +Matx<_Tp, m, n>::Matx(std::initializer_list<_Tp> list) +{ + CV_DbgAssert(list.size() == channels); + int i = 0; + for(const auto& elem : list) + { + val[i++] = elem; + } +} +#endif + template inline Matx<_Tp, m, n> Matx<_Tp, m, n>::all(_Tp alpha) { @@ -957,6 +991,12 @@ template inline Vec<_Tp, cn>::Vec(const _Tp* values) : Matx<_Tp, cn, 1>(values) {} +#ifdef CV_CXX11 +template inline +Vec<_Tp, cn>::Vec(std::initializer_list<_Tp> list) + : Matx<_Tp, cn, 1>(list) {} +#endif + template inline Vec<_Tp, cn>::Vec(const Vec<_Tp, cn>& m) : Matx<_Tp, cn, 1>(m.val) {} @@ -1081,7 +1121,7 @@ Vec<_Tp, cn> normalize(const Vec<_Tp, cn>& v) -//////////////////////////////// matx comma initializer ////////////////////////////////// +//////////////////////////////// vec comma initializer ////////////////////////////////// template static inline diff --git a/modules/core/include/opencv2/core/utility.hpp b/modules/core/include/opencv2/core/utility.hpp index a7a3eb9..c844c17 100644 --- a/modules/core/include/opencv2/core/utility.hpp +++ b/modules/core/include/opencv2/core/utility.hpp @@ -56,7 +56,7 @@ #include "opencv2/core.hpp" #include -#ifdef CV_CXX_11 +#ifdef CV_CXX11 #include #endif @@ -482,7 +482,7 @@ public: */ CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body, double nstripes=-1.); -#ifdef CV_CXX_11 +#ifdef CV_CXX11 class ParallelLoopBodyLambdaWrapper : public ParallelLoopBody { private: diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 1739503..4145895 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1398,6 +1398,15 @@ TEST(Core_Matx, fromMat_) ASSERT_EQ( cvtest::norm(a, b, NORM_INF), 0.); } +#ifdef CV_CXX11 +TEST(Core_Matx, from_initializer_list) +{ + Mat_ a = (Mat_(2,2) << 10, 11, 12, 13); + Matx22d b = {10, 11, 12, 13}; + ASSERT_EQ( cvtest::norm(a, b, NORM_INF), 0.); +} +#endif + TEST(Core_InputArray, empty) { vector > data; @@ -1735,7 +1744,7 @@ TEST(Mat, regression_8680) ASSERT_EQ(mat.channels(), 2); } -#ifdef CV_CXX_11 +#ifdef CV_CXX11 TEST(Mat_, range_based_for) { @@ -1751,4 +1760,21 @@ TEST(Mat_, range_based_for) ASSERT_DOUBLE_EQ(norm(img, ref), 0.); } +TEST(Mat, from_initializer_list) +{ + Mat A({1.f, 2.f, 3.f}); + Mat_ B(3, 1); B << 1, 2, 3; + + ASSERT_EQ(A.type(), CV_32F); + ASSERT_DOUBLE_EQ(norm(A, B, NORM_INF), 0.); +} + +TEST(Mat_, from_initializer_list) +{ + Mat_ A = {1, 2, 3}; + Mat_ B(3, 1); B << 1, 2, 3; + + ASSERT_DOUBLE_EQ(norm(A, B, NORM_INF), 0.); +} + #endif diff --git a/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp b/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp index 5f7013a..ed7d4a0 100644 --- a/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp +++ b/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp @@ -102,7 +102,7 @@ int main() double t1 = (double) getTickCount(); - #ifdef CV_CXX_11 + #ifdef CV_CXX11 //! [mandelbrot-parallel-call-cxx11] parallel_for_(Range(0, mandelbrotImg.rows*mandelbrotImg.cols), [&](const Range& range){ diff --git a/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp b/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp index 77ea938..d65e9b5 100644 --- a/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp +++ b/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp @@ -58,7 +58,13 @@ int main(int,char**) Mat C = (Mat_(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); cout << "C = " << endl << " " << C << endl << endl; //! [comma] - + // do the same with initializer_list +#ifdef CV_CXX11 + //! [list] + C = (Mat_({0, -1, 0, -1, 5, -1, 0, -1, 0})).reshape(3); + cout << "C = " << endl << " " << C << endl << endl; + //! [list] +#endif //! [clone] Mat RowClone = C.row(1).clone(); cout << "RowClone = " << endl << " " << RowClone << endl << endl; -- 2.7.4