123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- // This file is part of OpenCV project.
- // It is subject to the license terms in the LICENSE file found in the top-level directory
- // of this distribution and at http://opencv.org/license.html.
- //
- // Copyright (C) 2018 Intel Corporation
- #ifndef OPENCV_GAPI_OWN_MAT_HPP
- #define OPENCV_GAPI_OWN_MAT_HPP
- #include <opencv2/gapi/opencv_includes.hpp>
- #include <opencv2/gapi/own/types.hpp>
- #include <opencv2/gapi/own/scalar.hpp>
- #include <opencv2/gapi/own/saturate.hpp>
- #include <opencv2/gapi/own/assert.hpp>
- #include <memory> //std::shared_ptr
- #include <cstring> //std::memcpy
- #include <numeric> //std::accumulate
- #include <vector>
- #include <opencv2/gapi/util/throw.hpp>
- namespace cv { namespace gapi { namespace own {
- namespace detail {
- template <typename T, unsigned char channels>
- void assign_row(void* ptr, int cols, Scalar const& s)
- {
- auto p = static_cast<T*>(ptr);
- for (int c = 0; c < cols; c++)
- {
- for (int ch = 0; ch < channels; ch++)
- {
- p[c * channels + ch] = saturate<T>(s[ch], roundd);
- }
- }
- }
- inline size_t default_step(int type, int cols)
- {
- return CV_ELEM_SIZE(type) * cols;
- }
- //Matrix header, i.e. fields that are unique to each Mat object.
- //Devoted class is needed to implement custom behavior on move (erasing state of moved from object)
- struct MatHeader{
- enum { AUTO_STEP = 0};
- enum { TYPE_MASK = 0x00000FFF };
- MatHeader() = default;
- MatHeader(int _rows, int _cols, int type, void* _data, size_t _step)
- : flags((type & TYPE_MASK)), rows(_rows), cols(_cols), data((uchar*)_data), step(_step == AUTO_STEP ? detail::default_step(type, _cols) : _step)
- {}
- MatHeader(const std::vector<int> &_dims, int type, void* _data)
- : flags((type & TYPE_MASK)), data((uchar*)_data), step(0), dims(_dims)
- {}
- MatHeader(const MatHeader& ) = default;
- MatHeader(MatHeader&& src) : MatHeader(src) // reuse copy constructor here
- {
- MatHeader empty; //give it a name to call copy(not move) assignment below
- src = empty;
- }
- MatHeader& operator=(const MatHeader& ) = default;
- MatHeader& operator=(MatHeader&& src)
- {
- *this = src; //calling a copy assignment here, not move one
- MatHeader empty; //give it a name to call copy(not move) assignment below
- src = empty;
- return *this;
- }
- /*! includes several bit-fields:
- - depth
- - number of channels
- */
- int flags = 0;
- //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
- int rows = 0, cols = 0;
- //! pointer to the data
- uchar* data = nullptr;
- size_t step = 0;
- //! dimensions (ND-case)
- std::vector<int> dims;
- };
- } // namespace detail
- //concise version of cv::Mat suitable for GAPI needs (used when no dependence on OpenCV is required)
- class Mat : public detail::MatHeader{
- public:
- Mat() = default;
- /** @overload
- @param _rows Number of rows in a 2D array.
- @param _cols Number of columns in a 2D array.
- @param _type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or
- CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices.
- @param _data Pointer to the user data. Matrix constructors that take data and step parameters do not
- allocate matrix data. Instead, they just initialize the matrix header that points to the specified
- data, which means that no data is copied. This operation is very efficient and can be used to
- process external data using OpenCV functions. The external data is not automatically deallocated, so
- you should take care of it.
- @param _step Number of bytes each matrix row occupies. The value should include the padding bytes at
- the end of each row, if any. If the parameter is missing (set to AUTO_STEP ), no padding is assumed
- and the actual step is calculated as cols*elemSize(). See Mat::elemSize.
- */
- Mat(int _rows, int _cols, int _type, void* _data, size_t _step = AUTO_STEP)
- : MatHeader (_rows, _cols, _type, _data, _step)
- {}
- Mat(const std::vector<int> &_dims, int _type, void* _data)
- : MatHeader (_dims, _type, _data)
- {}
- Mat(std::vector<int> &&_dims, int _type, void* _data)
- : MatHeader (std::move(_dims), _type, _data)
- {}
- Mat(Mat const& src, const Rect& roi )
- : Mat(src)
- {
- rows = roi.height;
- cols = roi.width;
- data = ptr(roi.y, roi.x);
- }
- Mat(Mat const& ) = default;
- Mat(Mat&& ) = default;
- Mat& operator=(Mat const& ) = default;
- Mat& operator=(Mat&& ) = default;
- /** @brief Sets all or some of the array elements to the specified value.
- @param s Assigned scalar converted to the actual array type.
- */
- Mat& operator = (const Scalar& s)
- {
- constexpr unsigned max_channels = 4; //Scalar can't fit more than 4
- using func_p_t = void (*)(void*, int, Scalar const&);
- using detail::assign_row;
- #define TABLE_ENTRY(type) {assign_row<type, 1>, assign_row<type, 2>, assign_row<type, 3>, assign_row<type, 4>}
- static constexpr func_p_t func_tbl[][max_channels] = {
- TABLE_ENTRY(uchar),
- TABLE_ENTRY(schar),
- TABLE_ENTRY(ushort),
- TABLE_ENTRY(short),
- TABLE_ENTRY(int),
- TABLE_ENTRY(float),
- TABLE_ENTRY(double)
- };
- #undef TABLE_ENTRY
- static_assert(CV_8U == 0 && CV_8S == 1 && CV_16U == 2 && CV_16S == 3
- && CV_32S == 4 && CV_32F == 5 && CV_64F == 6,
- "OCV type ids used as indexes to array, thus exact numbers are important!"
- );
- const auto depth = static_cast<unsigned int>(this->depth());
- GAPI_Assert(depth < sizeof(func_tbl)/sizeof(func_tbl[0]));
- if (dims.empty())
- {
- const auto channels = static_cast<unsigned int>(this->channels());
- GAPI_Assert(channels <= max_channels);
- auto* f = func_tbl[depth][channels - 1];
- for (int r = 0; r < rows; ++r)
- {
- (*f)(static_cast<void *>(ptr(r)), cols, s );
- }
- }
- else
- {
- auto* f = func_tbl[depth][0];
- // FIXME: better to refactor assign_row to use std::size_t by default
- (*f)(static_cast<void *>(data), static_cast<int>(total()), s);
- }
- return *this;
- }
- /** @brief Returns the matrix element size in bytes.
- The method returns the matrix element size in bytes. For example, if the matrix type is CV_16SC3 ,
- the method returns 3\*sizeof(short) or 6.
- */
- size_t elemSize() const
- {
- return CV_ELEM_SIZE(type());
- }
- /** @brief Returns the type of a matrix element.
- The method returns a matrix element type. This is an identifier compatible with the CvMat type
- system, like CV_16SC3 or 16-bit signed 3-channel array, and so on.
- */
- int type() const {return CV_MAT_TYPE(flags);}
- /** @brief Returns the depth of a matrix element.
- The method returns the identifier of the matrix element depth (the type of each individual channel).
- For example, for a 16-bit signed element array, the method returns CV_16S . A complete list of
- matrix types contains the following values:
- - CV_8U - 8-bit unsigned integers ( 0..255 )
- - CV_8S - 8-bit signed integers ( -128..127 )
- - CV_16U - 16-bit unsigned integers ( 0..65535 )
- - CV_16S - 16-bit signed integers ( -32768..32767 )
- - CV_32S - 32-bit signed integers ( -2147483648..2147483647 )
- - CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )
- - CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )
- */
- int depth() const {return CV_MAT_DEPTH(flags);}
- /** @brief Returns the number of matrix channels.
- The method returns the number of matrix channels.
- If matrix is N-dimensional, -1 is returned.
- */
- int channels() const {return dims.empty() ? CV_MAT_CN(flags) : -1;}
- /**
- @param _rows New number of rows.
- @param _cols New number of columns.
- @param _type New matrix type.
- */
- void create(int _rows, int _cols, int _type)
- {
- create(Size{_cols, _rows}, _type);
- }
- /** @overload
- @param _size Alternative new matrix size specification: Size(cols, rows)
- @param _type New matrix type.
- */
- void create(Size _size, int _type)
- {
- GAPI_Assert(_size.height >= 0 && _size.width >= 0);
- if (_size != Size{cols, rows} )
- {
- Mat tmp{_size.height, _size.width, _type, nullptr};
- tmp.memory.reset(new uchar[ tmp.step * tmp.rows], [](uchar * p){delete[] p;});
- tmp.data = tmp.memory.get();
- *this = std::move(tmp);
- }
- }
- void create(const std::vector<int> &_dims, int _type)
- {
- // FIXME: make a proper reallocation-on-demands
- // WARNING: no tensor views, so no strides
- Mat tmp{_dims, _type, nullptr};
- // FIXME: this accumulate duplicates a lot
- const auto sz = std::accumulate(_dims.begin(), _dims.end(), 1, std::multiplies<int>());
- tmp.memory.reset(new uchar[CV_ELEM_SIZE(_type)*sz], [](uchar * p){delete[] p;});
- tmp.data = tmp.memory.get();
- *this = std::move(tmp);
- }
- /** @brief Creates a full copy of the matrix and the underlying data.
- The method creates a full copy of the matrix. The original step[] is not taken into account.
- So, the copy has a continuous buffer occupying total() * elemSize() bytes.
- */
- Mat clone() const
- {
- Mat m;
- copyTo(m);
- return m;
- }
- /** @brief Copies the matrix to another one.
- The method copies the matrix data to another matrix. Before copying the data, the method invokes :
- @code
- m.create(this->size(), this->type());
- @endcode
- so that the destination matrix is reallocated if needed. While m.copyTo(m); works flawlessly, the
- function does not handle the case of a partial overlap between the source and the destination
- matrices.
- */
- void copyTo(Mat& dst) const
- {
- if (dims.empty())
- {
- dst.create(rows, cols, type());
- for (int r = 0; r < rows; ++r)
- {
- std::copy_n(ptr(r), detail::default_step(type(),cols), dst.ptr(r));
- }
- }
- else
- {
- dst.create(dims, depth());
- std::copy_n(data, total()*elemSize(), data);
- }
- }
- /** @brief Returns true if the array has no elements.
- The method returns true if Mat::total() is 0 or if Mat::data is NULL. Because of pop_back() and
- resize() methods `M.total() == 0` does not imply that `M.data == NULL`.
- */
- bool empty() const
- {
- return data == 0 || total() == 0;
- }
- /** @brief Returns the total number of array elements.
- The method returns the number of array elements (a number of pixels if the array represents an
- image).
- */
- size_t total() const
- {
- return dims.empty()
- ? (static_cast<std::size_t>(rows) * cols)
- : std::accumulate(dims.begin(), dims.end(), static_cast<std::size_t>(1), std::multiplies<size_t>());
- }
- /** @overload
- @param roi Extracted submatrix specified as a rectangle.
- */
- Mat operator()( const Rect& roi ) const
- {
- return Mat{*this, roi};
- }
- /** @brief Returns a pointer to the specified matrix row.
- The methods return `uchar*` or typed pointer to the specified matrix row. See the sample in
- Mat::isContinuous to know how to use these methods.
- @param row Index along the dimension 0
- @param col Index along the dimension 1
- */
- uchar* ptr(int row, int col = 0)
- {
- return const_cast<uchar*>(const_cast<const Mat*>(this)->ptr(row,col));
- }
- /** @overload */
- const uchar* ptr(int row, int col = 0) const
- {
- return data + step * row + CV_ELEM_SIZE(type()) * col;
- }
- private:
- //actual memory allocated for storage, or nullptr if object is non owning view to over memory
- std::shared_ptr<uchar> memory;
- };
- } //namespace own
- } //namespace gapi
- } //namespace cv
- #endif /* OPENCV_GAPI_OWN_MAT_HPP */
|