增加换肤功能

This commit is contained in:
启星
2025-08-14 10:07:49 +08:00
parent f6964c1e89
commit 4f9318d98e
8789 changed files with 978530 additions and 2 deletions

View File

@@ -0,0 +1,217 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_NARY_MAT_ITERATOR_HPP_
#define FBC_CV_CORE_NARY_MAT_ITERATOR_HPP_
/* reference: include/opencv2/core/map.hpp
modules/core/src/matrix.cpp
*/
#include "mat.hpp"
namespace yt_tinycv {
// n-ary multi-dimensional array iterator
// Use the class to implement unary, binary, and, generally, n-ary element-wise operations on multi - dimensional arrays.
template<typename _Tp, int chs> class NAryMatIterator {
public:
// the default constructor
NAryMatIterator();
// the full constructor taking arbitrary number of n-dim matrices
NAryMatIterator(const Mat_<_Tp, chs>** arrays, uchar** ptrs, int narrays = -1);
// the full constructor taking arbitrary number of n-dim matrices
NAryMatIterator(const Mat_<_Tp, chs>** arrays, Mat_<_Tp, chs>* planes, int narrays = -1);
// the separate iterator initialization method
void init(const Mat_<_Tp, chs>** arrays, Mat_<_Tp, chs>* planes, uchar** ptrs, int narrays = -1);
// proceeds to the next plane of every iterated matrix
NAryMatIterator& operator ++();
// proceeds to the next plane of every iterated matrix (postfix increment operator)
NAryMatIterator operator ++(int);
// the iterated arrays
const Mat_<_Tp, chs>** arrays;
// the current planes
Mat_<_Tp, chs>* planes;
// data pointers
uchar** ptrs;
// the number of arrays
int narrays;
// the number of hyper-planes that the iterator steps through
size_t nplanes;
// the size of each segment (in elements)
size_t size;
protected:
int iterdepth;
size_t idx;
};
template<typename _Tp, int chs> inline
NAryMatIterator<_Tp, chs>::NAryMatIterator()
: arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0)
{
}
template<typename _Tp, int chs>
NAryMatIterator<_Tp, chs>::NAryMatIterator(const Mat_<_Tp, chs>** _arrays, Mat_<_Tp, chs>* _planes, int _narrays)
: arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0)
{
init(_arrays, _planes, 0, _narrays);
}
template<typename _Tp, int chs>
NAryMatIterator<_Tp, chs>::NAryMatIterator(const Mat_<_Tp, chs>** _arrays, uchar** _ptrs, int _narrays)
: arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0)
{
init(_arrays, 0, _ptrs, _narrays);
}
template<typename _Tp, int chs>
void NAryMatIterator<_Tp, chs>::init(const Mat_<_Tp, chs>** _arrays, Mat_<_Tp, chs>* _planes, uchar** _ptrs, int _narrays)
{
fprintf(stderr, "NAryMatIterator no impl\n");
FBC_Error("null"); // TODO
/*FBC_Assert(_arrays && (_ptrs || _planes));
int i, j, d1 = 0, i0 = -1, d = -1;
arrays = _arrays;
ptrs = _ptrs;
planes = _planes;
narrays = _narrays;
nplanes = 0;
size = 0;
if (narrays < 0) {
for (i = 0; _arrays[i] != 0; i++)
;
narrays = i;
FBC_Assert(narrays <= 1000);
}
iterdepth = 0;
for (i = 0; i < narrays; i++) {
FBC_Assert(arrays[i] != 0);
const Mat_<_Tp, chs>& A = *arrays[i];
if (ptrs)
ptrs[i] = A.data;
if (!A.data)
continue;
if (i0 < 0) {
i0 = i;
d = 2; // A.dims;
// find the first dimensionality which is different from 1;
// in any of the arrays the first "d1" step do not affect the continuity
for (d1 = 0; d1 < d; d1++)
if (A.size[d1] > 1)
break;
} else {
FBC_Assert(A.size == arrays[i0]->size);
}
if (!A.isContinuous()) {
FBC_Assert(A.step[d - 1] == A.elemSize());
for (j = d - 1; j > d1; j--)
if (A.step[j] * A.size[j] < A.step[j - 1])
break;
iterdepth = std::max(iterdepth, j);
}
}
if (i0 >= 0) {
size = arrays[i0]->size[d - 1];
for (j = d - 1; j > iterdepth; j--) {
int64 total1 = (int64)size*arrays[i0]->size[j - 1];
if (total1 != (int)total1)
break;
size = (int)total1;
}
iterdepth = j;
if (iterdepth == d1)
iterdepth = 0;
nplanes = 1;
for (j = iterdepth - 1; j >= 0; j--)
nplanes *= arrays[i0]->size[j];
} else {
iterdepth = 0;
}
idx = 0;
if (!planes)
return;
for (i = 0; i < narrays; i++) {
FBC_Assert(arrays[i] != 0);
const Mat_<_Tp, chs>& A = *arrays[i];
if (!A.data) {
planes[i] = Mat_<_Tp, chs>();
continue;
}
planes[i] = Mat_<_Tp, chs>(1, (int)size, A.data);
}*/
}
template<typename _Tp, int chs>
NAryMatIterator<_Tp, chs>& NAryMatIterator<_Tp, chs>::operator ++()
{
fprintf(stderr, "NAryMatIterator no impl\n");
/*if (idx >= nplanes - 1)
return *this;
++idx;
if (iterdepth == 1) {
if (ptrs) {
for (int i = 0; i < narrays; i++) {
if (!ptrs[i])
continue;
ptrs[i] = arrays[i]->data + arrays[i]->step[0] * idx;
}
}
if (planes) {
for (int i = 0; i < narrays; i++) {
if (!planes[i].data)
continue;
planes[i].data = arrays[i]->data + arrays[i]->step[0] * idx;
}
}
} else {
for (int i = 0; i < narrays; i++) {
const Mat_<_Tp, chs>& A = *arrays[i];
if (!A.data)
continue;
int _idx = (int)idx;
uchar* data = A.data;
for (int j = iterdepth - 1; j >= 0 && _idx > 0; j--) {
int szi = A.size[j], t = _idx / szi;
data += (_idx - t * szi)*A.step[j];
_idx = t;
}
if (ptrs)
ptrs[i] = data;
if (planes)
planes[i].data = data;
}
}*/
return *this;
}
template<typename _Tp, int chs>
NAryMatIterator<_Tp, chs> NAryMatIterator<_Tp, chs>::operator ++(int)
{
NAryMatIterator<_Tp, chs> it = *this;
++*this;
return it;
}
} // namespace yt_tinycv
#endif // FBC_CV_CORE_NARY_MAT_ITERATOR_HPP_

View File

@@ -0,0 +1,285 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_BASE_HPP_
#define FBC_CV_CORE_BASE_HPP_
// reference: include/opencv2/core/base.hpp
#ifndef __cplusplus
#error base.hpp header must be compiled as C++
#endif
#include <assert.h>
#include <algorithm>
#include <cmath>
#include "fbcdef.hpp"
#include "interface.hpp"
namespace yt_tinycv {
#define FBC_StaticAssert(condition, reason) static_assert((condition), reason " " #condition)
#define FBC_Assert(expr) assert(expr)
#define FBC_Error(msg) \
fprintf(stderr, "Error: "#msg", file: %s, func: %s, line: %d \n", __FILE__, __FUNCTION__, __LINE__); \
assert(0);
template<typename _Tp, typename _AccTp> static inline
_AccTp normL2Sqr(const _Tp* a, int n)
{
_AccTp s = 0;
int i = 0;
for (; i <= n - 4; i += 4) {
_AccTp v0 = a[i], v1 = a[i + 1], v2 = a[i + 2], v3 = a[i + 3];
s += v0*v0 + v1*v1 + v2*v2 + v3*v3;
}
for (; i < n; i++) {
_AccTp v = a[i];
s += v*v;
}
return s;
}
template<typename _Tp, typename _AccTp> static inline
_AccTp normL1(const _Tp* a, int n)
{
_AccTp s = 0;
int i = 0;
for (; i <= n - 4; i += 4) {
s += (_AccTp)cv_abs(a[i]) + (_AccTp)cv_abs(a[i + 1]) +
(_AccTp)cv_abs(a[i + 2]) + (_AccTp)cv_abs(a[i + 3]);
}
for (; i < n; i++)
s += cv_abs(a[i]);
return s;
}
template<typename _Tp, typename _AccTp> static inline
_AccTp normInf(const _Tp* a, int n)
{
_AccTp s = 0;
for (int i = 0; i < n; i++)
s = std::max(s, (_AccTp)cv_abs(a[i]));
return s;
}
template<typename _Tp, typename _AccTp> static inline
_AccTp normL2Sqr(const _Tp* a, const _Tp* b, int n)
{
_AccTp s = 0;
int i = 0;
for (; i <= n - 4; i += 4) {
_AccTp v0 = _AccTp(a[i] - b[i]), v1 = _AccTp(a[i + 1] - b[i + 1]), v2 = _AccTp(a[i + 2] - b[i + 2]), v3 = _AccTp(a[i + 3] - b[i + 3]);
s += v0*v0 + v1*v1 + v2*v2 + v3*v3;
}
for (; i < n; i++) {
_AccTp v = _AccTp(a[i] - b[i]);
s += v*v;
}
return s;
}
static inline float normL2Sqr(const float* a, const float* b, int n)
{
float s = 0.f;
for (int i = 0; i < n; i++) {
float v = a[i] - b[i];
s += v*v;
}
return s;
}
template<typename _Tp, typename _AccTp> static inline
_AccTp normL1(const _Tp* a, const _Tp* b, int n)
{
_AccTp s = 0;
int i = 0;
for (; i <= n - 4; i += 4) {
_AccTp v0 = _AccTp(a[i] - b[i]), v1 = _AccTp(a[i + 1] - b[i + 1]), v2 = _AccTp(a[i + 2] - b[i + 2]), v3 = _AccTp(a[i + 3] - b[i + 3]);
s += std::abs(v0) + std::abs(v1) + std::abs(v2) + std::abs(v3);
}
for (; i < n; i++) {
_AccTp v = _AccTp(a[i] - b[i]);
s += std::abs(v);
}
return s;
}
inline float normL1(const float* a, const float* b, int n)
{
float s = 0.f;
for (int i = 0; i < n; i++) {
s += std::abs(a[i] - b[i]);
}
return s;
}
inline int normL1(const uchar* a, const uchar* b, int n)
{
int s = 0;
for (int i = 0; i < n; i++) {
s += std::abs(a[i] - b[i]);
}
return s;
}
template<typename _Tp, typename _AccTp> static inline
_AccTp normInf(const _Tp* a, const _Tp* b, int n)
{
_AccTp s = 0;
for (int i = 0; i < n; i++) {
_AccTp v0 = a[i] - b[i];
s = std::max(s, std::abs(v0));
}
return s;
}
//! comparison types
enum CmpTypes {
CMP_EQ = 0, //!< src1 is equal to src2.
CMP_GT = 1, //!< src1 is greater than src2.
CMP_GE = 2, //!< src1 is greater than or equal to src2.
CMP_LT = 3, //!< src1 is less than src2.
CMP_LE = 4, //!< src1 is less than or equal to src2.
CMP_NE = 5 //!< src1 is unequal to src2.
};
//! matrix decomposition types
enum DecompTypes {
/** Gaussian elimination with the optimal pivot element chosen. */
DECOMP_LU = 0,
/** singular value decomposition (SVD) method; the system can be over-defined and/or the matrix
src1 can be singular */
DECOMP_SVD = 1,
/** eigenvalue decomposition; the matrix src1 must be symmetrical */
DECOMP_EIG = 2,
/** Cholesky \f$LL^T\f$ factorization; the matrix src1 must be symmetrical and positively
defined */
DECOMP_CHOLESKY = 3,
/** QR factorization; the system can be over-defined and/or the matrix src1 can be singular */
DECOMP_QR = 4,
/** while all the previous flags are mutually exclusive, this flag can be used together with
any of the previous; it means that the normal equations
\f$\texttt{src1}^T\cdot\texttt{src1}\cdot\texttt{dst}=\texttt{src1}^T\texttt{src2}\f$ are
solved instead of the original system
\f$\texttt{src1}\cdot\texttt{dst}=\texttt{src2}\f$ */
DECOMP_NORMAL = 16
};
/** norm types
- For one array:
\f[norm = \forkthree{\|\texttt{src1}\|_{L_{\infty}} = \max _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM_INF}\) }
{ \| \texttt{src1} \| _{L_1} = \sum _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM_L1}\) }
{ \| \texttt{src1} \| _{L_2} = \sqrt{\sum_I \texttt{src1}(I)^2} }{if \(\texttt{normType} = \texttt{NORM_L2}\) }\f]
- Absolute norm for two arrays
\f[norm = \forkthree{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} = \max _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM_INF}\) }
{ \| \texttt{src1} - \texttt{src2} \| _{L_1} = \sum _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM_L1}\) }
{ \| \texttt{src1} - \texttt{src2} \| _{L_2} = \sqrt{\sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2} }{if \(\texttt{normType} = \texttt{NORM_L2}\) }\f]
- Relative norm for two arrays
\f[norm = \forkthree{\frac{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} }{\|\texttt{src2}\|_{L_{\infty}} }}{if \(\texttt{normType} = \texttt{NORM_RELATIVE_INF}\) }
{ \frac{\|\texttt{src1}-\texttt{src2}\|_{L_1} }{\|\texttt{src2}\|_{L_1}} }{if \(\texttt{normType} = \texttt{NORM_RELATIVE_L1}\) }
{ \frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}} }{if \(\texttt{normType} = \texttt{NORM_RELATIVE_L2}\) }\f]
As example for one array consider the function \f$r(x)= \begin{pmatrix} x \\ 1-x \end{pmatrix}, x \in [-1;1]\f$.
The \f$ L_{1}, L_{2} \f$ and \f$ L_{\infty} \f$ norm for the sample value \f$r(-1) = \begin{pmatrix} -1 \\ 2 \end{pmatrix}\f$
is calculated as follows
\f{align*}
\| r(-1) \|_{L_1} &= |-1| + |2| = 3 \\
\| r(-1) \|_{L_2} &= \sqrt{(-1)^{2} + (2)^{2}} = \sqrt{5} \\
\| r(-1) \|_{L_\infty} &= \max(|-1|,|2|) = 2
\f}
and for \f$r(0.5) = \begin{pmatrix} 0.5 \\ 0.5 \end{pmatrix}\f$ the calculation is
\f{align*}
\| r(0.5) \|_{L_1} &= |0.5| + |0.5| = 1 \\
\| r(0.5) \|_{L_2} &= \sqrt{(0.5)^{2} + (0.5)^{2}} = \sqrt{0.5} \\
\| r(0.5) \|_{L_\infty} &= \max(|0.5|,|0.5|) = 0.5.
\f}
The following graphic shows all values for the three norm functions \f$\| r(x) \|_{L_1}, \| r(x) \|_{L_2}\f$ and \f$\| r(x) \|_{L_\infty}\f$.
It is notable that the \f$ L_{1} \f$ norm forms the upper and the \f$ L_{\infty} \f$ norm forms the lower border for the example function \f$ r(x) \f$.
![Graphs for the different norm functions from the above example](pics/NormTypes_OneArray_1-2-INF.png)
*/
enum NormTypes {
NORM_INF = 1,
NORM_L1 = 2,
NORM_L2 = 4,
NORM_L2SQR = 5,
NORM_HAMMING = 6,
NORM_HAMMING2 = 7,
NORM_TYPE_MASK = 7,
NORM_RELATIVE = 8, // flag
NORM_MINMAX = 32 // flag
};
//! Various border types, image boundaries are denoted with `|`
enum BorderTypes {
BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i`
BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh`
BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb`
BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg`
BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba`
BORDER_TRANSPARENT = 5, //!< `uvwxyz|absdefgh|ijklmno`
BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_ISOLATED = 16 //!< do not look outside of ROI
};
enum DftFlags {
/** performs an inverse 1D or 2D transform instead of the default forward transform. */
DFT_INVERSE = 1,
/** scales the result: divide it by the number of array elements. Normally, it is
combined with DFT_INVERSE. */
DFT_SCALE = 2,
/** performs a forward or inverse transform of every individual row of the input
matrix; this flag enables you to transform multiple vectors simultaneously and can be used to
decrease the overhead (which is sometimes several times larger than the processing itself) to
perform 3D and higher-dimensional transformations and so forth.*/
DFT_ROWS = 4,
/** performs a forward transformation of 1D or 2D real array; the result,
though being a complex array, has complex-conjugate symmetry (*CCS*, see the function
description below for details), and such an array can be packed into a real array of the same
size as input, which is the fastest option and which is what the function does by default;
however, you may wish to get a full complex array (for simpler spectrum analysis, and so on) -
pass the flag to enable the function to produce a full-size complex output array. */
DFT_COMPLEX_OUTPUT = 16,
/** performs an inverse transformation of a 1D or 2D complex array; the
result is normally a complex array of the same size, however, if the input array has
conjugate-complex symmetry (for example, it is a result of forward transformation with
DFT_COMPLEX_OUTPUT flag), the output is a real array; while the function itself does not
check whether the input is symmetrical or not, you can pass the flag and then the function
will assume the symmetry and produce the real output array (note that when the input is packed
into a real array and inverse transformation is executed, the function treats the input as a
packed complex-conjugate symmetrical array, and the output will also be a real array). */
DFT_REAL_OUTPUT = 32,
/** performs an inverse 1D or 2D transform instead of the default forward transform. */
DCT_INVERSE = DFT_INVERSE,
/** performs a forward or inverse transform of every individual row of the input
matrix. This flag enables you to transform multiple vectors simultaneously and can be used to
decrease the overhead (which is sometimes several times larger than the processing itself) to
perform 3D and higher-dimensional transforms and so forth.*/
DCT_ROWS = DFT_ROWS
};
} //yt_tinycv
#endif //FBC_CV_CORE_BASE_HPP_

View File

@@ -0,0 +1,313 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_CORE_HPP_
#define FBC_CV_CORE_CORE_HPP_
/* reference: include/opencv2/core/core_c.h
include/opencv2/core.hpp
modules/core/src/stat.cpp
modules/core/include/opencv2/core/private.hpp
modules/core/src/matrix.cpp
modules/core/src/arithm.cpp
*/
#ifndef __cplusplus
#error core.hpp header must be compiled as C++
#endif
#include <exception>
#include <string>
#include "fbcdef.hpp"
#include "mat.hpp"
namespace yt_tinycv {
// NormFlags
#define FBC_C 1
#define FBC_L1 2
#define FBC_L2 4
#define FBC_NORM_MASK 7
#define FBC_RELATIVE 8
#define FBC_DIFF 16
#define FBC_MINMAX 32
#define FBC_DIFF_C (FBC_DIFF | FBC_C)
#define FBC_DIFF_L1 (FBC_DIFF | FBC_L1)
#define FBC_DIFF_L2 (FBC_DIFF | FBC_L2)
#define FBC_RELATIVE_C (FBC_RELATIVE | FBC_C)
#define FBC_RELATIVE_L1 (FBC_RELATIVE | FBC_L1)
#define FBC_RELATIVE_L2 (FBC_RELATIVE | FBC_L2)
// Discrete Linear Transforms and Related Functions
#define FBC_DXT_SCALE 2 // divide result by size of array
// Fast cubic root calculation
FBC_EXPORTS float fbcCbrt(float value);
template<typename dump>
static inline void* fbcAlignPtr(const void* ptr, int align = 32)
{
FBC_Assert((align & (align - 1)) == 0);
return (void*)(((size_t)ptr + align - 1) & ~(size_t)(align - 1));
}
template<typename dump>
static inline int fbcAlign(int size, int align)
{
FBC_Assert((align & (align - 1)) == 0 && size < INT_MAX);
return (size + align - 1) & -align;
}
// Computes the source location of an extrapolated pixel
/* Various border types, image boundaries are denoted with '|'
* BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh
* BORDER_REFLECT: fedcba|abcdefgh|hgfedcb
* BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba
* BORDER_WRAP: cdefgh|abcdefgh|abcdefg
* BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified 'i'
*/
template<typename _Tp>
int borderInterpolate(int p, int len, int borderType)
{
if ((unsigned)p < (unsigned)len) {
;
} else if (borderType == BORDER_REPLICATE) {
p = p < 0 ? 0 : len - 1;
} else if (borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101) {
int delta = borderType == BORDER_REFLECT_101;
if (len == 1)
return 0;
do {
if (p < 0)
p = -p - 1 + delta;
else
p = len - 1 - (p - len) - delta;
} while ((unsigned)p >= (unsigned)len);
} else if (borderType == BORDER_WRAP) {
FBC_Assert(len > 0);
if (p < 0)
p -= ((p - len + 1) / len)*len;
if (p >= len)
p %= len;
} else if (borderType == BORDER_CONSTANT) {
p = -1;
} else {
FBC_Error("Unknown/unsupported border type");
}
return p;
}
// Transposes a matrix
// \f[\texttt{dst} (i,j) = \texttt{src} (j,i)\f]
template<typename _Tp, int chs>
int transpose(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst)
{
if (src.empty()) {
dst.release();
return -1;
}
// handle the case of single-column/single-row matrices, stored in STL vectors
if (src.rows != dst.cols || src.cols != dst.rows) {
FBC_Assert(src.size() == dst.size() && (src.cols == 1 || src.rows == 1));
src.copyTo(dst);
return 0;
}
if (dst.data == src.data) {
FBC_Assert(0); // TODO
} else {
Size sz = src.size();
int i = 0, j, m = sz.width, n = sz.height;
int sstep = src.step;
int dstep = dst.step;
for (; i <= m - 4; i += 4) {
_Tp* d0 = (_Tp*)(dst.data + dstep*i);
_Tp* d1 = (_Tp*)(dst.data + dstep*(i + 1));
_Tp* d2 = (_Tp*)(dst.data + dstep*(i + 2));
_Tp* d3 = (_Tp*)(dst.data + dstep*(i + 3));
for (j = 0; j <= n - 4; j += 4) {
const _Tp* s0 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*j);
const _Tp* s1 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 1));
const _Tp* s2 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 2));
const _Tp* s3 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 3));
d0[j] = s0[0]; d0[j + 1] = s1[0]; d0[j + 2] = s2[0]; d0[j + 3] = s3[0];
d1[j] = s0[1]; d1[j + 1] = s1[1]; d1[j + 2] = s2[1]; d1[j + 3] = s3[1];
d2[j] = s0[2]; d2[j + 1] = s1[2]; d2[j + 2] = s2[2]; d2[j + 3] = s3[2];
d3[j] = s0[3]; d3[j + 1] = s1[3]; d3[j + 2] = s2[3]; d3[j + 3] = s3[3];
}
for (; j < n; j++) {
const _Tp* s0 = (const _Tp*)(src.data + i*sizeof(_Tp) + j*sstep);
d0[j] = s0[0]; d1[j] = s0[1]; d2[j] = s0[2]; d3[j] = s0[3];
}
}
for (; i < m; i++) {
_Tp* d0 = (_Tp*)(dst.data + dstep*i);
j = 0;
for (; j <= n - 4; j += 4) {
const _Tp* s0 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*j);
const _Tp* s1 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 1));
const _Tp* s2 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 2));
const _Tp* s3 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 3));
d0[j] = s0[0]; d0[j + 1] = s1[0]; d0[j + 2] = s2[0]; d0[j + 3] = s3[0];
}
for (; j < n; j++) {
const _Tp* s0 = (const _Tp*)(src.data + i*sizeof(_Tp) + j*sstep);
d0[j] = s0[0];
}
}
}
return 0;
}
// Counts non-zero array elements
// \f[\sum _{ I: \; \texttt{ src } (I) \ne0 } 1\f]
template<typename _Tp, int chs>
int countNonZero(const Mat_<_Tp, chs>& src)
{
FBC_Assert(chs == 1);
int len = src.rows * src.cols;
const _Tp* p = (_Tp*)src.data;
int nz = 0;
for (int i = 0; i < len; i++) {
nz += (p[i] != 0);
}
return nz;
}
template<typename _Tp, int chs>
void scalarToRawData(const yt_tinycv::Scalar& s, void* _buf, int unroll_to = 0)
{
FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() || typeid(float).name() == typeid(_Tp).name()); // uchar || float
int i, cn = chs;
FBC_Assert(chs <= 4);
int depth = sizeof(_Tp);
switch (depth) {
case 1: {
uchar* buf = (uchar*)_buf;
for (i = 0; i < cn; i++)
buf[i] = saturate_cast<uchar>(s.val[i]);
for (; i < unroll_to; i++)
buf[i] = buf[i - cn];
}
break;
case 4: {
float* buf = (float*)_buf;
for (i = 0; i < cn; i++)
buf[i] = saturate_cast<float>(s.val[i]);
for (; i < unroll_to; i++)
buf[i] = buf[i - cn];
}
break;
default:
FBC_Error("UnsupportedFormat");
}
}
// calculates the per - element bit - wise logical conjunction
// \f[\texttt{dst} (I) = \texttt{src1} (I) \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f]
// mask optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed
template<typename _Tp, int chs>
int bitwise_and(const Mat_<_Tp, chs>& src1, const Mat_<_Tp, chs>& src2, Mat_<_Tp, chs>& dst, const Mat_<uchar, 1>& mask = Mat_<uchar, 1>())
{
FBC_Assert(src1.rows == src2.rows && src1.cols == src2.cols);
if (dst.empty()) {
dst = Mat_<_Tp, chs>(src1.rows, src1.cols);
} else {
FBC_Assert(src1.rows == dst.rows && src1.cols == dst.cols);
}
if (!mask.empty()) {
FBC_Assert(src1.rows == mask.rows && src1.cols == mask.cols);
}
int bytePerRow = src1.cols * chs * sizeof(_Tp);
int bypePerPixel = chs * sizeof(_Tp);
for (int y = 0; y < src1.rows; y++) {
const uchar* pSrc1 = src1.ptr(y);
const uchar* pSrc2 = src2.ptr(y);
uchar* pDst = dst.ptr(y);
const uchar* pMask = NULL;
if (!mask.empty()) {
pMask = mask.ptr(y);
for (int x = 0; x < src1.cols; x++) {
if (pMask[x] == 1) {
int addr = x * bypePerPixel;
for (int t = 0; t < bypePerPixel; t++) {
pDst[addr + t] = pSrc1[addr + t] & pSrc2[addr + t];
}
}
}
} else {
for (int x = 0; x < bytePerRow; x++) {
pDst[x] = pSrc1[x] & pSrc2[x];
}
}
}
return 0;
}
// Inverts every bit of an array
// \f[\texttt{dst} (I) = \neg \texttt{src} (I)\f]
// mask optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed
template<typename _Tp, int chs>
int bitwise_not(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, const Mat_<uchar, 1>& mask = Mat_<uchar, 1>())
{
if (dst.empty()) {
dst = Mat_<_Tp, chs>(src.rows, src.cols);
} else {
FBC_Assert(src.rows == dst.rows && src.cols == dst.cols);
}
if (!mask.empty()) {
FBC_Assert(src.rows == mask.rows && src.cols == mask.cols);
}
int bytePerRow = src.cols * chs * sizeof(_Tp);
int bypePerPixel = chs * sizeof(_Tp);
for (int y = 0; y < src.rows; y++) {
const uchar* pSrc = src.ptr(y);
uchar* pDst = dst.ptr(y);
const uchar* pMask = NULL;
if (!mask.empty()) {
pMask = mask.ptr(y);
for (int x = 0; x < src.cols; x++) {
if (pMask[x] == 1) {
int addr = x * bypePerPixel;
for (int t = 0; t < bypePerPixel; t++) {
pDst[addr + t] = ~pSrc[addr + t];
}
}
}
} else {
for (int x = 0; x < bytePerRow; x++) {
pDst[x] = ~pSrc[x];
}
}
}
return 0;
}
} // namespace yt_tinycv
#endif // FBC_CV_CORE_CORE_HPP_

View File

@@ -0,0 +1,543 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
// from: https://github.com/fengbingchun/OpenCV_Test/blob/master/src/fbc_cv/include/cvtColor.hpp
// commitID: 7c0eccf85e31c456256cc4c87d4ba752a56a18dc
#ifndef FBC_CV_CVTCOLOR_HPP_
#define FBC_CV_CVTCOLOR_HPP_
/* reference: include/opencv2/imgproc.hpp
imgproc/src/color.cpp
*/
#include <typeinfo>
#include "mat.hpp"
#include "saturate.hpp"
#include "imgproc.hpp"
#include "core.hpp"
#ifdef __ARM_NEON__
#include "arm_neon.h"
#include <sys/time.h>
#endif
namespace yt_tinycv {
#define FBC_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n))
#ifdef __ARM_NEON__
// neon intrinsic
static void NeonCvtColorRGBA2BGR(unsigned char *rgba, unsigned char *bgr, int rows, int cols) {
int len_color = rows * cols;
int num8x16 = len_color / 16;
int num8len = num8x16 * 16;
uint8x16x4_t intlv_rgba;
uint8x16x3_t intlv_bgr;
for (int i=0; i < num8x16; i++) {
intlv_rgba = vld4q_u8(rgba);
intlv_bgr.val[0] = intlv_rgba.val[2];
intlv_bgr.val[1] = intlv_rgba.val[1];
intlv_bgr.val[2] = intlv_rgba.val[0];
vst3q_u8(bgr, intlv_bgr);
rgba += 64;
bgr += 48;
}
for (; num8len < len_color; num8len++) {
bgr[0] = rgba[2];
bgr[1] = rgba[1];
bgr[2] = rgba[0];
rgba += 4;
bgr += 3;
}
}
static void NeonCvtColorRGBA2RGB(unsigned char *rgba, unsigned char *bgr, int rows, int cols) {
int len_color = rows * cols;
int num8x16 = len_color / 16;
int num8len = num8x16 * 16;
uint8x16x4_t intlv_rgba;
uint8x16x3_t intlv_bgr;
for (int i=0; i < num8x16; i++) {
intlv_rgba = vld4q_u8(rgba);
intlv_bgr.val[0] = intlv_rgba.val[0];
intlv_bgr.val[1] = intlv_rgba.val[1];
intlv_bgr.val[2] = intlv_rgba.val[2];
vst3q_u8(bgr, intlv_bgr);
rgba += 64;
bgr += 48;
}
for (; num8len < len_color; num8len++) {
bgr[0] = rgba[0];
bgr[1] = rgba[1];
bgr[2] = rgba[2];
rgba += 4;
bgr += 3;
}
}
static void NeonCvtColorRGB2BGR(unsigned char *rgb, unsigned char *bgr, int rows, int cols) {
int len_color = rows * cols;
int num8x16 = len_color / 16;
int num8len = num8x16 * 16;
uint8x16x3_t intlv_rgb;
uint8x16x3_t intlv_bgr;
for (int i=0; i < num8x16; i++) {
intlv_rgb = vld3q_u8(rgb);
intlv_bgr.val[0] = intlv_rgb.val[2];
intlv_bgr.val[1] = intlv_rgb.val[1];
intlv_bgr.val[2] = intlv_rgb.val[0];
vst3q_u8(bgr, intlv_bgr);
rgb += 48;
bgr += 48;
}
for (; num8len < len_color; num8len++) {
bgr[0] = rgb[2];
bgr[1] = rgb[1];
bgr[2] = rgb[0];
rgb += 3;
bgr += 3;
}
}
#endif
template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2RGB(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx);
template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2Gray(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx);
template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2YCrCb(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx, const float* coeffs_f, const int* coeffs_i);
template<typename _Tp, int chs1, int chs2, int bIdx, int uIdx> static void cvtRGBtoYUV420p(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst);
#undef R2Y
#undef G2Y
#undef B2Y
enum {
yuv_shift = 14,
xyz_shift = 12,
R2Y = 4899,
G2Y = 9617,
B2Y = 1868,
BLOCK_SIZE = 256
};
// Converts an image from one color space to another
// support type: uchar/ushort/float
template<typename _Tp, int chs1, int chs2>
int cvtColor(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int code)
{
FBC_Assert(src.cols > 0 && src.rows > 0 && dst.cols > 0 && dst.rows > 0);
FBC_Assert(src.cols == dst.cols);
FBC_Assert(src.data != NULL && dst.data != NULL);
FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() ||
typeid(ushort).name() == typeid(_Tp).name() ||
typeid(float).name() == typeid(_Tp).name());
FBC_Assert((sizeof(_Tp) == 1) || sizeof(_Tp) == 2 || sizeof(_Tp) == 4); // uchar || ushort || float
int scn = src.channels;
int dcn = dst.channels; // number of channels in the destination image
Size sz = src.size();
Size dz = dst.size();
int bidx;
#ifdef __ARM_NEON__
if (CV_RGBA2BGR == code || CV_BGRA2RGB == code) {
// timeval tv_begin, tv_end;
// gettimeofday(&tv_begin, NULL);
NeonCvtColorRGBA2BGR(src.data, dst.data, dst.rows, dst.cols);
// gettimeofday(&tv_end, NULL);
// float elapsed = ((tv_end.tv_sec - tv_begin.tv_sec) * 1000000.0f + tv_end.tv_usec - tv_begin.tv_usec) / 1000.0f;
// printf("lgy neon NeonCvtColorRGBA2BGR code : %d, %f ms\n", code, elapsed);
return 0;
}
if (CV_RGBA2RGB == code || CV_BGRA2BGR == code) {
NeonCvtColorRGBA2RGB(src.data, dst.data, dst.rows, dst.cols);
return 0;
}
if (CV_BGR2RGB == code || CV_RGB2BGR == code) {
NeonCvtColorRGB2BGR(src.data, dst.data, dst.rows, dst.cols);
return 0;
}
#endif
switch (code) {
case CV_BGR2BGRA: case CV_RGB2BGRA: case CV_BGRA2BGR:
case CV_RGBA2BGR: case CV_RGB2BGR: case CV_BGRA2RGBA: {
FBC_Assert(scn == 3 || scn == 4);
dcn = code == CV_BGR2BGRA || code == CV_RGB2BGRA || code == CV_BGRA2RGBA ? 4 : 3;
FBC_Assert(dst.channels == dcn);
bidx = code == CV_BGR2BGRA || code == CV_BGRA2BGR ? 0 : 2;
CvtColorLoop_RGB2RGB(src, dst, bidx); // uchar/ushort/float
break;
}
case CV_BGR2GRAY: case CV_BGRA2GRAY: case CV_RGB2GRAY: case CV_RGBA2GRAY: {
FBC_Assert(scn == 3 || scn == 4);
FBC_Assert(dst.channels == 1);
bidx = code == CV_BGR2GRAY || code == CV_BGRA2GRAY ? 0 : 2;
CvtColorLoop_RGB2Gray(src, dst, bidx);
break;
}
case CV_BGR2YUV: case CV_RGB2YUV:{
FBC_Assert(scn == 3 || scn == 4);
bidx = code == CV_BGR2YUV ? 0 : 2;
static const float yuv_f[] = { 0.114f, 0.587f, 0.299f, 0.492f, 0.877f };
static const int yuv_i[] = { B2Y, G2Y, R2Y, 8061, 14369 };
CvtColorLoop_RGB2YCrCb(src, dst, bidx, yuv_f, yuv_i);
break;
}
case CV_RGB2YUV_YV12: case CV_BGR2YUV_YV12: case CV_RGBA2YUV_YV12: case CV_BGRA2YUV_YV12:
case CV_RGB2YUV_IYUV: case CV_BGR2YUV_IYUV: case CV_RGBA2YUV_IYUV: case CV_BGRA2YUV_IYUV: {
const int bIdx = (code == CV_BGR2YUV_IYUV || code == CV_BGRA2YUV_IYUV || code == CV_BGR2YUV_YV12 || code == CV_BGRA2YUV_YV12) ? 0 : 2;
const int uIdx = (code == CV_BGR2YUV_IYUV || code == CV_BGRA2YUV_IYUV || code == CV_RGB2YUV_IYUV || code == CV_RGBA2YUV_IYUV) ? 1 : 2;
FBC_Assert(scn == 3 || scn == 4);
FBC_Assert(sizeof(_Tp) == 1);
FBC_Assert(dcn == 1);
FBC_Assert(sz.width % 2 == 0 && sz.height % 2 == 0);
//Size dstSz(sz.width, sz.height / 2 * 3);
FBC_Assert((dz.width == sz.width) && (sz.height / 2 * 3 == dz.height));
switch (bIdx + uIdx * 10) {
case 10: cvtRGBtoYUV420p<_Tp, chs1, chs2, 0, 1>(src, dst); break;
case 12: cvtRGBtoYUV420p<_Tp, chs1, chs2, 2, 1>(src, dst); break;
case 20: cvtRGBtoYUV420p<_Tp, chs1, chs2, 0, 2>(src, dst); break;
case 22: cvtRGBtoYUV420p<_Tp, chs1, chs2, 2, 2>(src, dst); break;
default: FBC_Error("Unknown/unsupported color conversion code"); break;
};
break;
}
default:
FBC_Error("Unknown/unsupported color conversion code");
}
return 0;
}
// computes cubic spline coefficients for a function: (xi=i, yi=f[i]), i=0..n
template<typename _Tp> static void splineBuild(const _Tp* f, int n, _Tp* tab)
{
_Tp cn = 0;
int i;
tab[0] = tab[1] = (_Tp)0;
for (i = 1; i < n - 1; i++) {
_Tp t = 3 * (f[i + 1] - 2 * f[i] + f[i - 1]);
_Tp l = 1 / (4 - tab[(i - 1) * 4]);
tab[i * 4] = l; tab[i * 4 + 1] = (t - tab[(i - 1) * 4 + 1])*l;
}
for (i = n - 1; i >= 0; i--) {
_Tp c = tab[i * 4 + 1] - tab[i * 4] * cn;
_Tp b = f[i + 1] - f[i] - (cn + c * 2)*(_Tp)0.3333333333333333;
_Tp d = (cn - c)*(_Tp)0.3333333333333333;
tab[i * 4] = f[i]; tab[i * 4 + 1] = b;
tab[i * 4 + 2] = c; tab[i * 4 + 3] = d;
cn = c;
}
}
// interpolates value of a function at x, 0 <= x <= n using a cubic spline.
template<typename _Tp> static inline _Tp splineInterpolate(_Tp x, const _Tp* tab, int n)
{
// don't touch this function without urgent need - some versions of gcc fail to inline it correctly
int ix = std::min(std::max(int(x), 0), n - 1);
x -= ix;
tab += ix * 4;
return ((tab[3] * x + tab[2])*x + tab[1])*x + tab[0];
}
template<typename _Tp> struct ColorChannel
{
typedef float worktype_f;
static _Tp max() { return std::numeric_limits<_Tp>::max(); }
static _Tp half() { return (_Tp)(max() / 2 + 1); }
};
template<> struct ColorChannel<float>
{
typedef float worktype_f;
static float max() { return 1.f; }
static float half() { return 0.5f; }
};
template<typename _Tp> struct RGB2Gray
{
typedef _Tp channel_type;
RGB2Gray(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn)
{
static const float coeffs0[] = { 0.299f, 0.587f, 0.114f };
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 3 * sizeof(coeffs[0]));
if (blueIdx == 0)
std::swap(coeffs[0], coeffs[2]);
}
void operator()(const _Tp* src, _Tp* dst, int n) const
{
int scn = srccn;
float cb = coeffs[0], cg = coeffs[1], cr = coeffs[2];
for (int i = 0; i < n; i++, src += scn)
dst[i] = saturate_cast<_Tp>(src[0] * cb + src[1] * cg + src[2] * cr);
}
int srccn;
float coeffs[3];
};
template<> struct RGB2Gray<uchar>
{
typedef uchar channel_type;
RGB2Gray(int _srccn, int blueIdx, const int* coeffs) : srccn(_srccn)
{
const int coeffs0[] = { R2Y, G2Y, B2Y };
if (!coeffs) coeffs = coeffs0;
int b = 0, g = 0, r = (1 << (yuv_shift - 1));
int db = coeffs[blueIdx ^ 2], dg = coeffs[1], dr = coeffs[blueIdx];
for (int i = 0; i < 256; i++, b += db, g += dg, r += dr) {
tab[i] = b;
tab[i + 256] = g;
tab[i + 512] = r;
}
}
void operator()(const uchar* src, uchar* dst, int n) const
{
int scn = srccn;
const int* _tab = tab;
for (int i = 0; i < n; i++, src += scn)
dst[i] = (uchar)((_tab[src[0]] + _tab[src[1] + 256] + _tab[src[2] + 512]) >> yuv_shift);
}
int srccn;
int tab[256 * 3];
};
template<> struct RGB2Gray<ushort>
{
typedef ushort channel_type;
RGB2Gray(int _srccn, int blueIdx, const int* _coeffs) : srccn(_srccn)
{
static const int coeffs0[] = { R2Y, G2Y, B2Y };
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 3 * sizeof(coeffs[0]));
if (blueIdx == 0)
std::swap(coeffs[0], coeffs[2]);
}
void operator()(const ushort* src, ushort* dst, int n) const
{
int scn = srccn, cb = coeffs[0], cg = coeffs[1], cr = coeffs[2];
for (int i = 0; i < n; i++, src += scn)
dst[i] = (ushort)FBC_DESCALE((unsigned)(src[0] * cb + src[1] * cg + src[2] * cr), yuv_shift);
}
int srccn;
int coeffs[3];
};
template<typename _Tp> struct RGB2YCrCb_f{
typedef _Tp channel_type;
RGB2YCrCb_f(int _srccn, int _blueIdx, const float* _coeffs) : srccn(_srccn), blueIdx(_blueIdx)
{
static const float coeffs0[] = { 0.299f, 0.587f, 0.114f, 0.713f, 0.564f };
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5 * sizeof(coeffs[0]));
if (blueIdx == 0) std::swap(coeffs[0], coeffs[2]);
}
void operator()(const _Tp* src, _Tp* dst, int n) const
{
int scn = srccn, bidx = blueIdx;
const _Tp delta = ColorChannel<_Tp>::half();
float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
n *= 3;
for (int i = 0; i < n; i += 3, src += scn) {
_Tp Y = saturate_cast<_Tp>(src[0] * C0 + src[1] * C1 + src[2] * C2);
_Tp Cr = saturate_cast<_Tp>((src[bidx ^ 2] - Y)*C3 + delta);
_Tp Cb = saturate_cast<_Tp>((src[bidx] - Y)*C4 + delta);
dst[i] = Y; dst[i + 1] = Cr; dst[i + 2] = Cb;
}
}
int srccn, blueIdx;
float coeffs[5];
};
template<typename _Tp> struct RGB2YCrCb_i{
typedef _Tp channel_type;
RGB2YCrCb_i(int _srccn, int _blueIdx, const int* _coeffs) : srccn(_srccn), blueIdx(_blueIdx)
{
static const int coeffs0[] = { R2Y, G2Y, B2Y, 11682, 9241 };
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5 * sizeof(coeffs[0]));
if (blueIdx == 0) std::swap(coeffs[0], coeffs[2]);
}
void operator()(const _Tp* src, _Tp* dst, int n) const
{
int scn = srccn, bidx = blueIdx;
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
int delta = ColorChannel<_Tp>::half()*(1 << yuv_shift);
n *= 3;
for (int i = 0; i < n; i += 3, src += scn) {
int Y = FBC_DESCALE(src[0] * C0 + src[1] * C1 + src[2] * C2, yuv_shift);
int Cr = FBC_DESCALE((src[bidx ^ 2] - Y)*C3 + delta, yuv_shift);
int Cb = FBC_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
dst[i] = saturate_cast<_Tp>(Y);
dst[i + 1] = saturate_cast<_Tp>(Cr);
dst[i + 2] = saturate_cast<_Tp>(Cb);
}
}
int srccn, blueIdx;
int coeffs[5];
};
const int ITUR_BT_601_CY = 1220542;
const int ITUR_BT_601_CUB = 2116026;
const int ITUR_BT_601_CUG = -409993;
const int ITUR_BT_601_CVG = -852492;
const int ITUR_BT_601_CVR = 1673527;
const int ITUR_BT_601_SHIFT = 20;
const int ITUR_BT_601_CRY = 269484;
const int ITUR_BT_601_CGY = 528482;
const int ITUR_BT_601_CBY = 102760;
const int ITUR_BT_601_CRU = -155188;
const int ITUR_BT_601_CGU = -305135;
const int ITUR_BT_601_CBU = 460324;
const int ITUR_BT_601_CGV = -385875;
const int ITUR_BT_601_CBV = -74448;
template<typename _Tp, int chs1, int chs2, int bIdx>
struct RGB888toYUV420pInvoker{
RGB888toYUV420pInvoker(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>* dst, const int uIdx)
: src_(src), dst_(dst), uIdx_(uIdx) { }
void operator()(const Range& rowRange) const
{
const int w = src_.cols;
const int h = src_.rows;
const int cn = src_.channels;
for (int i = rowRange.start; i < rowRange.end; i++) {
const uchar* row0 = src_.ptr(2 * i);
const uchar* row1 = src_.ptr(2 * i + 1);
uchar* y = (uchar*)dst_->ptr(2 * i);
uchar* u = (uchar*)dst_->ptr(h + i / 2) + (i % 2) * (w / 2);
uchar* v = (uchar*)dst_->ptr(h + (i + h / 2) / 2) + ((i + h / 2) % 2) * (w / 2);
if (uIdx_ == 2) std::swap(u, v);
for (int j = 0, k = 0; j < w * cn; j += 2 * cn, k++) {
int r00 = row0[2 - bIdx + j]; int g00 = row0[1 + j]; int b00 = row0[bIdx + j];
int r01 = row0[2 - bIdx + cn + j]; int g01 = row0[1 + cn + j]; int b01 = row0[bIdx + cn + j];
int r10 = row1[2 - bIdx + j]; int g10 = row1[1 + j]; int b10 = row1[bIdx + j];
int r11 = row1[2 - bIdx + cn + j]; int g11 = row1[1 + cn + j]; int b11 = row1[bIdx + cn + j];
const int shifted16 = (16 << ITUR_BT_601_SHIFT);
const int halfShift = (1 << (ITUR_BT_601_SHIFT - 1));
int y00 = ITUR_BT_601_CRY * r00 + ITUR_BT_601_CGY * g00 + ITUR_BT_601_CBY * b00 + halfShift + shifted16;
int y01 = ITUR_BT_601_CRY * r01 + ITUR_BT_601_CGY * g01 + ITUR_BT_601_CBY * b01 + halfShift + shifted16;
int y10 = ITUR_BT_601_CRY * r10 + ITUR_BT_601_CGY * g10 + ITUR_BT_601_CBY * b10 + halfShift + shifted16;
int y11 = ITUR_BT_601_CRY * r11 + ITUR_BT_601_CGY * g11 + ITUR_BT_601_CBY * b11 + halfShift + shifted16;
y[2 * k + 0] = saturate_cast<uchar>(y00 >> ITUR_BT_601_SHIFT);
y[2 * k + 1] = saturate_cast<uchar>(y01 >> ITUR_BT_601_SHIFT);
y[2 * k + dst_->step + 0] = saturate_cast<uchar>(y10 >> ITUR_BT_601_SHIFT);
y[2 * k + dst_->step + 1] = saturate_cast<uchar>(y11 >> ITUR_BT_601_SHIFT);
const int shifted128 = (128 << ITUR_BT_601_SHIFT);
int u00 = ITUR_BT_601_CRU * r00 + ITUR_BT_601_CGU * g00 + ITUR_BT_601_CBU * b00 + halfShift + shifted128;
int v00 = ITUR_BT_601_CBU * r00 + ITUR_BT_601_CGV * g00 + ITUR_BT_601_CBV * b00 + halfShift + shifted128;
u[k] = saturate_cast<uchar>(u00 >> ITUR_BT_601_SHIFT);
v[k] = saturate_cast<uchar>(v00 >> ITUR_BT_601_SHIFT);
}
}
}
private:
RGB888toYUV420pInvoker& operator=(const RGB888toYUV420pInvoker&);
const Mat_<_Tp, chs1>& src_;
Mat_<_Tp, chs2>* const dst_;
const int uIdx_;
};
template<typename _Tp, int chs1, int chs2>
static int CvtColorLoop_RGB2RGB(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx)
{
Range range(0, src.rows);
const uchar* yS_ = src.ptr(range.start);
uchar* yD_ = (uchar*)dst.ptr(range.start);
int scn = src.channels, dcn = dst.channels;
for (int h = range.start; h < range.end; ++h, yS_ += src.step, yD_ += dst.step) {
int n = src.cols;
const _Tp* yS = (const _Tp*)yS_;
_Tp* yD = (_Tp*)yD_;
if (dcn == 3) {
n *= 3;
for (int i = 0; i < n; i += 3, yS += scn) {
_Tp t0 = yS[bidx], t1 = yS[1], t2 = yS[bidx ^ 2];
yD[i] = t0; yD[i + 1] = t1; yD[i + 2] = t2;
}
} else if (scn == 3) {
n *= 3;
_Tp alpha = ColorChannel<_Tp>::max(); // Note: _Tp = float: alpha = 1.0f
for (int i = 0; i < n; i += 3, yD += 4) {
_Tp t0 = yS[i], t1 = yS[i + 1], t2 = yS[i + 2];
yD[bidx] = t0; yD[1] = t1; yD[bidx ^ 2] = t2; yD[3] = alpha;
}
} else {
n *= 4;
for (int i = 0; i < n; i += 4) {
_Tp t0 = yS[i], t1 = yS[i + 1], t2 = yS[i + 2], t3 = yS[i + 3];
yD[i] = t2; yD[i + 1] = t1; yD[i + 2] = t0; yD[i + 3] = t3;
}
}
}
return 0;
}
template<typename _Tp, int chs1, int chs2>
static int CvtColorLoop_RGB2Gray(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx)
{
Range range(0, src.rows);
const uchar* yS = src.ptr(range.start);
uchar* yD = (uchar*)dst.ptr(range.start);
int scn = src.channels, dcn = dst.channels;
RGB2Gray<_Tp> rgb2gray(scn, bidx, 0);
for (int i = range.start; i < range.end; ++i, yS += src.step, yD += dst.step) {
rgb2gray((const _Tp*)yS, (_Tp*)yD, src.cols);
}
return 0;
}
template<typename _Tp, int chs1, int chs2>
static int CvtColorLoop_RGB2YCrCb(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx, const float* coeffs_f, const int* coeffs_i)
{
Range range(0, src.rows);
const uchar* yS = src.ptr(range.start);
uchar* yD = (uchar*)dst.ptr(range.start);
int scn = src.channels, dcn = dst.channels;
if (sizeof(_Tp) == 4) {
RGB2YCrCb_f<_Tp> rgb2ycrcb(scn, bidx, coeffs_f);
for (int i = range.start; i < range.end; ++i, yS += src.step, yD += dst.step) {
rgb2ycrcb((const _Tp*)yS, (_Tp*)yD, src.cols);
}
} else {
if (sizeof(_Tp) == 1) {
RGB2YCrCb_i<uchar> rgb2ycrcb(scn, bidx, coeffs_i);
for (int i = range.start; i < range.end; ++i, yS += src.step, yD += dst.step) {
rgb2ycrcb((const uchar*)yS, (uchar*)yD, src.cols);
}
} else {
RGB2YCrCb_i<ushort> rgb2ycrcb(scn, bidx, coeffs_i);
for (int i = range.start; i < range.end; ++i, yS += src.step, yD += dst.step) {
rgb2ycrcb((const ushort*)yS, (ushort*)yD, src.cols);
}
}
}
return 0;
}
template<typename _Tp, int chs1, int chs2, int bIdx, int uIdx>
static void cvtRGBtoYUV420p(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst)
{
RGB888toYUV420pInvoker<_Tp, chs1, chs2, bIdx> colorConverter(src, &dst, uIdx);
colorConverter(Range(0, src.rows / 2));
}
} // namespace yt_tinycv
#endif // FBC_CV_CVTCOLOR_HPP_

View File

@@ -0,0 +1,75 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_FAST_MATH_HPP_
#define FBC_CV_CORE_FAST_MATH_HPP_
// reference: include/opencv2/core/fast_math.hpp
#include "fbcdef.hpp"
namespace yt_tinycv {
// Rounds floating-point number to the nearest integer
static inline int fbcRound(double value)
{
// it's ok if round does not comply with IEEE754 standard;
// it should allow +/-1 difference when the other functions use round
return (int)(value + (value >= 0 ? 0.5 : -0.5));
}
static inline int fbcRound(float value)
{
// it's ok if round does not comply with IEEE754 standard;
// it should allow +/-1 difference when the other functions use round
return (int)(value + (value >= 0 ? 0.5f : -0.5f));
}
static inline int fbcRound(int value)
{
return value;
}
// Rounds floating-point number to the nearest integer not larger than the original
static inline int fbcFloor(double value)
{
int i = fbcRound(value);
float diff = (float)(value - i);
return i - (diff < 0);
}
static inline int fbcFloor(float value)
{
int i = fbcRound(value);
float diff = (float)(value - i);
return i - (diff < 0);
}
static inline int fbcFloor(int value)
{
return value;
}
// Rounds floating-point number to the nearest integer not smaller than the original
static inline int fbcCeil(double value)
{
int i = fbcRound(value);
float diff = (float)(i - value);
return i + (diff < 0);
}
static inline int fbcCeil(float value)
{
int i = fbcRound(value);
float diff = (float)(i - value);
return i + (diff < 0);
}
static inline int fbcCeil(int value)
{
return value;
}
} // yt_tinycv
#endif // FBC_CV_CORE_FAST_MATH_HPP_

View File

@@ -0,0 +1,67 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_FBCDEF_HPP_
#define FBC_CV_CORE_FBCDEF_HPP_
/* reference: include/opencv2/core/cvdef.h
include/opencv2/core/typedef_c.h
*/
#include "interface.hpp"
#ifdef _MSC_VER
#define FBC_EXPORTS __declspec(dllexport)
#define FBC_DECL_ALIGNED(x) __declspec(align(x))
#else
#define FBC_EXPORTS __attribute__((visibility("default")))
#define FBC_DECL_ALIGNED(x) __attribute__((aligned(x)))
#endif
namespace yt_tinycv {
#define FBC_CN_MAX 512
#define FBC_CN_SHIFT 3
#define FBC_DEPTH_MAX (1 << FBC_CN_SHIFT)
#define FBC_MAT_TYPE_MASK (FBC_DEPTH_MAX*FBC_CN_MAX - 1)
#define FBC_MAT_TYPE(flags) ((flags) & FBC_MAT_TYPE_MASK)
#ifndef MIN
#define MIN(a,b) ((a) > (b) ? (b) : (a))
#endif
#ifndef MAX
#define MAX(a,b) ((a) < (b) ? (b) : (a))
#endif
#define FBC_CN_MAX 512
// Common macros and inline functions
#define FBC_SWAP(a,b,t) ((t) = (a), (a) = (b), (b) = (t))
/** min & max without jumps */
#define FBC_IMIN(a, b) ((a) ^ (((a)^(b)) & (((a) < (b)) - 1)))
#define FBC_IMAX(a, b) ((a) ^ (((a)^(b)) & (((a) > (b)) - 1)))
// fundamental constants
#define FBC_PI 3.1415926535897932384626433832795
// Note: No practical significance
class dump {};
typedef union Cv32suf {
int i;
unsigned u;
float f;
} Cv32suf;
typedef union Cv64suf {
int64 i;
yt_tinycv::uint64 u;
double f;
} Cv64suf;
} // namespace yt_tinycv
#endif // FBC_CV_CORE_FBCDEF_HPP_

View File

@@ -0,0 +1,30 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_FBCSTD_HPP_
#define FBC_CV_CORE_FBCSTD_HPP_
// reference: include/opencv2/core/cvstd.hpp
#include "fbcdef.hpp"
#ifndef __cplusplus
#error fbcstd.hpp header must be compiled as C++
#endif
namespace yt_tinycv {
/* the alignment of all the allocated buffers */
#define FBC_MALLOC_ALIGN 16
// Allocates an aligned memory buffer
FBC_EXPORTS void* fastMalloc(size_t size);
// Deallocates a memory buffer
FBC_EXPORTS void fastFree(void* ptr);
void* cvAlloc(size_t size);
void cvFree_(void* ptr);
#define cvFree(ptr) (cvFree_(*(ptr)), *(ptr)=0)
} // namespace yt_tinycv
#endif // FBC_CV_CORE_FBCSTD_HPP_

View File

@@ -0,0 +1,316 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_IMGPROC_HPP_
#define FBC_CV_IMGPROC_HPP_
// reference: include/opencv2/imgproc.hpp
#include "fbcdef.hpp"
#include "interface.hpp"
#include "mat.hpp"
#include "core.hpp"
namespace yt_tinycv {
// interpolation algorithm
enum InterpolationFlags{
/** nearest neighbor interpolation */
INTER_NEAREST = 0,
/** bilinear interpolation */
INTER_LINEAR = 1,
/** bicubic interpolation */
INTER_CUBIC = 2,
/** resampling using pixel area relation. It may be a preferred method for image decimation, as
it gives moire'-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method. */
INTER_AREA = 3,
/** Lanczos interpolation over 8x8 neighborhood */
INTER_LANCZOS4 = 4,
/** mask for interpolation codes */
INTER_MAX = 7,
/** flag, fills all of the destination image pixels. If some of them correspond to outliers in the
source image, they are set to zero */
WARP_FILL_OUTLIERS = 8,
/** flag, inverse transformation
For example, polar transforms:
- flag is __not__ set: \f$dst( \phi , \rho ) = src(x,y)\f$
- flag is set: \f$dst(x,y) = src( \phi , \rho )\f$
*/
WARP_INVERSE_MAP = 16
};
enum InterpolationMasks {
INTER_BITS = 5,
INTER_BITS2 = INTER_BITS * 2,
INTER_TAB_SIZE = 1 << INTER_BITS,
INTER_TAB_SIZE2 = INTER_TAB_SIZE * INTER_TAB_SIZE
};
// Constants for color conversion
enum ColorConversionFlags {
CV_BGR2BGRA = 0,
CV_RGB2RGBA = CV_BGR2BGRA,
CV_BGRA2BGR = 1,
CV_RGBA2RGB = CV_BGRA2BGR,
CV_BGR2RGBA = 2,
CV_RGB2BGRA = CV_BGR2RGBA,
CV_RGBA2BGR = 3,
CV_BGRA2RGB = CV_RGBA2BGR,
CV_BGR2RGB = 4,
CV_RGB2BGR = CV_BGR2RGB,
CV_BGRA2RGBA = 5,
CV_RGBA2BGRA = CV_BGRA2RGBA,
CV_BGR2GRAY = 6,
CV_RGB2GRAY = 7,
CV_GRAY2BGR = 8,
CV_GRAY2RGB = CV_GRAY2BGR,
CV_GRAY2BGRA = 9,
CV_GRAY2RGBA = CV_GRAY2BGRA,
CV_BGRA2GRAY = 10,
CV_RGBA2GRAY = 11,
// CV_BGR2BGR565 // 12 - 31
CV_BGR2XYZ = 32,
CV_RGB2XYZ = 33,
CV_XYZ2BGR = 34,
CV_XYZ2RGB = 35,
CV_BGR2YCrCb = 36,
CV_RGB2YCrCb = 37,
CV_YCrCb2BGR = 38,
CV_YCrCb2RGB = 39,
CV_BGR2HSV = 40,
CV_RGB2HSV = 41,
CV_BGR2Lab = 44,
CV_RGB2Lab = 45,
// CV_BayerBG2BGR // 46 - 49
CV_BGR2Luv = 50,
CV_RGB2Luv = 51,
CV_BGR2HLS = 52,
CV_RGB2HLS = 53,
CV_HSV2BGR = 54,
CV_HSV2RGB = 55,
CV_Lab2BGR = 56,
CV_Lab2RGB = 57,
CV_Luv2BGR = 58,
CV_Luv2RGB = 59,
CV_HLS2BGR = 60,
CV_HLS2RGB = 61,
// CV_BayerBG2BGR_VNG // 62 - 65
CV_BGR2HSV_FULL = 66,
CV_RGB2HSV_FULL = 67,
CV_BGR2HLS_FULL = 68,
CV_RGB2HLS_FULL = 69,
CV_HSV2BGR_FULL = 70,
CV_HSV2RGB_FULL = 71,
CV_HLS2BGR_FULL = 72,
CV_HLS2RGB_FULL = 73,
// CV_LBGR2Lab // 74 - 81
CV_BGR2YUV = 82,
CV_RGB2YUV = 83,
CV_YUV2BGR = 84,
CV_YUV2RGB = 85,
// CV_BayerBG2GRAY // 86 - 89
//YUV 4:2:0 formats family
CV_YUV2RGB_NV12 = 90,
CV_YUV2BGR_NV12 = 91,
CV_YUV2RGB_NV21 = 92,
CV_YUV2BGR_NV21 = 93,
CV_YUV420sp2RGB = CV_YUV2RGB_NV21,
CV_YUV420sp2BGR = CV_YUV2BGR_NV21,
CV_YUV2RGBA_NV12 = 94,
CV_YUV2BGRA_NV12 = 95,
CV_YUV2RGBA_NV21 = 96,
CV_YUV2BGRA_NV21 = 97,
CV_YUV420sp2RGBA = CV_YUV2RGBA_NV21,
CV_YUV420sp2BGRA = CV_YUV2BGRA_NV21,
CV_YUV2RGB_YV12 = 98,
CV_YUV2BGR_YV12 = 99,
CV_YUV2RGB_IYUV = 100,
CV_YUV2BGR_IYUV = 101,
CV_YUV2RGB_I420 = CV_YUV2RGB_IYUV,
CV_YUV2BGR_I420 = CV_YUV2BGR_IYUV,
CV_YUV420p2RGB = CV_YUV2RGB_YV12,
CV_YUV420p2BGR = CV_YUV2BGR_YV12,
CV_YUV2RGBA_YV12 = 102,
CV_YUV2BGRA_YV12 = 103,
CV_YUV2RGBA_IYUV = 104,
CV_YUV2BGRA_IYUV = 105,
CV_YUV2RGBA_I420 = CV_YUV2RGBA_IYUV,
CV_YUV2BGRA_I420 = CV_YUV2BGRA_IYUV,
CV_YUV420p2RGBA = CV_YUV2RGBA_YV12,
CV_YUV420p2BGRA = CV_YUV2BGRA_YV12,
CV_YUV2GRAY_420 = 106,
CV_YUV2GRAY_NV21 = CV_YUV2GRAY_420,
CV_YUV2GRAY_NV12 = CV_YUV2GRAY_420,
CV_YUV2GRAY_YV12 = CV_YUV2GRAY_420,
CV_YUV2GRAY_IYUV = CV_YUV2GRAY_420,
CV_YUV2GRAY_I420 = CV_YUV2GRAY_420,
CV_YUV420sp2GRAY = CV_YUV2GRAY_420,
CV_YUV420p2GRAY = CV_YUV2GRAY_420,
// YUV 4:2:2 formats family // 107 - 124
// alpha premultiplication // 125 - 126
CV_RGB2YUV_I420 = 127,
CV_BGR2YUV_I420 = 128,
CV_RGB2YUV_IYUV = CV_RGB2YUV_I420,
CV_BGR2YUV_IYUV = CV_BGR2YUV_I420,
CV_RGBA2YUV_I420 = 129,
CV_BGRA2YUV_I420 = 130,
CV_RGBA2YUV_IYUV = CV_RGBA2YUV_I420,
CV_BGRA2YUV_IYUV = CV_BGRA2YUV_I420,
CV_RGB2YUV_YV12 = 131,
CV_BGR2YUV_YV12 = 132,
CV_RGBA2YUV_YV12 = 133,
CV_BGRA2YUV_YV12 = 134
// Edge-Aware Demosaicing // 135 - 139
};
// type of morphological operation
enum MorphTypes{
MORPH_ERODE = 0, // see cv::erode
MORPH_DILATE = 1, // see cv::dilate
MORPH_OPEN = 2, // an opening operation
// \f[\texttt{dst} = \mathrm{open} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \mathrm{erode} ( \texttt{src} , \texttt{element} ))\f]
MORPH_CLOSE = 3, // a closing operation
// \f[\texttt{dst} = \mathrm{close} ( \texttt{src} , \texttt{element} )= \mathrm{erode} ( \mathrm{dilate} ( \texttt{src} , \texttt{element} ))\f]
MORPH_GRADIENT = 4, // a morphological gradient
// \f[\texttt{dst} = \mathrm{morph\_grad} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \texttt{src} , \texttt{element} )- \mathrm{erode} ( \texttt{src} , \texttt{element} )\f]
MORPH_TOPHAT = 5, // "top hat"
// \f[\texttt{dst} = \mathrm{tophat} ( \texttt{src} , \texttt{element} )= \texttt{src} - \mathrm{open} ( \texttt{src} , \texttt{element} )\f]
MORPH_BLACKHAT = 6, // "black hat"
// \f[\texttt{dst} = \mathrm{blackhat} ( \texttt{src} , \texttt{element} )= \mathrm{close} ( \texttt{src} , \texttt{element} )- \texttt{src}\f]
MORPH_HITMISS = 7 // "hit and miss"
// Only supported for CV_8UC1 binary images. Tutorial can be found in [this page](http://opencv-code.com/tutorials/hit-or-miss-transform-in-opencv/)
};
// shape of the structuring element
enum MorphShapes {
MORPH_RECT = 0, // a rectangular structuring element: \f[E_{ij}=1\f]
MORPH_CROSS = 1, // a cross-shaped structuring element:
//!< \f[E_{ij} = \fork{1}{if i=\texttt{anchor.y} or j=\texttt{anchor.x}}{0}{otherwise}\f]
MORPH_ELLIPSE = 2 // an elliptic structuring element, that is, a filled ellipse inscribed
// into the rectangle Rect(0, 0, esize.width, 0.esize.height)
};
// type of the threshold operation
enum ThresholdTypes {
THRESH_BINARY = 0, // \f[\texttt{dst} (x,y) = \fork{\texttt{maxval}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f]
THRESH_BINARY_INV = 1, // \f[\texttt{dst} (x,y) = \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{maxval}}{otherwise}\f]
THRESH_TRUNC = 2, // \f[\texttt{dst} (x,y) = \fork{\texttt{threshold}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f]
THRESH_TOZERO = 3, // \f[\texttt{dst} (x,y) = \fork{\texttt{src}(x,y)}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f]
THRESH_TOZERO_INV = 4, // \f[\texttt{dst} (x,y) = \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f]
THRESH_MASK = 7,
THRESH_OTSU = 8, // flag, use Otsu algorithm to choose the optimal threshold value, combine the flag with one of the above THRESH_* values
THRESH_TRIANGLE = 16 // flag, use Triangle algorithm to choose the optimal threshold value, combine the flag with one of the above THRESH_* values, but not with THRESH_OTSU
};
// adaptive threshold algorithm
enum AdaptiveThresholdTypes {
/** the threshold value \f$T(x,y)\f$ is a mean of the \f$\texttt{blockSize} \times
\texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$ minus C */
ADAPTIVE_THRESH_MEAN_C = 0,
/** the threshold value \f$T(x, y)\f$ is a weighted sum (cross-correlation with a Gaussian
window) of the \f$\texttt{blockSize} \times \texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$
minus C . The default sigma (standard deviation) is used for the specified blockSize . See cv::getGaussianKernel*/
ADAPTIVE_THRESH_GAUSSIAN_C = 1
};
// helper tables
const uchar icvSaturate8u_cv[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255
};
#define FBC_FAST_CAST_8U(t) (assert(-256 <= (t) && (t) <= 512), icvSaturate8u_cv[(t)+256])
#define FBC_CALC_MIN_8U(a,b) (a) -= FBC_FAST_CAST_8U((a) - (b))
#define FBC_CALC_MAX_8U(a,b) (a) += FBC_FAST_CAST_8U((b) - (a))
// cal a structuring element of the specified size and shape for morphological operations
FBC_EXPORTS int getStructuringElement(Mat_<uchar, 1>& dst, int shape, Size ksize, Point anchor = Point(-1, -1));
// Returns the optimal DFT size for a given vector size
// Arrays whose size is a power-of-two (2, 4, 8, 16, 32, ...) are the fastest to process.
// Though, the arrays whose size is a product of 2's, 3's, and 5's are also processed quite efficiently
FBC_EXPORTS int getOptimalDFTSize(int vecsize);
} // namespace yt_tinycv
#endif // FBC_CV_IMGPROC_HPP_

View File

@@ -0,0 +1,38 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_INTERFACE_HPP_
#define FBC_CV_CORE_INTERFACE_HPP_
// reference: include/opencv2/core/hal/interface.h
#include <stdint.h>
namespace yt_tinycv {
/* primitive types */
/*
schar - signed 1 byte integer
uchar - unsigned 1 byte integer
short - signed 2 byte integer
ushort - unsigned 2 byte integer
int - signed 4 byte integer
uint - unsigned 4 byte integer
int64 - signed 8 byte integer
uint64 - unsigned 8 byte integer
*/
typedef unsigned int uint;
typedef signed char schar;
typedef unsigned char uchar;
typedef unsigned short ushort;
#ifdef _MSC_VER
typedef __int64 int64;
typedef unsigned __int64 uint64;
#else
typedef int64_t int64;
typedef uint64_t uint64;
#endif
} // yt_tinycv
#endif // FBC_CV_CORE_INTERFACE_HPP_

View File

@@ -0,0 +1,646 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_MAT_HPP_
#define FBC_CV_CORE_MAT_HPP_
/* reference: include/opencv2/core/mat.hpp
core/src/alloc.cpp
include/opencv2/core/utility.hpp
include/opencv2/core/cvstd.hpp
include/opencv2/core/mat.inl.hpp
*/
#ifndef __cplusplus
#error mat.hpp header must be compiled as C++
#endif
#include <typeinfo>
#include <string.h>
#include <float.h>
#include "fbcdef.hpp"
#include "types.hpp"
#include "base.hpp"
#include "interface.hpp"
#include "fbcstd.hpp"
#include "utility.hpp"
#include "saturate.hpp"
namespace yt_tinycv {
// The class Mat_ represents an n-dimensional dense numerical single-channel or multi-channel array
template<typename _Tp, int chs> class Mat_ {
public:
typedef _Tp value_type;
// default constructor
Mat_() : rows(0), cols(0), channels(0), data(NULL), step(0), allocated(false), datastart(NULL), dataend(NULL) {}
// constructs 2D matrix of the specified size
Mat_(int _rows, int _cols);
// constucts 2D matrix and fills it with the specified value _s
Mat_(int _rows, int _cols, const Scalar& _s);
// constructor for matrix headers pointing to user-allocated data, no data is copied
Mat_(int _rows, int _cols, void* _data);
// copy constructor, NOTE: deep copy
Mat_(const Mat_<_Tp, chs>& _m);
Mat_& operator = (const Mat_& _m);
Mat_ clone() const;
// reports whether the matrix is continuous or not
bool isContinuous() const;
// returns true if the matrix is a submatrix of another matrix
bool isSubmatrix() const;
// copies the matrix content to "_m"
void copyTo(Mat_<_Tp, chs>& _m, const Rect& rect = Rect(0, 0, 0, 0)) const;
// return typed pointer to the specified matrix row,i0, A 0-based row index
const uchar* ptr(int i0 = 0) const;
uchar* ptr(int i0 = 0);
// no data is copied, no memory is allocated
void getROI(Mat_<_Tp, chs>& _m, const Rect& rect = Rect(0, 0, 0, 0));
// Locates the matrix header within a parent matrix
void locateROI(Size& wholeSize, Point& ofs) const;
// Adjusts a submatrix size and position within the parent matrix
void adjustROI(int dtop, int dbottom, int dleft, int dright);
// value converted to the actual array type
void setTo(const Scalar& _value);
// Converts an array to another data type with optional scaling
// the method converts source pixel values to the target data type
// if it does not have a proper size before the operation, it is reallocated
// \f[m(x,y) = saturate \_ cast<rType>( \alpha (*this)(x,y) + \beta )\f]
template<typename _Tp2>
void convertTo(Mat_<_Tp2, chs>& _m, double alpha = 1, const Scalar& scalar = Scalar(0, 0, 0, 0)) const;
Mat_<_Tp, chs>& zeros(int _rows, int _cols);
// returns the matrix cols and rows
Size size() const;
// returns true if Mat_::total() is 0 or if Mat_::data is NULL
bool empty() const;
// returns the matrix element size in bytes: sizeof(_Tp) * channels
size_t elemSize() const;
// returns the size of each matrix element channel in bytes: sizeof(_Tp)
size_t elemSize1() const;
// returns the total number of array elements
size_t total() const;
// release memory
inline void release();
// destructor - calls release()
~Mat_() { release(); };
public:
// the number of rows and columns
int rows, cols;
// channel num
int channels;
// pointer to the data
uchar* data;
// bytes per row
int step; // stride
// memory allocation flag
bool allocated;
// helper fields used in locateROI and adjustROI
const uchar* datastart;
const uchar* dataend;
}; // Mat_
typedef Mat_<uchar, 1> Mat1Gray;
typedef Mat_<uchar, 3> Mat3BGR;
typedef Mat_<uchar, 4> Mat4BGRA;
template<typename _Tp, int chs> inline
void Mat_<_Tp, chs>::release()
{
if (this->data && this->allocated) {
fastFree(this->data);
}
this->data = NULL;
this->datastart = NULL;
this->dataend = NULL;
this->allocated = false;
this->rows = this->cols = this->step = this->channels = 0;
}
template<typename _Tp, int chs>
Mat_<_Tp, chs>::Mat_(int _rows, int _cols)
{
FBC_Assert(_rows > 0 && _cols > 0 && chs > 0);
this->rows = _rows;
this->cols = _cols;
this->channels = chs;
this->step = sizeof(_Tp) * _cols * chs;
this->allocated = true;
size_t size_ = this->rows * this->step;
uchar* p = (uchar*)fastMalloc(size_);
FBC_Assert(p != NULL);
this->data = p;
this->datastart = this->data;
this->dataend = this->data + size_;
}
template<typename _Tp, int chs>
Mat_<_Tp, chs>::Mat_(int _rows, int _cols, const Scalar& _s)
{
FBC_Assert(_rows > 0 && _cols > 0 && chs > 0);
this->rows = _rows;
this->cols = _cols;
this->channels = chs;
this->step = sizeof(_Tp) * _cols * chs;
this->allocated = true;
size_t size_ = this->rows * this->step;
uchar* p = (uchar*)fastMalloc(size_);
FBC_Assert(p != NULL);
this->data = p;
this->datastart = this->data;
this->dataend = this->data + size_;
for (int i = 0; i < _rows; i++) {
_Tp* pRow = (_Tp*)this->data + i * _cols * chs;
for (int j = 0; j < _cols; j++) {
_Tp* pPixel = pRow + j * chs;
for (int m = 0, n = 0; m < chs && n < 4; m++, n++) {
pPixel[n] = saturate_cast<_Tp>(_s.val[n]);
}
}
}
}
template<typename _Tp, int chs>
Mat_<_Tp, chs>::Mat_(int _rows, int _cols, void* _data)
{
FBC_Assert(_rows > 0 && _cols > 0 && chs > 0);
this->rows = _rows;
this->cols = _cols;
this->channels = chs;
this->step = sizeof(_Tp) * _cols * chs;
this->allocated = false;
this->data = (uchar*)_data;
this->datastart = this->data;
this->dataend = this->data + this->step * this->rows;
}
template<typename _Tp, int chs>
Mat_<_Tp, chs>::Mat_(const Mat_<_Tp, chs>& _m)
{
this->rows = _m.rows;
this->cols = _m.cols;
this->channels = _m.channels;
this->step = sizeof(_Tp) * this->cols * this->channels;
size_t size_ = this->rows * this->step;
if (size_ > 0) {
this->allocated = true;
uchar* p = (uchar*)fastMalloc(size_);
FBC_Assert(p != NULL);
memcpy(p, _m.data, size_);
this->data = p;
} else {
this->allocated = false;
this->data = NULL;
}
this->datastart = this->data;
this->dataend = this->data + size_;
}
// template<typename _Tp, int chs>
// Mat_<_Tp, chs>& Mat_<_Tp, chs>::operator () (const Rect& roi)
// {
// return *this;
// }
template<typename _Tp, int chs>
Mat_<_Tp, chs>& Mat_<_Tp, chs>::operator = (const Mat_& _m)
{
size_t size1 = this->rows * this->step;
size_t size2 = _m.rows * _m.step;
this->rows = _m.rows;
this->cols = _m.cols;
this->channels = _m.channels;
this->step = sizeof(_Tp) * this->cols * this->channels;
if ((size1 == size2) && (this->allocated == true) && (this->data != _m.data)) {
memcpy(this->data, _m.data, size2);
} else if (size2 > 0){
if (this->allocated == true) {
fastFree(this->data);
}
this->allocated = true;
uchar* p = (uchar*)fastMalloc(size2);
FBC_Assert(p != NULL);
memcpy(p, _m.data, size2);
this->data = p;
} else {
this->allocated = false;
this->data = NULL;
}
this->datastart = this->data;
this->dataend = this->data + size2;
return *this;
}
template<typename _Tp, int chs>
Mat_<_Tp, chs> Mat_<_Tp, chs>::clone() const
{
Mat_ m;
Rect rect(0, 0, this->cols, this->rows);
copyTo(m, rect);
return m;
}
template<typename _Tp, int chs>
bool Mat_<_Tp, chs>::isContinuous() const
{
return this->rows == 1 || this->step == this->cols * this->elemSize();
}
template<typename _Tp, int chs>
bool Mat_<_Tp, chs>::isSubmatrix() const
{
if ((this->datastart < this->data) || ((this->data + this->step * this->rows) < this->dataend))
return true;
return false;
}
template<typename _Tp, int chs>
void Mat_<_Tp, chs>::copyTo(Mat_<_Tp, chs>& _m, const Rect& rect) const
{
FBC_Assert((this->rows >= rect.y + rect.height) && (this->cols >= rect.x + rect.width));
if (this->data != NULL) {
if ((rect.width > 0) && (rect.height > 0)) {
size_t size1 = sizeof(_Tp) * this->channels * rect.width * rect.height;
int step_ = sizeof(_Tp) * this->channels * rect.width;
size_t size2 = _m.rows * _m.step;
if (size1 == size2) {
uchar* p1 = _m.data;
uchar* p2 = this->data;
for (int i = 0; i < rect.height; i++) {
uchar* p1_ = p1 + i * sizeof(_Tp) * this->channels * rect.width;
uchar* p2_ = p2 + (rect.y + i) * this->step + rect.x * this->channels * sizeof(_Tp);
memcpy(p1_, p2_, step_);
}
} else {
if (_m.allocated == true)
fastFree(_m.data);
uchar* p1 = (uchar*)fastMalloc(size1);
FBC_Assert(p1 != NULL);
uchar* p2 = this->data;
for (int i = 0; i < rect.height; i++) {
uchar* p1_ = p1 + i * sizeof(_Tp) * this->channels * rect.width;
uchar* p2_ = p2 + (rect.y + i) * this->step + rect.x * this->channels * sizeof(_Tp);
memcpy(p1_, p2_, step_);
}
_m.data = p1;
_m.allocated = true;
}
_m.rows = rect.height;
_m.cols = rect.width;
_m.step = step_;
} else {
size_t size1 = this->rows * this->step;
size_t size2 = _m.step * _m.rows;
if (size1 == size2) {
memcpy(_m.data, this->data, size1);
} else {
if (_m.allocated == true)
fastFree(_m.data);
uchar* p = (uchar*)fastMalloc(size1);
FBC_Assert(p != NULL);
memcpy(p, this->data, size1);
_m.data = p;
_m.allocated = true;
}
_m.rows = this->rows;
_m.cols = this->cols;
_m.step = this->step;
}
_m.channels = this->channels;
} else {
if ((_m.data != NULL) && (_m.allocated == true)) {
fastFree(_m.data);
}
_m.data = NULL;
_m.allocated = false;
_m.rows = 0;
_m.cols = 0;
_m.step = 0;
_m.channels = 0;
}
_m.datastart = _m.data;
_m.dataend = _m.data + _m.step * _m.rows;
}
template<typename _Tp, int chs>
const uchar* Mat_<_Tp, chs>::ptr(int i0) const
{
FBC_Assert(i0 < this->rows);
return this->data + i0 * this->step;
}
template<typename _Tp, int chs>
uchar* Mat_<_Tp, chs>::ptr(int i0)
{
FBC_Assert(i0 < this->rows);
return this->data + i0 * this->step;
}
template<typename _Tp, int chs>
void Mat_<_Tp, chs>::getROI(Mat_<_Tp, chs>& _m, const Rect& rect)
{
FBC_Assert((rect.x >= 0) && (rect.y >= 0) && (rect.width > 0) && (rect.height > 0) &&
(this->rows >= rect.y + rect.height) && (this->cols >= rect.x + rect.width));
if (_m.allocated == true) {
fastFree(_m.data);
}
_m.rows = rect.height;
_m.cols = rect.width;
_m.channels = this->channels;
_m.allocated = false;
_m.step = this->step;
_m.data = this->data + rect.y * this->step + rect.x * sizeof(_Tp) * this->channels;
_m.datastart = this->datastart;
_m.dataend = this->dataend;
}
template<typename _Tp, int chs>
void Mat_<_Tp, chs>::locateROI(Size& wholeSize, Point& ofs) const
{
wholeSize.width = this->step / (sizeof(_Tp) * chs);
wholeSize.height = (this->dataend - this->datastart) / this->step;
ofs.y = (this->data - this->datastart) / this->step;
ofs.x = ((this->data - this->datastart) - ((this->data - this->datastart) / this->step * this->step)) / (sizeof(_Tp) * chs);
FBC_Assert(wholeSize.width >= 0 && wholeSize.height >= 0 && ofs.x >= 0 && ofs.y >= 0);
}
template<typename _Tp, int chs>
void Mat_<_Tp, chs>::adjustROI(int dtop, int dbottom, int dleft, int dright)
{
Size wholeSize; Point ofs;
size_t esz = elemSize();
locateROI(wholeSize, ofs);
int row1 = std::max(ofs.y - dtop, 0);
int row2 = std::min(ofs.y + rows + dbottom, wholeSize.height);
int col1 = std::max(ofs.x - dleft, 0);
int col2 = std::min(ofs.x + cols + dright, wholeSize.width);
this->data += (row1 - ofs.y)*step + (col1 - ofs.x)*esz;
this->rows = row2 - row1;
this->cols = col2 - col1;
}
template<typename _Tp, int chs>
void Mat_<_Tp, chs>::setTo(const Scalar& _value)
{
for (int i = 0; i < this->rows; i++) {
uchar* pRow = this->data + i * this->step;
for (int j = 0; j < this->cols; j++) {
_Tp* pPixel = (_Tp*)pRow + j * chs;
for (int m = 0, n = 0; m < chs && n < 4; m++, n++) {
pPixel[n] = saturate_cast<_Tp>(_value.val[n]);
}
}
}
}
template<typename _Tp, int chs> template<typename _Tp2>
void Mat_<_Tp, chs>::convertTo(Mat_<_Tp2, chs>& _m, double alpha, const Scalar& scalar) const
{
FBC_Assert(this->channels <= 4);
bool noScale = fabs(alpha - 1) < DBL_EPSILON && fabs(scalar[0]) < DBL_EPSILON && fabs(scalar[1]) < DBL_EPSILON &&
fabs(scalar[2]) < DBL_EPSILON && fabs(scalar[3]) < DBL_EPSILON;
/*if ((typeid(_Tp).name() == typeid(_Tp2).name()) && noScale) {
this->copyTo(_m);
return;
}*/
size_t size = this->rows * this->cols * this->channels * sizeof(_Tp2);
if (this->rows * this->cols != _m.rows * _m.cols) {
if (_m.allocated == true) {
fastFree(_m.data);
}
uchar* p = (uchar*)fastMalloc(size);
FBC_Assert(p != NULL);
_m.data = p;
_m.allocated = true;
}
_m.channels = this->channels;
_m.rows = this->rows;
_m.cols = this->cols;
_m.step = _m.cols * sizeof(_Tp2) * _m.channels;
_m.datastart = _m.data;
_m.dataend = _m.data + _m.step * _m.rows;
_Tp2 alpha_ = (_Tp2)alpha;
Scalar_<_Tp2> scalar_;
for (int i = 0; i < 4; i++) {
scalar_.val[i]= (_Tp2)scalar.val[i];
}
for (int i = 0; i < this->rows; i++) {
uchar* p1 = this->data + i * this->step;
uchar* p2 = _m.data + i * _m.step;
for (int j = 0; j < this->cols; j++) {
_Tp* p1_ = (_Tp*)p1 + j * chs;
_Tp2* p2_ = (_Tp2*)p2 + j * chs;
for (int ch = 0; ch < chs; ch++) {
p2_[ch] = saturate_cast<_Tp2>(p1_[ch] * alpha_ + scalar_.val[ch]);
}
}
}
}
template<typename _Tp, int chs>
Mat_<_Tp, chs>& Mat_<_Tp, chs>::zeros(int _rows, int _cols)
{
this->rows = _rows;
this->cols = _cols;
this->channels = chs;
this->step = sizeof(_Tp) * _cols * chs;
this->allocated = true;
size_t size_ = this->rows * this->step;
uchar* p = (uchar*)fastMalloc(size_);
FBC_Assert(p != NULL);
this->data = p;
memset(this->data, 0, size_);
return *this;
}
template<typename _Tp, int chs>
Size Mat_<_Tp, chs>::size() const
{
return Size(this->cols, this->rows);
}
template<typename _Tp, int chs>
size_t Mat_<_Tp, chs>::elemSize() const
{
return (this->channels * sizeof(_Tp));
}
template<typename _Tp, int chs>
size_t Mat_<_Tp, chs>::elemSize1() const
{
return sizeof(_Tp);
}
template<typename _Tp, int chs>
size_t Mat_<_Tp, chs>::total() const
{
return (size_t)rows * cols;
}
template<typename _Tp, int chs>
bool Mat_<_Tp, chs>::empty() const
{
return total() == 0 || this->data == NULL;
}
/////////////////////////// Mat_ out-of-class operators ///////////////////////////
template<typename _Tp1, typename _Tp2, int chs> static inline
Mat_<_Tp1, chs>& operator -= (Mat_<_Tp1, chs>& a, const Mat_<_Tp2, chs>& b)
{
FBC_Assert(a.rows == b.rows && a.cols == b.cols);
for (int y = 0; y < a.rows; y++) {
_Tp1* pa = (_Tp1*)a.ptr(y);
_Tp2* pb = (_Tp2*)b.ptr(y);
for (int x = 0; x < a.cols * chs; x++) {
pa[x] = saturate_cast<_Tp1>(pa[x] - pb[x]);
}
}
return a;
}
template<typename _Tp1, typename _Tp2, int chs> static inline
Mat_<_Tp1, chs>& operator += (Mat_<_Tp1, chs>& a, const Mat_<_Tp2, chs>& b)
{
FBC_Assert(a.rows == b.rows && a.cols == b.cols);
for (int y = 0; y < a.rows; y++) {
_Tp1* pa = (_Tp1*)a.ptr(y);
_Tp2* pb = (_Tp2*)b.ptr(y);
for (int x = 0; x < a.cols * chs; x++) {
pa[x] = saturate_cast<_Tp1>(pa[x] + pb[x]);
}
}
return a;
}
template<typename _Tp1, typename _Tp2, int chs> static inline
Mat_<_Tp1, chs> operator - (const Mat_<_Tp1, chs>& a, const Mat_<_Tp2, chs>& b)
{
FBC_Assert(a.rows == b.rows && a.cols == b.cols);
Mat_<_Tp1, chs> c(a.rows, a.cols);
for (int y = 0; y < a.rows; y++) {
_Tp1* pa = (_Tp1*)a.ptr(y);
_Tp2* pb = (_Tp2*)b.ptr(y);
_Tp1* pc = (_Tp1*)c.ptr(y);
for (int x = 0; x < a.cols * chs; x++) {
pc[x] = saturate_cast<_Tp1>(pa[x] - pb[x]);
}
}
return c;
}
template<typename _Tp1, typename _Tp2, int chs> static inline
Mat_<_Tp1, chs> operator == (const Mat_<_Tp1, chs>& a, const Mat_<_Tp2, chs>& b)
{
FBC_Assert(a.rows == b.rows && a.cols == b.cols);
Mat_<_Tp1, chs> c(a.rows, a.cols);
for (int y = 0; y < a.rows; y++) {
_Tp1* pa = (_Tp1*)a.ptr(y);
_Tp2* pb = (_Tp2*)b.ptr(y);
_Tp1* pc = (_Tp1*)c.ptr(y);
for (int x = 0; x < a.cols * chs; x++) {
pc[x] = pa[x] != pb[x] ? 0 : 1;
}
}
return c;
}
template<typename _Tp, int chs> static inline
Mat_<_Tp, chs> operator & (const Mat_<_Tp, chs>& a, const Mat_<_Tp, chs>& b)
{
FBC_Assert(a.rows == b.rows && a.cols == b.cols);
Mat_<_Tp, chs> c(a.rows, a.cols);
for (int y = 0; y < a.rows; y++) {
_Tp* pa = (_Tp*)a.ptr(y);
_Tp* pb = (_Tp*)b.ptr(y);
_Tp* pc = (_Tp*)c.ptr(y);
for (int x = 0; x < a.cols * chs; x++) {
pc[x] = pa[x] & pb[x];
}
}
return c;
}
} // yt_tinycv
#endif // FBC_CV_CORE_MAT_HPP_

View File

@@ -0,0 +1,667 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_MATHFUNCS_HPP_
#define FBC_CV_CORE_MATHFUNCS_HPP_
/* reference: include/opencv2/core.hpp
modules/core/src/mathfuncs.cpp
modules/core/src/mathfuncs_core.cpp
*/
#include "mat.hpp"
#include "NAryMatIterator.hpp"
namespace yt_tinycv {
// calculates the magnitude of 2D vectors formed from the corresponding elements of x and y arrays
// \f[\texttt{dst} (I) = \sqrt{\texttt{x}(I)^2 + \texttt{y}(I)^2}\f]
// support type: float/double, multi-channels
// template <typename _Tp, int chs>
// int magnitude(const Mat_<_Tp, chs>& src1, const Mat_<_Tp, chs>& src2, Mat_<_Tp, chs>& dst)
// {
// FBC_Assert(typeid(float).name() == typeid(_Tp).name() || typeid(double).name() == typeid(_Tp).name());
// FBC_Assert(src1.size() == src2.size());
// if (dst.empty()) {
// dst = Mat_<_Tp, chs>(src1.rows, src1.cols);
// } else {
// FBC_Assert(src1.size() == dst.size());
// }
// for (int y = 0; y < src1.rows; y++) {
// const _Tp* pRowSrc1 = (const _Tp*)src1.ptr(y);
// const _Tp* pRowSrc2 = (const _Tp*)src2.ptr(y);
// _Tp* pRowDst = (_Tp*)dst.ptr(y);
// for (int x = 0; x < src1.cols; x++) {
// pRowDst[x] = std::sqrt(pRowSrc1[x] * pRowSrc1[x] + pRowSrc2[x] * pRowSrc2[x]);
// }
// }
// return 0;
// }
/////////////////////////////////////////// LOG ///////////////////////////////////////
// #define LOGTAB_SCALE 8
// #define LOGTAB_MASK ((1 << LOGTAB_SCALE) - 1)
// #define LOGTAB_MASK2 ((1 << (20 - LOGTAB_SCALE)) - 1)
// #define LOGTAB_MASK2_32F ((1 << (23 - LOGTAB_SCALE)) - 1)
// static const double FBC_DECL_ALIGNED(16) ifbcLogTab[] = {
// 0.0000000000000000000000000000000000000000, 1.000000000000000000000000000000000000000,
// .00389864041565732288852075271279318258166, .9961089494163424124513618677042801556420,
// .00778214044205494809292034119607706088573, .9922480620155038759689922480620155038760,
// .01165061721997527263705585198749759001657, .9884169884169884169884169884169884169884,
// .01550418653596525274396267235488267033361, .9846153846153846153846153846153846153846,
// .01934296284313093139406447562578250654042, .9808429118773946360153256704980842911877,
// .02316705928153437593630670221500622574241, .9770992366412213740458015267175572519084,
// .02697658769820207233514075539915211265906, .9733840304182509505703422053231939163498,
// .03077165866675368732785500469617545604706, .9696969696969696969696969696969696969697,
// .03455238150665972812758397481047722976656, .9660377358490566037735849056603773584906,
// .03831886430213659461285757856785494368522, .9624060150375939849624060150375939849624,
// .04207121392068705056921373852674150839447, .9588014981273408239700374531835205992509,
// .04580953603129420126371940114040626212953, .9552238805970149253731343283582089552239,
// .04953393512227662748292900118940451648088, .9516728624535315985130111524163568773234,
// .05324451451881227759255210685296333394944, .9481481481481481481481481481481481481481,
// .05694137640013842427411105973078520037234, .9446494464944649446494464944649446494465,
// .06062462181643483993820353816772694699466, .9411764705882352941176470588235294117647,
// .06429435070539725460836422143984236754475, .9377289377289377289377289377289377289377,
// .06795066190850773679699159401934593915938, .9343065693430656934306569343065693430657,
// .07159365318700880442825962290953611955044, .9309090909090909090909090909090909090909,
// .07522342123758751775142172846244648098944, .9275362318840579710144927536231884057971,
// .07884006170777602129362549021607264876369, .9241877256317689530685920577617328519856,
// .08244366921107458556772229485432035289706, .9208633093525179856115107913669064748201,
// .08603433734180314373940490213499288074675, .9175627240143369175627240143369175627240,
// .08961215868968712416897659522874164395031, .9142857142857142857142857142857142857143,
// .09317722485418328259854092721070628613231, .9110320284697508896797153024911032028470,
// .09672962645855109897752299730200320482256, .9078014184397163120567375886524822695035,
// .10026945316367513738597949668474029749630, .9045936395759717314487632508833922261484,
// .10379679368164355934833764649738441221420, .9014084507042253521126760563380281690141,
// .10731173578908805021914218968959175981580, .8982456140350877192982456140350877192982,
// .11081436634029011301105782649756292812530, .8951048951048951048951048951048951048951,
// .11430477128005862852422325204315711744130, .8919860627177700348432055749128919860627,
// .11778303565638344185817487641543266363440, .8888888888888888888888888888888888888889,
// .12124924363286967987640707633545389398930, .8858131487889273356401384083044982698962,
// .12470347850095722663787967121606925502420, .8827586206896551724137931034482758620690,
// .12814582269193003360996385708858724683530, .8797250859106529209621993127147766323024,
// .13157635778871926146571524895989568904040, .8767123287671232876712328767123287671233,
// .13499516453750481925766280255629681050780, .8737201365187713310580204778156996587031,
// .13840232285911913123754857224412262439730, .8707482993197278911564625850340136054422,
// .14179791186025733629172407290752744302150, .8677966101694915254237288135593220338983,
// .14518200984449788903951628071808954700830, .8648648648648648648648648648648648648649,
// .14855469432313711530824207329715136438610, .8619528619528619528619528619528619528620,
// .15191604202584196858794030049466527998450, .8590604026845637583892617449664429530201,
// .15526612891112392955683674244937719777230, .8561872909698996655518394648829431438127,
// .15860503017663857283636730244325008243330, .8533333333333333333333333333333333333333,
// .16193282026931324346641360989451641216880, .8504983388704318936877076411960132890365,
// .16524957289530714521497145597095368430010, .8476821192052980132450331125827814569536,
// .16855536102980664403538924034364754334090, .8448844884488448844884488448844884488449,
// .17185025692665920060697715143760433420540, .8421052631578947368421052631578947368421,
// .17513433212784912385018287750426679849630, .8393442622950819672131147540983606557377,
// .17840765747281828179637841458315961062910, .8366013071895424836601307189542483660131,
// .18167030310763465639212199675966985523700, .8338762214983713355048859934853420195440,
// .18492233849401198964024217730184318497780, .8311688311688311688311688311688311688312,
// .18816383241818296356839823602058459073300, .8284789644012944983818770226537216828479,
// .19139485299962943898322009772527962923050, .8258064516129032258064516129032258064516,
// .19461546769967164038916962454095482826240, .8231511254019292604501607717041800643087,
// .19782574332991986754137769821682013571260, .8205128205128205128205128205128205128205,
// .20102574606059073203390141770796617493040, .8178913738019169329073482428115015974441,
// .20421554142869088876999228432396193966280, .8152866242038216560509554140127388535032,
// .20739519434607056602715147164417430758480, .8126984126984126984126984126984126984127,
// .21056476910734961416338251183333341032260, .8101265822784810126582278481012658227848,
// .21372432939771812687723695489694364368910, .8075709779179810725552050473186119873817,
// .21687393830061435506806333251006435602900, .8050314465408805031446540880503144654088,
// .22001365830528207823135744547471404075630, .8025078369905956112852664576802507836991,
// .22314355131420973710199007200571941211830, .8000000000000000000000000000000000000000,
// .22626367865045338145790765338460914790630, .7975077881619937694704049844236760124611,
// .22937410106484582006380890106811420992010, .7950310559006211180124223602484472049689,
// .23247487874309405442296849741978803649550, .7925696594427244582043343653250773993808,
// .23556607131276688371634975283086532726890, .7901234567901234567901234567901234567901,
// .23864773785017498464178231643018079921600, .7876923076923076923076923076923076923077,
// .24171993688714515924331749374687206000090, .7852760736196319018404907975460122699387,
// .24478272641769091566565919038112042471760, .7828746177370030581039755351681957186544,
// .24783616390458124145723672882013488560910, .7804878048780487804878048780487804878049,
// .25088030628580937353433455427875742316250, .7781155015197568389057750759878419452888,
// .25391520998096339667426946107298135757450, .7757575757575757575757575757575757575758,
// .25694093089750041913887912414793390780680, .7734138972809667673716012084592145015106,
// .25995752443692604627401010475296061486000, .7710843373493975903614457831325301204819,
// .26296504550088134477547896494797896593800, .7687687687687687687687687687687687687688,
// .26596354849713793599974565040611196309330, .7664670658682634730538922155688622754491,
// .26895308734550393836570947314612567424780, .7641791044776119402985074626865671641791,
// .27193371548364175804834985683555714786050, .7619047619047619047619047619047619047619,
// .27490548587279922676529508862586226314300, .7596439169139465875370919881305637982196,
// .27786845100345625159121709657483734190480, .7573964497041420118343195266272189349112,
// .28082266290088775395616949026589281857030, .7551622418879056047197640117994100294985,
// .28376817313064456316240580235898960381750, .7529411764705882352941176470588235294118,
// .28670503280395426282112225635501090437180, .7507331378299120234604105571847507331378,
// .28963329258304265634293983566749375313530, .7485380116959064327485380116959064327485,
// .29255300268637740579436012922087684273730, .7463556851311953352769679300291545189504,
// .29546421289383584252163927885703742504130, .7441860465116279069767441860465116279070,
// .29836697255179722709783618483925238251680, .7420289855072463768115942028985507246377,
// .30126133057816173455023545102449133992200, .7398843930635838150289017341040462427746,
// .30414733546729666446850615102448500692850, .7377521613832853025936599423631123919308,
// .30702503529491181888388950937951449304830, .7356321839080459770114942528735632183908,
// .30989447772286465854207904158101882785550, .7335243553008595988538681948424068767908,
// .31275571000389684739317885942000430077330, .7314285714285714285714285714285714285714,
// .31560877898630329552176476681779604405180, .7293447293447293447293447293447293447293,
// .31845373111853458869546784626436419785030, .7272727272727272727272727272727272727273,
// .32129061245373424782201254856772720813750, .7252124645892351274787535410764872521246,
// .32411946865421192853773391107097268104550, .7231638418079096045197740112994350282486,
// .32694034499585328257253991068864706903700, .7211267605633802816901408450704225352113,
// .32975328637246797969240219572384376078850, .7191011235955056179775280898876404494382,
// .33255833730007655635318997155991382896900, .7170868347338935574229691876750700280112,
// .33535554192113781191153520921943709254280, .7150837988826815642458100558659217877095,
// .33814494400871636381467055798566434532400, .7130919220055710306406685236768802228412,
// .34092658697059319283795275623560883104800, .7111111111111111111111111111111111111111,
// .34370051385331840121395430287520866841080, .7091412742382271468144044321329639889197,
// .34646676734620857063262633346312213689100, .7071823204419889502762430939226519337017,
// .34922538978528827602332285096053965389730, .7052341597796143250688705234159779614325,
// .35197642315717814209818925519357435405250, .7032967032967032967032967032967032967033,
// .35471990910292899856770532096561510115850, .7013698630136986301369863013698630136986,
// .35745588892180374385176833129662554711100, .6994535519125683060109289617486338797814,
// .36018440357500774995358483465679455548530, .6975476839237057220708446866485013623978,
// .36290549368936841911903457003063522279280, .6956521739130434782608695652173913043478,
// .36561919956096466943762379742111079394830, .6937669376693766937669376693766937669377,
// .36832556115870762614150635272380895912650, .6918918918918918918918918918918918918919,
// .37102461812787262962487488948681857436900, .6900269541778975741239892183288409703504,
// .37371640979358405898480555151763837784530, .6881720430107526881720430107526881720430,
// .37640097516425302659470730759494472295050, .6863270777479892761394101876675603217158,
// .37907835293496944251145919224654790014030, .6844919786096256684491978609625668449198,
// .38174858149084833769393299007788300514230, .6826666666666666666666666666666666666667,
// .38441169891033200034513583887019194662580, .6808510638297872340425531914893617021277,
// .38706774296844825844488013899535872042180, .6790450928381962864721485411140583554377,
// .38971675114002518602873692543653305619950, .6772486772486772486772486772486772486772,
// .39235876060286384303665840889152605086580, .6754617414248021108179419525065963060686,
// .39499380824086893770896722344332374632350, .6736842105263157894736842105263157894737,
// .39762193064713846624158577469643205404280, .6719160104986876640419947506561679790026,
// .40024316412701266276741307592601515352730, .6701570680628272251308900523560209424084,
// .40285754470108348090917615991202183067800, .6684073107049608355091383812010443864230,
// .40546510810816432934799991016916465014230, .6666666666666666666666666666666666666667,
// .40806588980822172674223224930756259709600, .6649350649350649350649350649350649350649,
// .41065992498526837639616360320360399782650, .6632124352331606217616580310880829015544,
// .41324724855021932601317757871584035456180, .6614987080103359173126614987080103359173,
// .41582789514371093497757669865677598863850, .6597938144329896907216494845360824742268,
// .41840189913888381489925905043492093682300, .6580976863753213367609254498714652956298,
// .42096929464412963239894338585145305842150, .6564102564102564102564102564102564102564,
// .42353011550580327293502591601281892508280, .6547314578005115089514066496163682864450,
// .42608439531090003260516141381231136620050, .6530612244897959183673469387755102040816,
// .42863216738969872610098832410585600882780, .6513994910941475826972010178117048346056,
// .43117346481837132143866142541810404509300, .6497461928934010152284263959390862944162,
// .43370832042155937902094819946796633303180, .6481012658227848101265822784810126582278,
// .43623676677491801667585491486534010618930, .6464646464646464646464646464646464646465,
// .43875883620762790027214350629947148263450, .6448362720403022670025188916876574307305,
// .44127456080487520440058801796112675219780, .6432160804020100502512562814070351758794,
// .44378397241030093089975139264424797147500, .6416040100250626566416040100250626566416,
// .44628710262841947420398014401143882423650, .6400000000000000000000000000000000000000,
// .44878398282700665555822183705458883196130, .6384039900249376558603491271820448877805,
// .45127464413945855836729492693848442286250, .6368159203980099502487562189054726368159,
// .45375911746712049854579618113348260521900, .6352357320099255583126550868486352357320,
// .45623743348158757315857769754074979573500, .6336633663366336633663366336633663366337,
// .45870962262697662081833982483658473938700, .6320987654320987654320987654320987654321,
// .46117571512217014895185229761409573256980, .6305418719211822660098522167487684729064,
// .46363574096303250549055974261136725544930, .6289926289926289926289926289926289926290,
// .46608972992459918316399125615134835243230, .6274509803921568627450980392156862745098,
// .46853771156323925639597405279346276074650, .6259168704156479217603911980440097799511,
// .47097971521879100631480241645476780831830, .6243902439024390243902439024390243902439,
// .47341577001667212165614273544633761048330, .6228710462287104622871046228710462287105,
// .47584590486996386493601107758877333253630, .6213592233009708737864077669902912621359,
// .47827014848147025860569669930555392056700, .6198547215496368038740920096852300242131,
// .48068852934575190261057286988943815231330, .6183574879227053140096618357487922705314,
// .48310107575113581113157579238759353756900, .6168674698795180722891566265060240963855,
// .48550781578170076890899053978500887751580, .6153846153846153846153846153846153846154,
// .48790877731923892879351001283794175833480, .6139088729016786570743405275779376498801,
// .49030398804519381705802061333088204264650, .6124401913875598086124401913875598086124,
// .49269347544257524607047571407747454941280, .6109785202863961813842482100238663484487,
// .49507726679785146739476431321236304938800, .6095238095238095238095238095238095238095,
// .49745538920281889838648226032091770321130, .6080760095011876484560570071258907363420,
// .49982786955644931126130359189119189977650, .6066350710900473933649289099526066350711,
// .50219473456671548383667413872899487614650, .6052009456264775413711583924349881796690,
// .50455601075239520092452494282042607665050, .6037735849056603773584905660377358490566,
// .50691172444485432801997148999362252652650, .6023529411764705882352941176470588235294,
// .50926190178980790257412536448100581765150, .6009389671361502347417840375586854460094,
// .51160656874906207391973111953120678663250, .5995316159250585480093676814988290398126,
// .51394575110223428282552049495279788970950, .5981308411214953271028037383177570093458,
// .51627947444845445623684554448118433356300, .5967365967365967365967365967365967365967,
// .51860776420804555186805373523384332656850, .5953488372093023255813953488372093023256,
// .52093064562418522900344441950437612831600, .5939675174013921113689095127610208816705,
// .52324814376454775732838697877014055848100, .5925925925925925925925925925925925925926,
// .52556028352292727401362526507000438869000, .5912240184757505773672055427251732101617,
// .52786708962084227803046587723656557500350, .5898617511520737327188940092165898617512,
// .53016858660912158374145519701414741575700, .5885057471264367816091954022988505747126,
// .53246479886947173376654518506256863474850, .5871559633027522935779816513761467889908,
// .53475575061602764748158733709715306758900, .5858123569794050343249427917620137299771,
// .53704146589688361856929077475797384977350, .5844748858447488584474885844748858447489,
// .53932196859560876944783558428753167390800, .5831435079726651480637813211845102505695,
// .54159728243274429804188230264117009937750, .5818181818181818181818181818181818181818,
// .54386743096728351609669971367111429572100, .5804988662131519274376417233560090702948,
// .54613243759813556721383065450936555862450, .5791855203619909502262443438914027149321,
// .54839232556557315767520321969641372561450, .5778781038374717832957110609480812641084,
// .55064711795266219063194057525834068655950, .5765765765765765765765765765765765765766,
// .55289683768667763352766542084282264113450, .5752808988764044943820224719101123595506,
// .55514150754050151093110798683483153581600, .5739910313901345291479820627802690582960,
// .55738115013400635344709144192165695130850, .5727069351230425055928411633109619686801,
// .55961578793542265941596269840374588966350, .5714285714285714285714285714285714285714,
// .56184544326269181269140062795486301183700, .5701559020044543429844097995545657015590,
// .56407013828480290218436721261241473257550, .5688888888888888888888888888888888888889,
// .56628989502311577464155334382667206227800, .5676274944567627494456762749445676274945,
// .56850473535266865532378233183408156037350, .5663716814159292035398230088495575221239,
// .57071468100347144680739575051120482385150, .5651214128035320088300220750551876379691,
// .57291975356178548306473885531886480748650, .5638766519823788546255506607929515418502,
// .57511997447138785144460371157038025558000, .5626373626373626373626373626373626373626,
// .57731536503482350219940144597785547375700, .5614035087719298245614035087719298245614,
// .57950594641464214795689713355386629700650, .5601750547045951859956236323851203501094,
// .58169173963462239562716149521293118596100, .5589519650655021834061135371179039301310,
// .58387276558098266665552955601015128195300, .5577342047930283224400871459694989106754,
// .58604904500357812846544902640744112432000, .5565217391304347826086956521739130434783,
// .58822059851708596855957011939608491957200, .5553145336225596529284164859002169197397,
// .59038744660217634674381770309992134571100, .5541125541125541125541125541125541125541,
// .59254960960667157898740242671919986605650, .5529157667386609071274298056155507559395,
// .59470710774669277576265358220553025603300, .5517241379310344827586206896551724137931,
// .59685996110779382384237123915227130055450, .5505376344086021505376344086021505376344,
// .59900818964608337768851242799428291618800, .5493562231759656652360515021459227467811,
// .60115181318933474940990890900138765573500, .5481798715203426124197002141327623126338,
// .60329085143808425240052883964381180703650, .5470085470085470085470085470085470085470,
// .60542532396671688843525771517306566238400, .5458422174840085287846481876332622601279,
// .60755525022454170969155029524699784815300, .5446808510638297872340425531914893617021,
// .60968064953685519036241657886421307921400, .5435244161358811040339702760084925690021,
// .61180154110599282990534675263916142284850, .5423728813559322033898305084745762711864,
// .61391794401237043121710712512140162289150, .5412262156448202959830866807610993657505,
// .61602987721551394351138242200249806046500, .5400843881856540084388185654008438818565,
// .61813735955507864705538167982012964785100, .5389473684210526315789473684210526315789,
// .62024040975185745772080281312810257077200, .5378151260504201680672268907563025210084,
// .62233904640877868441606324267922900617100, .5366876310272536687631027253668763102725,
// .62443328801189346144440150965237990021700, .5355648535564853556485355648535564853556,
// .62652315293135274476554741340805776417250, .5344467640918580375782881002087682672234,
// .62860865942237409420556559780379757285100, .5333333333333333333333333333333333333333,
// .63068982562619868570408243613201193511500, .5322245322245322245322245322245322245322,
// .63276666957103777644277897707070223987100, .5311203319502074688796680497925311203320,
// .63483920917301017716738442686619237065300, .5300207039337474120082815734989648033126,
// .63690746223706917739093569252872839570050, .5289256198347107438016528925619834710744,
// .63897144645792069983514238629140891134750, .5278350515463917525773195876288659793814,
// .64103117942093124081992527862894348800200, .5267489711934156378600823045267489711934,
// .64308667860302726193566513757104985415950, .5256673511293634496919917864476386036961,
// .64513796137358470073053240412264131009600, .5245901639344262295081967213114754098361,
// .64718504499530948859131740391603671014300, .5235173824130879345603271983640081799591,
// .64922794662510974195157587018911726772800, .5224489795918367346938775510204081632653,
// .65126668331495807251485530287027359008800, .5213849287169042769857433808553971486762,
// .65330127201274557080523663898929953575150, .5203252032520325203252032520325203252033,
// .65533172956312757406749369692988693714150, .5192697768762677484787018255578093306288,
// .65735807270835999727154330685152672231200, .5182186234817813765182186234817813765182,
// .65938031808912778153342060249997302889800, .5171717171717171717171717171717171717172,
// .66139848224536490484126716182800009846700, .5161290322580645161290322580645161290323,
// .66341258161706617713093692145776003599150, .5150905432595573440643863179074446680080,
// .66542263254509037562201001492212526500250, .5140562248995983935742971887550200803213,
// .66742865127195616370414654738851822912700, .5130260521042084168336673346693386773547,
// .66943065394262923906154583164607174694550, .5120000000000000000000000000000000000000,
// .67142865660530226534774556057527661323550, .5109780439121756487025948103792415169661,
// .67342267521216669923234121597488410770900, .5099601593625498007968127490039840637450,
// .67541272562017662384192817626171745359900, .5089463220675944333996023856858846918489,
// .67739882359180603188519853574689477682100, .5079365079365079365079365079365079365079,
// .67938098479579733801614338517538271844400, .5069306930693069306930693069306930693069,
// .68135922480790300781450241629499942064300, .5059288537549407114624505928853754940711,
// .68333355911162063645036823800182901322850, .5049309664694280078895463510848126232742,
// .68530400309891936760919861626462079584600, .5039370078740157480314960629921259842520,
// .68727057207096020619019327568821609020250, .5029469548133595284872298624754420432220,
// .68923328123880889251040571252815425395950, .5019607843137254901960784313725490196078,
// .69314718055994530941723212145818, 5.0e-01,
// };
// #define LOGTAB_TRANSLATE(x,h) (((x) - 1.)*ifbcLogTab[(h)+1])
// static const double ln_2 = 0.69314718055994530941723212145818;
// typedef union
// {
// struct {
// int lo;
// int hi;
// } i;
// double d;
// } DBLINT;
// template<typename dump> static void Log_32f(const float *_x, float *y, int n)
// {
// static const float shift[] = { 0, -1.f / 512 };
// static const float
// A0 = 0.3333333333333333333333333f,
// A1 = -0.5f,
// A2 = 1.f;
// #undef LOGPOLY
// #define LOGPOLY(x) (((A0*(x) + A1)*(x) + A2)*(x))
// int i = 0;
// Cv32suf buf[4];
// const int* x = (const int*)_x;
// for (; i <= n - 4; i += 4) {
// double x0, x1, x2, x3;
// double y0, y1, y2, y3;
// int h0, h1, h2, h3;
// h0 = x[i];
// h1 = x[i + 1];
// buf[0].i = (h0 & LOGTAB_MASK2_32F) | (127 << 23);
// buf[1].i = (h1 & LOGTAB_MASK2_32F) | (127 << 23);
// y0 = (((h0 >> 23) & 0xff) - 127) * ln_2;
// y1 = (((h1 >> 23) & 0xff) - 127) * ln_2;
// h0 = (h0 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// h1 = (h1 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y0 += ifbcLogTab[h0];
// y1 += ifbcLogTab[h1];
// h2 = x[i + 2];
// h3 = x[i + 3];
// x0 = LOGTAB_TRANSLATE(buf[0].f, h0);
// x1 = LOGTAB_TRANSLATE(buf[1].f, h1);
// buf[2].i = (h2 & LOGTAB_MASK2_32F) | (127 << 23);
// buf[3].i = (h3 & LOGTAB_MASK2_32F) | (127 << 23);
// y2 = (((h2 >> 23) & 0xff) - 127) * ln_2;
// y3 = (((h3 >> 23) & 0xff) - 127) * ln_2;
// h2 = (h2 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// h3 = (h3 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y2 += ifbcLogTab[h2];
// y3 += ifbcLogTab[h3];
// x2 = LOGTAB_TRANSLATE(buf[2].f, h2);
// x3 = LOGTAB_TRANSLATE(buf[3].f, h3);
// x0 += shift[h0 == 510];
// x1 += shift[h1 == 510];
// y0 += LOGPOLY(x0);
// y1 += LOGPOLY(x1);
// y[i] = (float)y0;
// y[i + 1] = (float)y1;
// x2 += shift[h2 == 510];
// x3 += shift[h3 == 510];
// y2 += LOGPOLY(x2);
// y3 += LOGPOLY(x3);
// y[i + 2] = (float)y2;
// y[i + 3] = (float)y3;
// }
// for (; i < n; i++) {
// int h0 = x[i];
// double y0;
// float x0;
// y0 = (((h0 >> 23) & 0xff) - 127) * ln_2;
// buf[0].i = (h0 & LOGTAB_MASK2_32F) | (127 << 23);
// h0 = (h0 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y0 += ifbcLogTab[h0];
// x0 = (float)LOGTAB_TRANSLATE(buf[0].f, h0);
// x0 += shift[h0 == 510];
// y0 += LOGPOLY(x0);
// y[i] = (float)y0;
// }
// }
// template<typename dump> static void Log_64f(const double *x, double *y, int n)
// {
// static const double shift[] = { 0, -1. / 512 };
// static const double
// A7 = 1.0,
// A6 = -0.5,
// A5 = 0.333333333333333314829616256247390992939472198486328125,
// A4 = -0.25,
// A3 = 0.2,
// A2 = -0.1666666666666666574148081281236954964697360992431640625,
// A1 = 0.1428571428571428769682682968777953647077083587646484375,
// A0 = -0.125;
// #undef LOGPOLY
// #define LOGPOLY(x,k) ((x)+=shift[k], xq = (x)*(x),\
// (((A0*xq + A2)*xq + A4)*xq + A6)*xq + \
// (((A1*xq + A3)*xq + A5)*xq + A7)*(x))
// int i = 0;
// DBLINT buf[4];
// DBLINT *X = (DBLINT *)x;
// for (; i <= n - 4; i += 4) {
// double xq;
// double x0, x1, x2, x3;
// double y0, y1, y2, y3;
// int h0, h1, h2, h3;
// h0 = X[i].i.lo;
// h1 = X[i + 1].i.lo;
// buf[0].i.lo = h0;
// buf[1].i.lo = h1;
// h0 = X[i].i.hi;
// h1 = X[i + 1].i.hi;
// buf[0].i.hi = (h0 & LOGTAB_MASK2) | (1023 << 20);
// buf[1].i.hi = (h1 & LOGTAB_MASK2) | (1023 << 20);
// y0 = (((h0 >> 20) & 0x7ff) - 1023) * ln_2;
// y1 = (((h1 >> 20) & 0x7ff) - 1023) * ln_2;
// h2 = X[i + 2].i.lo;
// h3 = X[i + 3].i.lo;
// buf[2].i.lo = h2;
// buf[3].i.lo = h3;
// h0 = (h0 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// h1 = (h1 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y0 += ifbcLogTab[h0];
// y1 += ifbcLogTab[h1];
// h2 = X[i + 2].i.hi;
// h3 = X[i + 3].i.hi;
// x0 = LOGTAB_TRANSLATE(buf[0].d, h0);
// x1 = LOGTAB_TRANSLATE(buf[1].d, h1);
// buf[2].i.hi = (h2 & LOGTAB_MASK2) | (1023 << 20);
// buf[3].i.hi = (h3 & LOGTAB_MASK2) | (1023 << 20);
// y2 = (((h2 >> 20) & 0x7ff) - 1023) * ln_2;
// y3 = (((h3 >> 20) & 0x7ff) - 1023) * ln_2;
// h2 = (h2 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// h3 = (h3 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y2 += ifbcLogTab[h2];
// y3 += ifbcLogTab[h3];
// x2 = LOGTAB_TRANSLATE(buf[2].d, h2);
// x3 = LOGTAB_TRANSLATE(buf[3].d, h3);
// y0 += LOGPOLY(x0, h0 == 510);
// y1 += LOGPOLY(x1, h1 == 510);
// y[i] = y0;
// y[i + 1] = y1;
// y2 += LOGPOLY(x2, h2 == 510);
// y3 += LOGPOLY(x3, h3 == 510);
// y[i + 2] = y2;
// y[i + 3] = y3;
// }
// for (; i < n; i++) {
// int h0 = X[i].i.hi;
// double xq;
// double x0, y0 = (((h0 >> 20) & 0x7ff) - 1023) * ln_2;
// buf[0].i.hi = (h0 & LOGTAB_MASK2) | (1023 << 20);
// buf[0].i.lo = X[i].i.lo;
// h0 = (h0 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y0 += ifbcLogTab[h0];
// x0 = LOGTAB_TRANSLATE(buf[0].d, h0);
// y0 += LOGPOLY(x0, h0 == 510);
// y[i] = y0;
// }
// }
// // calculates the natural logarithm of the absolute value of every element of the input array
// // \f[\texttt{dst} (I) = \fork{\log |\texttt{src}(I)|}{if \(\texttt{src}(I) \ne 0\) }{\texttt{C}}{otherwise}\f]
// // support type: float/double, multi-channels
// template <typename _Tp, int chs>
// int log(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst)
// {
// FBC_Assert(typeid(float).name() == typeid(_Tp).name() || typeid(double).name() == typeid(_Tp).name());
// if (dst.empty()) {
// dst = Mat_<_Tp, chs>(src.rows, src.cols);
// } else {
// FBC_Assert(src.size() == dst.size());
// }
// if (src.isContinuous() == false || dst.isContinuous() == false) {
// fprintf(stderr, "Error: src and dst must be continuous\n");
// return -1;
// }
// const Mat_<_Tp, chs>* arrays[] = { &src, &dst, 0 };
// uchar* ptrs[2];
// ptrs[0] = src.data;
// ptrs[1] = dst.data;
// int len = (int)(src.rows * src.cols *chs);
// if (sizeof(_Tp) == 4) { // floal
// Log_32f<dump>((const float*)ptrs[0], (float*)ptrs[1], len);
// } else { // double
// Log_64f<dump>((const double*)ptrs[0], (double*)ptrs[1], len);
// }
// return 0;
// }
// find the minimum and maximum element values and their positions
//// support type: single-channel
template<typename _Tp, int chs>
int minMaxLoc(const Mat_<_Tp, chs>& _img, double* minVal, double* maxVal = 0, Point* minLoc = 0, Point* maxLoc = 0, const Mat_<uchar, 1>& mask = Mat_<uchar, 1>())
{
FBC_Assert(chs == 1);
if (!mask.empty()) {
FBC_Assert(_img.rows == mask.rows && _img.cols == mask.cols);
}
double minVal_ = INT_MAX;
double maxVal_ = INT_MIN;
Point minLoc_ = Point(-1, -1);
Point maxLoc_ = Point(-1, -1);
if (mask.empty()) {
for (int y = 0; y < _img.rows; y++) {
_Tp* p = (_Tp*)_img.ptr(y);
for (int x = 0; x < _img.cols; x++) {
if (p[x] > maxVal_) {
maxVal_ = p[x];
maxLoc_.x = x;
maxLoc_.y = y;
}
if (p[x] < minVal_) {
minVal_ = p[x];
minLoc_.x = x;
minLoc_.y = y;
}
}
}
} else {
for (int y = 0; y < _img.rows; y++) {
_Tp* p1 = (_Tp*)_img.ptr(y);
const uchar* p2 = mask.ptr(y);
for (int x = 0; x < _img.cols; x++) {
if (p2[x] && p1[x] > maxVal_) {
maxVal_ = p1[x];
maxLoc_.x = x;
maxLoc_.y = y;
}
if (p2[x] && p1[x] < minVal_) {
minVal_ = p1[x];
minLoc_.x = x;
minLoc_.y = y;
}
}
}
}
*minVal = minVal_;
if (maxVal) *maxVal = maxVal_;
if (minLoc) *minLoc = minLoc_;
if (maxLoc) *maxLoc = maxLoc_;
return 0;
}
// Normalizes the norm or value range of an array
/* \f[\| \texttt{dst} \| _{L_p}= \texttt{alpha}\f]
(where p=Inf, 1 or 2) when normType=NORM_INF, NORM_L1, or NORM_L2, respectively; or so that
\f[\min _I \texttt{dst} (I)= \texttt{alpha} , \, \, \max _I \texttt{dst} (I)= \texttt{beta}\f] */
// support type: float/double, multi-channels
template<typename _Tp1, typename _Tp2, int chs>
int normalize(const Mat_<_Tp1, chs>& _src, Mat_<_Tp2, chs>& _dst, double a = 1, double b = 0, int norm_type = NORM_L2, const Mat_<uchar, 1>& _mask = Mat_<uchar, 1>())
{
//FBC_Assert(typeid(float).name() == typeid(_Tp).name() || typeid(double).name() == typeid(_Tp).name());
if (_dst.empty()) {
_dst = Mat_<_Tp2, chs>(_src.rows, _src.cols);
} else {
FBC_Assert(_src.size() == _dst.size());
}
double scale = 1, shift = 0;
if (norm_type == FBC_MINMAX) {
double smin = 0, smax = 0;
double dmin = MIN(a, b), dmax = MAX(a, b);
minMaxLoc(_src, &smin, &smax, 0, 0, _mask);
scale = (dmax - dmin)*(smax - smin > DBL_EPSILON ? 1. / (smax - smin) : 0);
shift = dmin - smin*scale;
} else if (norm_type == FBC_L2 || norm_type == FBC_L1 || norm_type == FBC_C) {
fprintf(stderr, "Error: normalize norm no impl\n");
FBC_Assert(0); // TODO
/*scale = norm(_src, norm_type, _mask);
scale = scale > DBL_EPSILON ? a / scale : 0.;
shift = 0;*/
} else {
FBC_Error("Unknown/unsupported norm type");
}
Scalar scalar = Scalar::all(shift);
if (_mask.empty()) {
_src.convertTo(_dst, scale, scalar);
} else {
Mat_<_Tp2, chs> tmp;
_src.convertTo(tmp, scale, scalar);
for (int y = 0; y < _dst.rows; y++) {
_Tp2* p1 = (_Tp2*)_dst.ptr(y);
const _Tp2* p2 = (_Tp2*)tmp.ptr(y);
const uchar* p3 = _mask.ptr(y);
for (int x = 0; x < _dst.cols; x++) {
if (p3[x] != 0) {
p1[x] = p2[x];
}
}
}
}
return 0;
}
} // namespace yt_tinycv
#endif // FBC_CV_CORE_MATHFUNCS_HPP_

View File

@@ -0,0 +1,851 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_MATX_HPP_
#define FBC_CV_CORE_MATX_HPP_
// reference: include/opencv2/core/matx.hpp
#ifndef __cplusplus
#error matx.hpp header must be compiled as C++
#endif
#include "fbcdef.hpp"
#include "base.hpp"
#include "interface.hpp"
#include "saturate.hpp"
namespace yt_tinycv {
////////////////////////////// Small Matrix ///////////////////////////
// Template class for small matrices whose type and size are known at compilation time
template<typename _Tp, int m, int n> class Matx {
public:
enum {
rows = m,
cols = n,
channels = rows*cols,
shortdim = (m < n ? m : n)
};
typedef _Tp value_type;
typedef Matx<_Tp, m, n> mat_type;
typedef Matx<_Tp, shortdim, 1> diag_type;
//! default constructor
Matx();
Matx(_Tp v0); //!< 1x1 matrix
Matx(_Tp v0, _Tp v1); //!< 1x2 or 2x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2); //!< 1x3 or 3x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 1x4, 2x2 or 4x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 1x5 or 5x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 1x6, 2x3, 3x2 or 6x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 1x7 or 7x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 1x8, 2x4, 4x2 or 8x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 1x9, 3x3 or 9x1 matrix
explicit Matx(const _Tp* vals); //!< initialize from a plain array
static Matx all(_Tp alpha);
static Matx zeros();
static Matx ones();
static Matx eye();
static Matx diag(const diag_type& d);
//! dot product computed with the default precision
_Tp dot(const Matx<_Tp, m, n>& v) const;
//! dot product computed in double-precision arithmetics
double ddot(const Matx<_Tp, m, n>& v) const;
//! conversion to another data type
template<typename T2> operator Matx<T2, m, n>() const;
//! change the matrix shape
template<int m1, int n1> Matx<_Tp, m1, n1> reshape() const;
//! extract part of the matrix
template<int m1, int n1> Matx<_Tp, m1, n1> get_minor(int i, int j) const;
//! extract the matrix row
Matx<_Tp, 1, n> row(int i) const;
//! extract the matrix column
Matx<_Tp, m, 1> col(int i) const;
//! extract the matrix diagonal
diag_type diag() const;
//! element access
const _Tp& operator ()(int i, int j) const;
_Tp& operator ()(int i, int j);
//! 1D element access
const _Tp& operator ()(int i) const;
_Tp& operator ()(int i);
_Tp val[m*n]; //< matrix elements
};
typedef Matx<float, 1, 2> Matx12f;
typedef Matx<double, 1, 2> Matx12d;
typedef Matx<float, 1, 3> Matx13f;
typedef Matx<double, 1, 3> Matx13d;
typedef Matx<float, 1, 4> Matx14f;
typedef Matx<double, 1, 4> Matx14d;
typedef Matx<float, 1, 6> Matx16f;
typedef Matx<double, 1, 6> Matx16d;
typedef Matx<float, 2, 1> Matx21f;
typedef Matx<double, 2, 1> Matx21d;
typedef Matx<float, 3, 1> Matx31f;
typedef Matx<double, 3, 1> Matx31d;
typedef Matx<float, 4, 1> Matx41f;
typedef Matx<double, 4, 1> Matx41d;
typedef Matx<float, 6, 1> Matx61f;
typedef Matx<double, 6, 1> Matx61d;
typedef Matx<float, 2, 2> Matx22f;
typedef Matx<double, 2, 2> Matx22d;
typedef Matx<float, 2, 3> Matx23f;
typedef Matx<double, 2, 3> Matx23d;
typedef Matx<float, 3, 2> Matx32f;
typedef Matx<double, 3, 2> Matx32d;
typedef Matx<float, 3, 3> Matx33f;
typedef Matx<double, 3, 3> Matx33d;
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx()
{
for (int i = 0; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0)
{
val[0] = v0;
for (int i = 1; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1)
{
FBC_StaticAssert(channels >= 2, "Matx should have at least 2 elements.");
val[0] = v0; val[1] = v1;
for (int i = 2; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2)
{
FBC_StaticAssert(channels >= 3, "Matx should have at least 3 elements.");
val[0] = v0; val[1] = v1; val[2] = v2;
for (int i = 3; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3)
{
FBC_StaticAssert(channels >= 4, "Matx should have at least 4 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3;
for (int i = 4; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4)
{
FBC_StaticAssert(channels >= 5, "Matx should have at least 5 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4;
for (int i = 5; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5)
{
FBC_StaticAssert(channels >= 6, "Matx should have at least 6 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3;
val[4] = v4; val[5] = v5;
for (int i = 6; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6)
{
FBC_StaticAssert(channels >= 7, "Matx should have at least 7 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3;
val[4] = v4; val[5] = v5; val[6] = v6;
for (int i = 7; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7)
{
FBC_StaticAssert(channels >= 8, "Matx should have at least 8 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3;
val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7;
for (int i = 8; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8)
{
FBC_StaticAssert(channels >= 9, "Matx should have at least 9 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3;
val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7;
val[8] = v8;
for (int i = 9; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(const _Tp* values)
{
for (int i = 0; i < channels; i++) val[i] = values[i];
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n> Matx<_Tp, m, n>::all(_Tp alpha)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++) M.val[i] = alpha;
return M;
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n> Matx<_Tp, m, n>::zeros()
{
return all(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n> Matx<_Tp, m, n>::ones()
{
return all(1);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n> Matx<_Tp, m, n>::eye()
{
Matx<_Tp, m, n> M;
for (int i = 0; i < shortdim; i++)
M(i, i) = 1;
return M;
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n> Matx<_Tp, m, n>::diag(const typename Matx<_Tp, m, n>::diag_type& d)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < shortdim; i++)
M(i, i) = d(i, 0);
return M;
}
template<typename _Tp, int m, int n> inline
_Tp Matx<_Tp, m, n>::dot(const Matx<_Tp, m, n>& M) const
{
_Tp s = 0;
for (int i = 0; i < channels; i++) s += val[i] * M.val[i];
return s;
}
template<typename _Tp, int m, int n> inline
double Matx<_Tp, m, n>::ddot(const Matx<_Tp, m, n>& M) const
{
double s = 0;
for (int i = 0; i < channels; i++) s += (double)val[i] * M.val[i];
return s;
}
template<typename _Tp, int m, int n> template<typename T2>
inline Matx<_Tp, m, n>::operator Matx<T2, m, n>() const
{
Matx<T2, m, n> M;
for (int i = 0; i < m*n; i++) M.val[i] = saturate_cast<T2>(val[i]);
return M;
}
template<typename _Tp, int m, int n> template<int m1, int n1> inline
Matx<_Tp, m1, n1> Matx<_Tp, m, n>::reshape() const
{
FBC_StaticAssert(m1*n1 == m*n, "Input and destnarion matrices must have the same number of elements");
return (const Matx<_Tp, m1, n1>&)*this;
}
template<typename _Tp, int m, int n>
template<int m1, int n1> inline
Matx<_Tp, m1, n1> Matx<_Tp, m, n>::get_minor(int i, int j) const
{
FBC_Assert(0 <= i && i + m1 <= m && 0 <= j && j + n1 <= n);
Matx<_Tp, m1, n1> s;
for (int di = 0; di < m1; di++)
for (int dj = 0; dj < n1; dj++)
s(di, dj) = (*this)(i + di, j + dj);
return s;
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, 1, n> Matx<_Tp, m, n>::row(int i) const
{
FBC_Assert((unsigned)i < (unsigned)m);
return Matx<_Tp, 1, n>(&val[i*n]);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, 1> Matx<_Tp, m, n>::col(int j) const
{
FBC_Assert((unsigned)j < (unsigned)n);
Matx<_Tp, m, 1> v;
for (int i = 0; i < m; i++)
v.val[i] = val[i*n + j];
return v;
}
template<typename _Tp, int m, int n> inline
typename Matx<_Tp, m, n>::diag_type Matx<_Tp, m, n>::diag() const
{
diag_type d;
for (int i = 0; i < shortdim; i++)
d.val[i] = val[i*n + i];
return d;
}
template<typename _Tp, int m, int n> inline
const _Tp& Matx<_Tp, m, n>::operator()(int i, int j) const
{
FBC_Assert((unsigned)i < (unsigned)m && (unsigned)j < (unsigned)n);
return this->val[i*n + j];
}
template<typename _Tp, int m, int n> inline
_Tp& Matx<_Tp, m, n>::operator ()(int i, int j)
{
FBC_Assert((unsigned)i < (unsigned)m && (unsigned)j < (unsigned)n);
return val[i*n + j];
}
template<typename _Tp, int m, int n> inline
const _Tp& Matx<_Tp, m, n>::operator ()(int i) const
{
FBC_StaticAssert(m == 1 || n == 1, "Single index indexation requires matrix to be a column or a row");
FBC_Assert((unsigned)i < (unsigned)(m + n - 1));
return val[i];
}
template<typename _Tp, int m, int n> inline
_Tp& Matx<_Tp, m, n>::operator ()(int i)
{
FBC_StaticAssert(m == 1 || n == 1, "Single index indexation requires matrix to be a column or a row");
FBC_Assert((unsigned)i < (unsigned)(m + n - 1));
return val[i];
}
template<typename _Tp, int m, int n> static inline
double norm(const Matx<_Tp, m, n>& M)
{
return std::sqrt(normL2Sqr<_Tp, double>(M.val, m*n));
}
template<typename _Tp, int m, int n> static inline
double norm(const Matx<_Tp, m, n>& M, int normType)
{
switch (normType) {
case NORM_INF:
return (double)normInf<_Tp, _Tp>(M.val, m*n);
case NORM_L1:
return (double)normL1<_Tp, _Tp>(M.val, m*n);
case NORM_L2SQR:
return (double)normL2Sqr<_Tp, _Tp>(M.val, m*n);
default:
case NORM_L2:
return std::sqrt((double)normL2Sqr<_Tp, _Tp>(M.val, m*n));
}
}
///////////////////////////// Matx out-of-class operators ////////////////////////////////
template<typename _Tp1, typename _Tp2, int m, int n> static inline
Matx<_Tp1, m, n>& operator += (Matx<_Tp1, m, n>& a, const Matx<_Tp2, m, n>& b)
{
for (int i = 0; i < m*n; i++)
a.val[i] = saturate_cast<_Tp1>(a.val[i] + b.val[i]);
return a;
}
template<typename _Tp1, typename _Tp2, int m, int n> static inline
Matx<_Tp1, m, n>& operator -= (Matx<_Tp1, m, n>& a, const Matx<_Tp2, m, n>& b)
{
for (int i = 0; i < m*n; i++)
a.val[i] = saturate_cast<_Tp1>(a.val[i] - b.val[i]);
return a;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator + (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] + b.val[i]);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator - (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] - b.val[i]);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, int alpha)
{
for (int i = 0; i < m*n; i++)
a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return a;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, float alpha)
{
for (int i = 0; i < m*n; i++)
a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return a;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, double alpha)
{
for (int i = 0; i < m*n; i++)
a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return a;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, int alpha)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, float alpha)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, double alpha)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (int alpha, const Matx<_Tp, m, n>& a)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (float alpha, const Matx<_Tp, m, n>& a)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (double alpha, const Matx<_Tp, m, n>& a)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n, int l> static inline
Matx<_Tp, m, n> operator * (const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
_Tp s = 0;
for (int k = 0; k < l; k++)
s += a(i, k) * b(k, j);
M.val[i*n + j] = s;
}
return M;
}
template<typename _Tp, int m, int n> static inline
bool operator == (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b)
{
for (int i = 0; i < m*n; i++)
if (a.val[i] != b.val[i]) return false;
return true;
}
template<typename _Tp, int m, int n> static inline
bool operator != (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b)
{
return !(a == b);
}
///////////////////////////////////////// Vec ///////////////////////////////////
// Template class for short numerical vectors, a partial case of Matx
template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1> {
public:
typedef _Tp value_type;
enum {
channels = cn
};
//! default constructor
Vec();
Vec(_Tp v0); //!< 1-element vector constructor
Vec(_Tp v0, _Tp v1); //!< 2-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2); //!< 3-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 4-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 5-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 6-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 7-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 8-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 9-element vector constructor
explicit Vec(const _Tp* values);
Vec(const Vec<_Tp, cn>& v);
static Vec all(_Tp alpha);
//! per-element multiplication
Vec mul(const Vec<_Tp, cn>& v) const;
//! conversion to another data type
template<typename T2> operator Vec<T2, cn>() const;
/*! element access */
const _Tp& operator [](int i) const;
_Tp& operator[](int i);
const _Tp& operator ()(int i) const;
_Tp& operator ()(int i);
};
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;
typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
typedef Vec<ushort, 2> Vec2w;
typedef Vec<ushort, 3> Vec3w;
typedef Vec<ushort, 4> Vec4w;
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<int, 6> Vec6i;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec() {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0)
: Matx<_Tp, cn, 1>(v0) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1)
: Matx<_Tp, cn, 1>(v0, v1) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2)
: Matx<_Tp, cn, 1>(v0, v1, v2) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7, v8) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(const _Tp* values)
: Matx<_Tp, cn, 1>(values) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(const Vec<_Tp, cn>& m)
: Matx<_Tp, cn, 1>(m.val) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn> Vec<_Tp, cn>::all(_Tp alpha)
{
Vec v;
for (int i = 0; i < cn; i++) v.val[i] = alpha;
return v;
}
template<typename _Tp, int cn> inline
Vec<_Tp, cn> Vec<_Tp, cn>::mul(const Vec<_Tp, cn>& v) const
{
Vec<_Tp, cn> w;
for (int i = 0; i < cn; i++) w.val[i] = saturate_cast<_Tp>(this->val[i] * v.val[i]);
return w;
}
template<typename _Tp, int cn> template<typename T2> inline
Vec<_Tp, cn>::operator Vec<T2, cn>() const
{
Vec<T2, cn> v;
for (int i = 0; i < cn; i++) v.val[i] = saturate_cast<T2>(this->val[i]);
return v;
}
template<typename _Tp, int cn> inline
const _Tp& Vec<_Tp, cn>::operator [](int i) const
{
FBC_Assert((unsigned)i < (unsigned)cn);
return this->val[i];
}
template<typename _Tp, int cn> inline
_Tp& Vec<_Tp, cn>::operator [](int i)
{
FBC_Assert((unsigned)i < (unsigned)cn);
return this->val[i];
}
template<typename _Tp, int cn> inline
const _Tp& Vec<_Tp, cn>::operator ()(int i) const
{
FBC_Assert((unsigned)i < (unsigned)cn);
return this->val[i];
}
template<typename _Tp, int cn> inline
_Tp& Vec<_Tp, cn>::operator ()(int i)
{
FBC_Assert((unsigned)i < (unsigned)cn);
return this->val[i];
}
////////////////////////////// Vec out-of-class operators ////////////////////////////////
template<typename _Tp1, typename _Tp2, int cn> static inline
Vec<_Tp1, cn>& operator += (Vec<_Tp1, cn>& a, const Vec<_Tp2, cn>& b)
{
for (int i = 0; i < cn; i++)
a.val[i] = saturate_cast<_Tp1>(a.val[i] + b.val[i]);
return a;
}
template<typename _Tp1, typename _Tp2, int cn> static inline
Vec<_Tp1, cn>& operator -= (Vec<_Tp1, cn>& a, const Vec<_Tp2, cn>& b)
{
for (int i = 0; i < cn; i++)
a.val[i] = saturate_cast<_Tp1>(a.val[i] - b.val[i]);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator + (const Vec<_Tp, cn>& a, const Vec<_Tp, cn>& b)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] + b.val[i]);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator - (const Vec<_Tp, cn>& a, const Vec<_Tp, cn>& b)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] - b.val[i]);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, int alpha)
{
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * alpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, float alpha)
{
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * alpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, double alpha)
{
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * alpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, int alpha)
{
double ialpha = 1. / alpha;
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * ialpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, float alpha)
{
float ialpha = 1.f / alpha;
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * ialpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, double alpha)
{
double ialpha = 1. / alpha;
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * ialpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (const Vec<_Tp, cn>& a, int alpha)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (int alpha, const Vec<_Tp, cn>& a)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (const Vec<_Tp, cn>& a, float alpha)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (float alpha, const Vec<_Tp, cn>& a)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (const Vec<_Tp, cn>& a, double alpha)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (double alpha, const Vec<_Tp, cn>& a)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator / (const Vec<_Tp, cn>& a, int alpha)
{
Vec<_Tp, cn> v;
double ialpha = 1. / alpha;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * ialpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator / (const Vec<_Tp, cn>& a, float alpha)
{
Vec<_Tp, cn> v;
float ialpha = 1.f / alpha;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * ialpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator / (const Vec<_Tp, cn>& a, double alpha)
{
Vec<_Tp, cn> v;
double ialpha = 1. / alpha;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * ialpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator - (const Vec<_Tp, cn>& a)
{
Vec<_Tp, cn> t;
for (int i = 0; i < cn; i++) t.val[i] = saturate_cast<_Tp>(-a.val[i]);
return t;
}
} //yt_tinycv
#endif //FBC_CV_CORE_MATX_HPP_

View File

@@ -0,0 +1,470 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_RESIZE_HPP_
#define FBC_CV_RESIZE_HPP_
/* reference: imgproc/include/opencv2/imgproc.hpp
imgproc/src/imgwarp.cpp
*/
#include <typeinfo>
#include "mat.hpp"
#include "base.hpp"
#include "saturate.hpp"
#include "utility.hpp"
#include "imgproc.hpp"
namespace yt_tinycv {
static const int MAX_ESIZE = 16;
// interpolation formulas and tables
const int INTER_RESIZE_COEF_BITS = 11;
const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;
template<typename _Tp, int chs> static int resize_nearest(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst);
template<typename _Tp, int chs> static int resize_linear(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst);
// resize the image src down to or up to the specified size
// support type: uchar/float
template<typename _Tp, int chs>
int resize(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, int interpolation = INTER_LINEAR)
{
FBC_Assert((interpolation >= 0) && (interpolation < 5));
FBC_Assert((src.rows >= 4 && src.cols >= 4) && (dst.rows >= 4 && dst.cols >= 4));
FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() || typeid(float).name() == typeid(_Tp).name()); // uchar || float
Size ssize = src.size();
Size dsize = dst.size();
if (dsize == ssize) {
// Source and destination are of same size. Use simple copy.
src.copyTo(dst);
return 0;
}
switch (interpolation) {
case 0: {
resize_nearest(src, dst);
break;
}
case 1: {
resize_linear(src, dst);
break;
}
default:
return -1;
}
return 0;
}
template<typename ST, typename DT> struct Cast
{
typedef ST type1;
typedef DT rtype;
DT operator()(ST val) const { return saturate_cast<DT>(val); }
};
template<typename ST, typename DT, int bits> struct FixedPtCast
{
typedef ST type1;
typedef DT rtype;
enum { SHIFT = bits, DELTA = 1 << (bits - 1) };
DT operator()(ST val) const { return saturate_cast<DT>((val + DELTA) >> SHIFT); }
};
template<typename type>
static type clip(type x, type a, type b)
{
return x >= a ? (x < b ? x : b - 1) : a;
}
template<typename T, typename WT, typename AT>
struct HResizeLinear
{
typedef T value_type;
typedef WT buf_type;
typedef AT alpha_type;
void operator()(const T** src, WT** dst, int count,
const int* xofs, const AT* alpha,
int swidth, int dwidth, int cn, int xmin, int xmax, int ONE) const
{
int dx, k;
int dx0 = 0;
for (k = 0; k <= count - 2; k++) {
const T *S0 = src[k], *S1 = src[k + 1];
WT *D0 = dst[k], *D1 = dst[k + 1];
for (dx = dx0; dx < xmax; dx++) {
int sx = xofs[dx];
WT a0 = alpha[dx * 2], a1 = alpha[dx * 2 + 1];
WT t0 = S0[sx] * a0 + S0[sx + cn] * a1;
WT t1 = S1[sx] * a0 + S1[sx + cn] * a1;
D0[dx] = t0; D1[dx] = t1;
}
for (; dx < dwidth; dx++) {
int sx = xofs[dx];
D0[dx] = WT(S0[sx] * ONE); D1[dx] = WT(S1[sx] * ONE);
}
}
for (; k < count; k++) {
const T *S = src[k];
WT *D = dst[k];
for (dx = 0; dx < xmax; dx++) {
int sx = xofs[dx];
D[dx] = S[sx] * alpha[dx * 2] + S[sx + cn] * alpha[dx * 2 + 1];
}
for (; dx < dwidth; dx++) {
D[dx] = WT(S[xofs[dx]] * ONE);
}
}
}
};
template<typename T, typename WT, typename AT, class CastOp>
struct VResizeLinear
{
typedef T value_type;
typedef WT buf_type;
typedef AT alpha_type;
void operator()(const WT** src, T* dst, const AT* beta, int width) const
{
WT b0 = beta[0], b1 = beta[1];
const WT *S0 = src[0], *S1 = src[1];
CastOp castOp;
int x = 0;
for (; x <= width - 4; x += 4) {
WT t0, t1;
t0 = S0[x] * b0 + S1[x] * b1;
t1 = S0[x + 1] * b0 + S1[x + 1] * b1;
dst[x] = castOp(t0); dst[x + 1] = castOp(t1);
t0 = S0[x + 2] * b0 + S1[x + 2] * b1;
t1 = S0[x + 3] * b0 + S1[x + 3] * b1;
dst[x + 2] = castOp(t0); dst[x + 3] = castOp(t1);
}
for (; x < width; x++) {
dst[x] = castOp(S0[x] * b0 + S1[x] * b1);
}
}
};
template<>
struct VResizeLinear<uchar, int, short, FixedPtCast<int, uchar, INTER_RESIZE_COEF_BITS * 2>>
{
typedef uchar value_type;
typedef int buf_type;
typedef short alpha_type;
void operator()(const buf_type** src, value_type* dst, const alpha_type* beta, int width) const
{
alpha_type b0 = beta[0], b1 = beta[1];
const buf_type *S0 = src[0], *S1 = src[1];
int x = 0;
for (; x <= width - 4; x += 4) {
dst[x + 0] = uchar((((b0 * (S0[x + 0] >> 4)) >> 16) + ((b1 * (S1[x + 0] >> 4)) >> 16) + 2) >> 2);
dst[x + 1] = uchar((((b0 * (S0[x + 1] >> 4)) >> 16) + ((b1 * (S1[x + 1] >> 4)) >> 16) + 2) >> 2);
dst[x + 2] = uchar((((b0 * (S0[x + 2] >> 4)) >> 16) + ((b1 * (S1[x + 2] >> 4)) >> 16) + 2) >> 2);
dst[x + 3] = uchar((((b0 * (S0[x + 3] >> 4)) >> 16) + ((b1 * (S1[x + 3] >> 4)) >> 16) + 2) >> 2);
}
for (; x < width; x++) {
dst[x] = uchar((((b0 * (S0[x] >> 4)) >> 16) + ((b1 * (S1[x] >> 4)) >> 16) + 2) >> 2);
}
}
};
template<typename _Tp, typename value_type, typename buf_type, typename alpha_type, int chs>
static void resizeGeneric_Linear(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst,
const int* xofs, const void* _alpha, const int* yofs, const void* _beta, int xmin, int xmax, int ksize, int ONE)
{
Size ssize = src.size(), dsize = dst.size();
int dy, cn = src.channels;
ssize.width *= cn;
dsize.width *= cn;
xmin *= cn;
xmax *= cn;
// image resize is a separable operation. In case of not too strong
Range range(0, dsize.height);
int bufstep = (int)alignSize(dsize.width, 16);
AutoBuffer<buf_type> _buffer(bufstep*ksize);
const value_type* srows[MAX_ESIZE] = { 0 };
buf_type* rows[MAX_ESIZE] = { 0 };
int prev_sy[MAX_ESIZE];
for (int k = 0; k < ksize; k++) {
prev_sy[k] = -1;
rows[k] = (buf_type*)_buffer + bufstep*k;
}
const alpha_type* beta = (const alpha_type*)_beta + ksize * range.start;
HResizeLinear<value_type, buf_type, alpha_type> hresize;
VResizeLinear<value_type, buf_type, alpha_type, FixedPtCast<int, uchar, INTER_RESIZE_COEF_BITS * 2>> vresize1;
VResizeLinear<value_type, buf_type, alpha_type, Cast<float, float>> vresize2;
for (dy = range.start; dy < range.end; dy++, beta += ksize) {
int sy0 = yofs[dy], k0 = ksize, k1 = 0, ksize2 = ksize / 2;
for (int k = 0; k < ksize; k++) {
int sy = clip<int>(sy0 - ksize2 + 1 + k, 0, ssize.height);
for (k1 = std::max(k1, k); k1 < ksize; k1++) {
if (sy == prev_sy[k1]) { // if the sy-th row has been computed already, reuse it.
if (k1 > k) {
memcpy(rows[k], rows[k1], bufstep*sizeof(rows[0][0]));
}
break;
}
}
if (k1 == ksize) {
k0 = std::min(k0, k); // remember the first row that needs to be computed
}
srows[k] = (const value_type*)src.ptr(sy);
prev_sy[k] = sy;
}
if (k0 < ksize) {
hresize((const value_type**)(srows + k0), (buf_type**)(rows + k0), ksize - k0, xofs, (const alpha_type*)(_alpha),
ssize.width, dsize.width, cn, xmin, xmax, ONE);
}
if (sizeof(_Tp) == 1) { // uchar
vresize1((const buf_type**)rows, (value_type*)(dst.data + dst.step*dy), beta, dsize.width);
} else { // float
vresize2((const buf_type**)rows, (value_type*)(dst.data + dst.step*dy), beta, dsize.width);
}
}
}
template<typename _Tp, int chs>
static int resize_nearest(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst)
{
Size ssize = src.size();
Size dsize = dst.size();
double fx = (double)dsize.width / ssize.width;
double fy = (double)dsize.height / ssize.height;
AutoBuffer<int> _x_ofs(dsize.width);
int* x_ofs = _x_ofs;
int pix_size = (int)src.elemSize();
int pix_size4 = (int)(pix_size / sizeof(int));
double ifx = 1. / fx, ify = 1. / fy;
for (int x = 0; x < dsize.width; x++) {
int sx = fbcFloor(x*ifx);
x_ofs[x] = std::min(sx, ssize.width - 1)*pix_size;
}
Range range(0, dsize.height);
int x, y;
for (y = range.start; y < range.end; y++) {
uchar* D = dst.data + dst.step*y;
int sy = std::min(fbcFloor(y*ify), ssize.height - 1);
const uchar* S = src.ptr(sy);
switch (pix_size) {
case 1:
for (x = 0; x <= dsize.width - 2; x += 2) {
uchar t0 = S[x_ofs[x]];
uchar t1 = S[x_ofs[x + 1]];
D[x] = t0;
D[x + 1] = t1;
}
for (; x < dsize.width; x++) {
D[x] = S[x_ofs[x]];
}
break;
case 2:
for (x = 0; x < dsize.width; x++) {
*(ushort*)(D + x * 2) = *(ushort*)(S + x_ofs[x]);
}
break;
case 3:
for (x = 0; x < dsize.width; x++, D += 3) {
const uchar* _tS = S + x_ofs[x];
D[0] = _tS[0]; D[1] = _tS[1]; D[2] = _tS[2];
}
break;
case 4:
for (x = 0; x < dsize.width; x++) {
*(int*)(D + x * 4) = *(int*)(S + x_ofs[x]);
}
break;
case 6:
for (x = 0; x < dsize.width; x++, D += 6) {
const ushort* _tS = (const ushort*)(S + x_ofs[x]);
ushort* _tD = (ushort*)D;
_tD[0] = _tS[0]; _tD[1] = _tS[1]; _tD[2] = _tS[2];
}
break;
case 8:
for (x = 0; x < dsize.width; x++, D += 8) {
const int* _tS = (const int*)(S + x_ofs[x]);
int* _tD = (int*)D;
_tD[0] = _tS[0]; _tD[1] = _tS[1];
}
break;
case 12:
for (x = 0; x < dsize.width; x++, D += 12) {
const int* _tS = (const int*)(S + x_ofs[x]);
int* _tD = (int*)D;
_tD[0] = _tS[0]; _tD[1] = _tS[1]; _tD[2] = _tS[2];
}
break;
default:
for (x = 0; x < dsize.width; x++, D += pix_size) {
const int* _tS = (const int*)(S + x_ofs[x]);
int* _tD = (int*)D;
for (int k = 0; k < pix_size4; k++)
_tD[k] = _tS[k];
}
}
}
return 0;
}
template<typename _Tp, int chs>
static int resize_linear(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst)
{
Size ssize = src.size();
Size dsize = dst.size();
double inv_scale_x = (double)dsize.width / ssize.width;
double inv_scale_y = (double)dsize.height / ssize.height;
double scale_x = 1. / inv_scale_x, scale_y = 1. / inv_scale_y;
int iscale_x = saturate_cast<int>(scale_x);
int iscale_y = saturate_cast<int>(scale_y);
bool is_area_fast = std::abs(scale_x - iscale_x) < DBL_EPSILON && std::abs(scale_y - iscale_y) < DBL_EPSILON;
// in case of scale_x && scale_y is equal to 2
// INTER_AREA (fast) also is equal to INTER_LINEAR
// if (is_area_fast && iscale_x == 2 && iscale_y == 2) {
// resize_area(src, dst);
// return 0;
// }
int cn = dst.channels;
int k, sx, sy, dx, dy;
int xmin = 0, xmax = dsize.width, width = dsize.width*cn;
bool fixpt = sizeof(_Tp) == 1 ? true : false;
float fx, fy;
int ksize = 2, ksize2;
ksize2 = ksize / 2;
AutoBuffer<uchar> _buffer((width + dsize.height)*(sizeof(int) + sizeof(float)*ksize));
int* xofs = (int*)(uchar*)_buffer;
int* yofs = xofs + width;
float* alpha = (float*)(yofs + dsize.height);
short* ialpha = (short*)alpha;
float* beta = alpha + width*ksize;
short* ibeta = ialpha + width*ksize;
float cbuf[MAX_ESIZE];
for (dx = 0; dx < dsize.width; dx++) {
fx = (float)((dx + 0.5)*scale_x - 0.5);
sx = fbcFloor(fx);
fx -= sx;
if (sx < ksize2 - 1) {
xmin = dx + 1;
if (sx < 0) {
fx = 0, sx = 0;
}
}
if (sx + ksize2 >= ssize.width) {
xmax = std::min(xmax, dx);
if (sx >= ssize.width - 1) {
fx = 0, sx = ssize.width - 1;
}
}
for (k = 0, sx *= cn; k < cn; k++) {
xofs[dx*cn + k] = sx + k;
}
cbuf[0] = 1.f - fx;
cbuf[1] = fx;
if (fixpt) {
for (k = 0; k < ksize; k++) {
ialpha[dx*cn*ksize + k] = saturate_cast<short>(cbuf[k] * INTER_RESIZE_COEF_SCALE);
}
for (; k < cn*ksize; k++) {
ialpha[dx*cn*ksize + k] = ialpha[dx*cn*ksize + k - ksize];
}
} else {
for (k = 0; k < ksize; k++) {
alpha[dx*cn*ksize + k] = cbuf[k];
}
for (; k < cn*ksize; k++) {
alpha[dx*cn*ksize + k] = alpha[dx*cn*ksize + k - ksize];
}
}
}
for (dy = 0; dy < dsize.height; dy++) {
fy = (float)((dy + 0.5)*scale_y - 0.5);
sy = fbcFloor(fy);
fy -= sy;
yofs[dy] = sy;
cbuf[0] = 1.f - fy;
cbuf[1] = fy;
if (fixpt) {
for (k = 0; k < ksize; k++) {
ibeta[dy*ksize + k] = saturate_cast<short>(cbuf[k] * INTER_RESIZE_COEF_SCALE);
}
} else {
for (k = 0; k < ksize; k++) {
beta[dy*ksize + k] = cbuf[k];
}
}
}
if (sizeof(_Tp) == 1) { // uchar
typedef uchar value_type; // HResizeLinear/VResizeLinear
typedef int buf_type;
typedef short alpha_type;
int ONE = INTER_RESIZE_COEF_SCALE;
resizeGeneric_Linear<_Tp, value_type, buf_type, alpha_type, chs>(src, dst,
xofs, fixpt ? (void*)ialpha : (void*)alpha, yofs, fixpt ? (void*)ibeta : (void*)beta, xmin, xmax, ksize, ONE);
} else if (sizeof(_Tp) == 4) { // float
typedef float value_type; // HResizeLinear/VResizeLinear
typedef float buf_type;
typedef float alpha_type;
int ONE = 1;
resizeGeneric_Linear<_Tp, value_type, buf_type, alpha_type, chs>(src, dst,
xofs, fixpt ? (void*)ialpha : (void*)alpha, yofs, fixpt ? (void*)ibeta : (void*)beta, xmin, xmax, ksize, ONE);
} else {
fprintf(stderr, "not support type\n");
return -1;
}
return 0;
}
} // namespace yt_tinycv
#endif // FBC_CV_RESIZE_HPP_

View File

@@ -0,0 +1,64 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_SATURATE_HPP_
#define FBC_CV_CORE_SATURATE_HPP_
// reference: include/opencv2/core/saturate.hpp
#include <algorithm>
#include <limits.h>
#include "fbcdef.hpp"
#include "interface.hpp"
#include "fast_math.hpp"
namespace yt_tinycv
{
template<typename _Tp> static inline _Tp saturate_cast(uchar v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(schar v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(ushort v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(short v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(unsigned int v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(int v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(float v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(double v) { return _Tp(v); }
template<> inline uchar saturate_cast<uchar>(schar v) { return (uchar)std::max((int)v, 0); }
template<> inline uchar saturate_cast<uchar>(ushort v) { return (uchar)std::min((unsigned)v, (unsigned)UCHAR_MAX); }
template<> inline uchar saturate_cast<uchar>(int v) { return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); }
template<> inline uchar saturate_cast<uchar>(short v) { return saturate_cast<uchar>((int)v); }
template<> inline uchar saturate_cast<uchar>(unsigned int v) { return (uchar)std::min(v, (unsigned)UCHAR_MAX); }
template<> inline uchar saturate_cast<uchar>(float v) { int iv = fbcRound(v); return saturate_cast<uchar>(iv); }
template<> inline uchar saturate_cast<uchar>(double v) { int iv = fbcRound(v); return saturate_cast<uchar>(iv); }
template<> inline schar saturate_cast<schar>(uchar v) { return (schar)std::min((int)v, SCHAR_MAX); }
template<> inline schar saturate_cast<schar>(ushort v) { return (schar)std::min((unsigned)v, (unsigned)SCHAR_MAX); }
template<> inline schar saturate_cast<schar>(int v) { return (schar)((unsigned)(v-SCHAR_MIN) <= (unsigned)UCHAR_MAX ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN); }
template<> inline schar saturate_cast<schar>(short v) { return saturate_cast<schar>((int)v); }
template<> inline schar saturate_cast<schar>(unsigned v) { return (schar)std::min(v, (unsigned)SCHAR_MAX); }
template<> inline schar saturate_cast<schar>(float v) { int iv = fbcRound(v); return saturate_cast<schar>(iv); }
template<> inline schar saturate_cast<schar>(double v) { int iv = fbcRound(v); return saturate_cast<schar>(iv); }
template<> inline ushort saturate_cast<ushort>(schar v) { return (ushort)std::max((int)v, 0); }
template<> inline ushort saturate_cast<ushort>(short v) { return (ushort)std::max((int)v, 0); }
template<> inline ushort saturate_cast<ushort>(int v) { return (ushort)((unsigned)v <= (unsigned)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); }
template<> inline ushort saturate_cast<ushort>(unsigned v) { return (ushort)std::min(v, (unsigned)USHRT_MAX); }
template<> inline ushort saturate_cast<ushort>(float v) { int iv = fbcRound(v); return saturate_cast<ushort>(iv); }
template<> inline ushort saturate_cast<ushort>(double v) { int iv = fbcRound(v); return saturate_cast<ushort>(iv); }
template<> inline short saturate_cast<short>(ushort v) { return (short)std::min((int)v, SHRT_MAX); }
template<> inline short saturate_cast<short>(int v) { return (short)((unsigned)(v - SHRT_MIN) <= (unsigned)USHRT_MAX ? v : v > 0 ? SHRT_MAX : SHRT_MIN); }
template<> inline short saturate_cast<short>(unsigned v) { return (short)std::min(v, (unsigned)SHRT_MAX); }
template<> inline short saturate_cast<short>(float v) { int iv = fbcRound(v); return saturate_cast<short>(iv); }
template<> inline short saturate_cast<short>(double v) { int iv = fbcRound(v); return saturate_cast<short>(iv); }
template<> inline int saturate_cast<int>(float v) { return fbcRound(v); }
template<> inline int saturate_cast<int>(double v) { return fbcRound(v); }
template<> inline unsigned saturate_cast<unsigned>(float v) { return fbcRound(v); }
template<> inline unsigned saturate_cast<unsigned>(double v) { return fbcRound(v); }
} // yt_tinycv
#endif // FBC_CV_CORE_SATURATE_HPP_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,189 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_UTILITY_HPP_
#define FBC_CV_CORE_UTILITY_HPP_
// reference: include/opencv2/core/utility.hpp
#ifndef __cplusplus
#error utility.hpp header must be compiled as C++
#endif
#include "fbcdef.hpp"
#include "base.hpp"
namespace yt_tinycv {
// The function returns the aligned pointer of the same type as the input pointer
template<typename _Tp> static inline _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp))
{
return (_Tp*)(((size_t)ptr + n - 1) & -n);
}
// The function returns the minimum number that is greater or equal to sz and is divisible by n
static inline size_t alignSize(size_t sz, int n)
{
FBC_Assert((n & (n - 1)) == 0); // n is a power of 2
return (sz + n - 1) & -n;
}
// Automatically Allocated Buffer Class
// The class is used for temporary buffers in functions and methods.
template<typename _Tp, size_t fixed_size = 1024 / sizeof(_Tp) + 8> class AutoBuffer {
public:
typedef _Tp value_type;
// the default constructor
AutoBuffer();
// constructor taking the real buffer size
AutoBuffer(size_t _size);
// the copy constructor
AutoBuffer(const AutoBuffer<_Tp, fixed_size>& buf);
// the assignment operator
AutoBuffer<_Tp, fixed_size>& operator = (const AutoBuffer<_Tp, fixed_size>& buf);
// destructor. calls deallocate()
~AutoBuffer();
// allocates the new buffer of size _size. if the _size is small enough, stack-allocated buffer is used
void allocate(size_t _size);
// deallocates the buffer if it was dynamically allocated
void deallocate();
// resizes the buffer and preserves the content
void resize(size_t _size);
// returns the current buffer size
size_t size() const;
// returns pointer to the real buffer, stack-allocated or head-allocated
operator _Tp* ();
// returns read-only pointer to the real buffer, stack-allocated or head-allocated
operator const _Tp* () const;
protected:
// pointer to the real buffer, can point to buf if the buffer is small enough
_Tp* ptr;
// size of the real buffer
size_t sz;
//! pre-allocated buffer. At least 1 element to confirm C++ standard reqirements
_Tp buf[(fixed_size > 0) ? fixed_size : 1];
};
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::AutoBuffer()
{
ptr = buf;
sz = fixed_size;
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::AutoBuffer(size_t _size)
{
ptr = buf;
sz = fixed_size;
allocate(_size);
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::AutoBuffer(const AutoBuffer<_Tp, fixed_size>& abuf)
{
ptr = buf;
sz = fixed_size;
allocate(abuf.size());
for (size_t i = 0; i < sz; i++) {
ptr[i] = abuf.ptr[i];
}
}
template<typename _Tp, size_t fixed_size> inline AutoBuffer<_Tp, fixed_size>&
AutoBuffer<_Tp, fixed_size>::operator = (const AutoBuffer<_Tp, fixed_size>& abuf)
{
if (this != &abuf) {
deallocate();
allocate(abuf.size());
for (size_t i = 0; i < sz; i++) {
ptr[i] = abuf.ptr[i];
}
}
return *this;
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::~AutoBuffer()
{
deallocate();
}
template<typename _Tp, size_t fixed_size> inline void
AutoBuffer<_Tp, fixed_size>::allocate(size_t _size)
{
if (_size <= sz) {
sz = _size;
return;
}
deallocate();
if (_size > fixed_size) {
ptr = new _Tp[_size];
sz = _size;
}
}
template<typename _Tp, size_t fixed_size> inline void
AutoBuffer<_Tp, fixed_size>::deallocate()
{
if (ptr != buf) {
delete[] ptr;
ptr = buf;
sz = fixed_size;
}
}
template<typename _Tp, size_t fixed_size> inline void
AutoBuffer<_Tp, fixed_size>::resize(size_t _size)
{
if (_size <= sz) {
sz = _size;
return;
}
size_t i, prevsize = sz, minsize = MIN(prevsize, _size);
_Tp* prevptr = ptr;
ptr = _size > fixed_size ? new _Tp[_size] : buf;
sz = _size;
if (ptr != prevptr) {
for (i = 0; i < minsize; i++) {
ptr[i] = prevptr[i];
}
}
for (i = prevsize; i < _size; i++) {
ptr[i] = _Tp();
}
if (prevptr != buf) {
delete[] prevptr;
}
}
template<typename _Tp, size_t fixed_size> inline size_t
AutoBuffer<_Tp, fixed_size>::size() const
{
return sz;
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::operator _Tp* ()
{
return ptr;
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::operator const _Tp* () const
{
return ptr;
}
} // yt_tinycv
#endif // FBC_CV_CORE_UTILITY_HPP_

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>YTCv</string>
<key>CFBundleIdentifier</key>
<string>com.tencent.youtu.cv</string>
<key>CFBundleExecutable</key>
<string>YTCv</string>
<key>CFBundleVersion</key>
<string>v0.0.7-2-g3bdc755</string>
<key>CFBundleShortVersionString</key>
<string>v0.0.7-2-g3bdc755</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
</dict>
</plist>