parent
983823468d
commit
0ebe30a362
17 changed files with 431 additions and 333 deletions
@ -0,0 +1,240 @@ |
||||
#ifndef __OPENCV_DNN_DNN_BLOB_HPP__ |
||||
#define __OPENCV_DNN_DNN_BLOB_HPP__ |
||||
#include <opencv2/core.hpp> |
||||
#include <vector> |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace dnn |
||||
{ |
||||
/** @brief provides convenient methods for continuous n-dimensional array processing, dedicated for convolution neural networks
|
||||
It's realized as wrapper over \ref cv::Mat and \ref cv::UMat and will support methods for CPU/GPU switching |
||||
*/ |
||||
class CV_EXPORTS Blob |
||||
{ |
||||
public: |
||||
explicit Blob(); |
||||
explicit Blob(InputArray in); |
||||
|
||||
void create(int ndims, const int *sizes, int type = CV_32F); |
||||
void create(Vec4i shape, int type = CV_32F); |
||||
void create(int num, int cn, int rows, int cols, int type = CV_32F); |
||||
|
||||
void fill(InputArray in); |
||||
void fill(int ndims, const int *sizes, int type, void *data, bool deepCopy = true); |
||||
|
||||
Mat& getMatRef(); |
||||
const Mat& getMatRef() const; |
||||
Mat getMat(); |
||||
Mat getMat(int n, int cn); |
||||
|
||||
//shape getters
|
||||
///returns real count of blob dimensions
|
||||
int dims() const; |
||||
|
||||
/** @brief returns size of corresponding dimension (axis)
|
||||
@param axis dimension index |
||||
Python-like indexing is supported, so \p axis can be negative, i. e. -1 is last dimension. |
||||
Supposed that size of non-existing dimensions equal to 1, so the method always finished. |
||||
*/ |
||||
int size(int axis) const; |
||||
|
||||
/** @brief returns size of corresponding dimension (axis)
|
||||
@param axis dimension index |
||||
Python-like indexing is supported, so \p axis can be negative, i. e. -1 is last dimension. |
||||
@note Unlike ::size, if \p axis points to non-existing dimension then an error will be generated. |
||||
*/ |
||||
int sizeAt(int axis) const; |
||||
|
||||
/** @brief returns number of elements
|
||||
@param startAxis starting axis (inverse indexing can be used) |
||||
@param endAxis ending (excluded) axis |
||||
@see ::canonicalAxis |
||||
*/ |
||||
size_t total(int startAxis = 0, int endAxis = -1) const; |
||||
|
||||
/** @brief converts axis index to canonical format (where 0 <= axis <= ::dims)
|
||||
*/ |
||||
int canonicalAxis(int axis) const; |
||||
|
||||
/** @brief returns real shape of the blob
|
||||
*/ |
||||
std::vector<int> shape() const; |
||||
|
||||
//shape getters, oriented for 4-dim Blobs processing
|
||||
int cols() const; |
||||
int rows() const; |
||||
int channels() const; |
||||
int num() const; |
||||
Size size2() const; |
||||
Vec4i shape4() const; |
||||
|
||||
//CPU data pointer functions
|
||||
int offset(int n = 0, int cn = 0, int row = 0, int col = 0) const; |
||||
uchar *ptrRaw(int n = 0, int cn = 0, int row = 0, int col = 0); |
||||
float *ptrf(int n = 0, int cn = 0, int row = 0, int col = 0); |
||||
template<typename TFloat> |
||||
TFloat *ptr(int n = 0, int cn = 0, int row = 0, int col = 0); |
||||
|
||||
int type() const; |
||||
bool isFloat() const; |
||||
bool isDouble() const; |
||||
|
||||
private: |
||||
const int *sizes() const; |
||||
|
||||
Mat m; |
||||
}; |
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline int Blob::canonicalAxis(int axis) const |
||||
{ |
||||
CV_Assert(-dims() <= axis && axis < dims()); |
||||
|
||||
if (axis < 0) |
||||
{ |
||||
return dims() + axis; |
||||
} |
||||
return axis; |
||||
} |
||||
|
||||
inline int Blob::size(int axis) const |
||||
{ |
||||
if (axis < 0) |
||||
axis += dims(); |
||||
|
||||
if (axis < 0 || axis >= dims()) |
||||
return 1; |
||||
|
||||
return sizes()[axis]; |
||||
} |
||||
|
||||
inline int Blob::sizeAt(int axis) const |
||||
{ |
||||
CV_Assert(-dims() <= axis && axis < dims()); |
||||
|
||||
if (axis < 0) |
||||
axis += dims(); |
||||
|
||||
return sizes()[axis]; |
||||
} |
||||
|
||||
inline size_t Blob::total(int startAxis, int endAxis) const |
||||
{ |
||||
startAxis = canonicalAxis(startAxis); |
||||
|
||||
if (endAxis == -1) |
||||
endAxis = dims(); |
||||
|
||||
CV_Assert(startAxis <= endAxis && endAxis <= dims()); |
||||
|
||||
size_t size = 1; //assume that blob isn't empty
|
||||
for (int i = startAxis; i < endAxis; i++) |
||||
size *= (size_t)sizes()[i]; |
||||
|
||||
return size; |
||||
} |
||||
|
||||
inline int Blob::offset(int n, int cn, int row, int col) const |
||||
{ |
||||
CV_DbgAssert(0 <= n && n < num() && 0 <= cn && cn < channels() && 0 <= row && row < rows() && 0 <= col && col < cols()); |
||||
return ((n*channels() + cn)*rows() + row)*cols() + col; |
||||
} |
||||
|
||||
inline float *Blob::ptrf(int n, int cn, int row, int col) |
||||
{ |
||||
CV_Assert(type() == CV_32F); |
||||
return (float*)m.data + offset(n, cn, row, col); |
||||
} |
||||
|
||||
inline uchar *Blob::ptrRaw(int n, int cn, int row, int col) |
||||
{ |
||||
return m.data + m.elemSize() * offset(n, cn, row, col); |
||||
} |
||||
|
||||
template<typename TFloat> |
||||
inline TFloat* Blob::ptr(int n, int cn, int row, int col) |
||||
{ |
||||
CV_Assert(type() == cv::DataDepth<TFloat>::value); |
||||
return (TFloat*) ptrRaw(n, cn, row, col); |
||||
} |
||||
|
||||
inline std::vector<int> Blob::shape() const |
||||
{ |
||||
return std::vector<int>(sizes(), sizes() + dims()); |
||||
} |
||||
|
||||
inline Mat& Blob::getMatRef() |
||||
{ |
||||
return m; |
||||
} |
||||
|
||||
inline const Mat& Blob::getMatRef() const |
||||
{ |
||||
return m; |
||||
} |
||||
|
||||
inline Mat Blob::getMat() |
||||
{ |
||||
return m; |
||||
} |
||||
|
||||
inline Mat Blob::getMat(int n, int cn) |
||||
{ |
||||
return Mat(rows(), cols(), m.type(), this->ptrRaw(n, cn)); |
||||
} |
||||
|
||||
inline int Blob::cols() const |
||||
{ |
||||
return size(-1); |
||||
} |
||||
|
||||
inline int Blob::rows() const |
||||
{ |
||||
return size(-2); |
||||
} |
||||
|
||||
inline Size Blob::size2() const |
||||
{ |
||||
return Size(cols(), rows()); |
||||
} |
||||
|
||||
inline int Blob::channels() const |
||||
{ |
||||
return size(-3); |
||||
} |
||||
|
||||
inline int Blob::num() const |
||||
{ |
||||
return size(-4); |
||||
} |
||||
|
||||
inline int Blob::type() const |
||||
{ |
||||
return m.depth(); |
||||
} |
||||
|
||||
inline bool Blob::isFloat() const |
||||
{ |
||||
return (type() == CV_32F); |
||||
} |
||||
|
||||
inline bool Blob::isDouble() const |
||||
{ |
||||
return (type() == CV_32F); |
||||
} |
||||
|
||||
inline const int * Blob::sizes() const |
||||
{ |
||||
return &m.size[0]; |
||||
} |
||||
|
||||
inline int Blob::dims() const |
||||
{ |
||||
return m.dims; |
||||
} |
||||
} |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,132 @@ |
||||
#include "precomp.hpp" |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace dnn |
||||
{ |
||||
|
||||
Blob::Blob() |
||||
{ |
||||
int zeros[4] = { 0, 0, 0, 0 }; |
||||
m = Mat(4, zeros, CV_32F, NULL); |
||||
} |
||||
|
||||
Blob::Blob(InputArray in) |
||||
{ |
||||
CV_Assert(in.isMat() || in.isUMat()); |
||||
|
||||
if (in.isMat()) |
||||
{ |
||||
Mat mat = in.getMat(); |
||||
|
||||
CV_Assert(mat.dims == 2); |
||||
int rows = mat.rows; |
||||
int cols = mat.cols; |
||||
int cn = mat.channels(); |
||||
int type = mat.type(); |
||||
int dstType = CV_MAKE_TYPE(CV_MAT_DEPTH(type), 1); |
||||
|
||||
int size[3] = { cn, rows, cols }; |
||||
this->create(3, size, dstType); |
||||
uchar *data = m.data; |
||||
int step = rows * cols * CV_ELEM_SIZE(dstType); |
||||
|
||||
if (cn == 1) |
||||
{ |
||||
Mat wrapper2D(rows, cols, dstType, m.data); |
||||
mat.copyTo(wrapper2D); |
||||
} |
||||
else |
||||
{ |
||||
std::vector<Mat> wrappers(cn); |
||||
for (int i = 0; i < cn; i++) |
||||
{ |
||||
wrappers[i] = Mat(rows, cols, dstType, data); |
||||
data += step; |
||||
} |
||||
|
||||
cv::split(mat, wrappers); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
CV_Error(cv::Error::StsNotImplemented, "Not Implemented"); |
||||
} |
||||
} |
||||
|
||||
inline void squeezeShape_(const int srcDims, const int *srcSizes, const int dstDims, int *dstSizes) |
||||
{ |
||||
const int m = std::min(dstDims, srcDims); |
||||
|
||||
//copy common(last) dimensions
|
||||
for (int i = 0; i < m; i++) |
||||
dstSizes[dstDims - 1 - i] = srcSizes[srcDims - 1 - i]; |
||||
|
||||
//either flatten extra dimensions
|
||||
for (int i = m; i < srcDims; i++) |
||||
dstSizes[0] *= srcSizes[srcDims - 1 - i]; |
||||
|
||||
//either fill gaps
|
||||
for (int i = m; i < dstDims; i++) |
||||
dstSizes[dstDims - 1 - i] = 1; |
||||
} |
||||
|
||||
static Vec4i squeezeShape4(const int ndims, const int *sizes) |
||||
{ |
||||
Vec4i res; |
||||
squeezeShape_(ndims, sizes, 4, &res[0]); |
||||
return res; |
||||
} |
||||
|
||||
void Blob::fill(int ndims, const int *sizes, int type, void *data, bool deepCopy) |
||||
{ |
||||
CV_Assert(type == CV_32F || type == CV_64F); |
||||
|
||||
Vec4i shape = squeezeShape4(ndims, sizes); |
||||
|
||||
if (deepCopy) |
||||
{ |
||||
m.create(4, &shape[0], type); |
||||
size_t dataSize = m.total() * m.elemSize(); |
||||
memcpy(m.data, data, dataSize); |
||||
} |
||||
else |
||||
{ |
||||
m = Mat(shape.channels, &shape[0], type, data); |
||||
} |
||||
} |
||||
|
||||
void Blob::fill(InputArray in) |
||||
{ |
||||
CV_Assert(in.isMat() || in.isMatVector()); |
||||
|
||||
//TODO
|
||||
*this = Blob(in); |
||||
} |
||||
|
||||
void Blob::create(int ndims, const int *sizes, int type) |
||||
{ |
||||
CV_Assert(type == CV_32F || type == CV_64F); |
||||
Vec4i shape = squeezeShape4(ndims, sizes); |
||||
m.create(shape.channels, &shape[0], type); |
||||
} |
||||
|
||||
void Blob::create(Vec4i shape, int type) |
||||
{ |
||||
m.create(shape.channels, &shape[0], type); |
||||
} |
||||
|
||||
void Blob::create(int num, int cn, int rows, int cols, int type) |
||||
{ |
||||
Vec4i shape(num, cn, rows, cols); |
||||
create(4, &shape[0], type); |
||||
} |
||||
|
||||
Vec4i Blob::shape4() const |
||||
{ |
||||
return squeezeShape4(dims(), sizes()); |
||||
} |
||||
|
||||
|
||||
} |
||||
} |
Loading…
Reference in new issue