1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Alekhin
2021-04-09 10:30:38 +00:00
1114 changed files with 64039 additions and 14611 deletions
+4 -1
View File
@@ -50,7 +50,6 @@
#endif
#include "opencv2/core/cvdef.h"
#include "opencv2/core/version.hpp"
#include "opencv2/core/base.hpp"
#include "opencv2/core/cvstd.hpp"
#include "opencv2/core/traits.hpp"
@@ -97,6 +96,10 @@
@}
@defgroup core_lowlevel_api Low-level API for external libraries / plugins
@}
@defgroup core_parallel Parallel Processing
@{
@defgroup core_parallel_backend Parallel backends API
@}
@}
*/
@@ -538,6 +538,16 @@ _AccTp normInf(const _Tp* a, const _Tp* b, int n)
*/
CV_EXPORTS_W float cubeRoot(float val);
/** @overload
cubeRoot with argument of `double` type calls `std::cbrt(double)`
*/
static inline
double cubeRoot(double val)
{
return std::cbrt(val);
}
/** @brief Calculates the angle of a 2D vector in degrees.
The function fastAtan2 calculates the full-range angle of an input 2D vector. The angle is measured
@@ -7,6 +7,9 @@
#include <opencv2/core/async.hpp>
#include <opencv2/core/detail/async_promise.hpp>
#include <opencv2/core/utils/logger.hpp>
#include <stdexcept>
namespace cv { namespace utils {
//! @addtogroup core_utils
@@ -58,6 +61,67 @@ String dumpCString(const char* argument)
return cv::format("String: %s", argument);
}
CV_WRAP static inline
String dumpString(const String& argument)
{
return cv::format("String: %s", argument.c_str());
}
CV_WRAP static inline
String testOverloadResolution(int value, const Point& point = Point(42, 24))
{
return format("overload (int=%d, point=(x=%d, y=%d))", value, point.x,
point.y);
}
CV_WRAP static inline
String testOverloadResolution(const Rect& rect)
{
return format("overload (rect=(x=%d, y=%d, w=%d, h=%d))", rect.x, rect.y,
rect.width, rect.height);
}
CV_WRAP static inline
String dumpRect(const Rect& argument)
{
return format("rect: (x=%d, y=%d, w=%d, h=%d)", argument.x, argument.y,
argument.width, argument.height);
}
CV_WRAP static inline
String dumpTermCriteria(const TermCriteria& argument)
{
return format("term_criteria: (type=%d, max_count=%d, epsilon=%lf",
argument.type, argument.maxCount, argument.epsilon);
}
CV_WRAP static inline
String dumpRotatedRect(const RotatedRect& argument)
{
return format("rotated_rect: (c_x=%f, c_y=%f, w=%f, h=%f, a=%f)",
argument.center.x, argument.center.y, argument.size.width,
argument.size.height, argument.angle);
}
CV_WRAP static inline
String dumpRange(const Range& argument)
{
if (argument == Range::all())
{
return "range: all";
}
else
{
return format("range: (s=%d, e=%d)", argument.start, argument.end);
}
}
CV_WRAP static inline
void testRaiseGeneralException()
{
throw std::runtime_error("exception text");
}
CV_WRAP static inline
AsyncArray testAsyncArray(InputArray argument)
{
@@ -81,7 +145,30 @@ AsyncArray testAsyncException()
return p.getArrayResult();
}
//! @}
}} // namespace
namespace fs {
CV_EXPORTS_W cv::String getCacheDirectoryForDownloads();
} // namespace fs
//! @} // core_utils
} // namespace cv::utils
//! @cond IGNORED
CV_WRAP static inline
int setLogLevel(int level)
{
// NB: Binding generators doesn't work with enums properly yet, so we define separate overload here
return cv::utils::logging::setLogLevel((cv::utils::logging::LogLevel)level);
}
CV_WRAP static inline
int getLogLevel()
{
return cv::utils::logging::getLogLevel();
}
//! @endcond IGNORED
} // namespaces cv / utils
#endif // OPENCV_CORE_BINDINGS_UTILS_HPP
+215
View File
@@ -340,6 +340,209 @@ public:
Allocator* allocator;
};
struct CV_EXPORTS_W GpuData
{
explicit GpuData(size_t _size);
~GpuData();
GpuData(const GpuData&) = delete;
GpuData& operator=(const GpuData&) = delete;
GpuData(GpuData&&) = delete;
GpuData& operator=(GpuData&&) = delete;
uchar* data;
size_t size;
};
class CV_EXPORTS_W GpuMatND
{
public:
using SizeArray = std::vector<int>;
using StepArray = std::vector<size_t>;
using IndexArray = std::vector<int>;
//! destructor
~GpuMatND();
//! default constructor
GpuMatND();
/** @overload
@param size Array of integers specifying an n-dimensional array shape.
@param type Array type. Use CV_8UC1, ..., CV_16FC4 to create 1-4 channel matrices, or
CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices.
*/
GpuMatND(SizeArray size, int type);
/** @overload
@param size Array of integers specifying an n-dimensional array shape.
@param type Array type. Use CV_8UC1, ..., CV_16FC4 to create 1-4 channel matrices, or
CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices.
@param data Pointer to the user data. Matrix constructors that take data and step parameters do not
allocate matrix data. Instead, they just initialize the matrix header that points to the specified
data, which means that no data is copied. This operation is very efficient and can be used to
process external data using OpenCV functions. The external data is not automatically deallocated, so
you should take care of it.
@param step Array of _size.size()-1 steps in case of a multi-dimensional array (the last step is always
set to the element size). If not specified, the matrix is assumed to be continuous.
*/
GpuMatND(SizeArray size, int type, void* data, StepArray step = StepArray());
/** @brief Allocates GPU memory.
Suppose there is some GPU memory already allocated. In that case, this method may choose to reuse that
GPU memory under the specific condition: it must be of the same size and type, not externally allocated,
the GPU memory is continuous(i.e., isContinuous() is true), and is not a sub-matrix of another GpuMatND
(i.e., isSubmatrix() is false). In other words, this method guarantees that the GPU memory allocated by
this method is always continuous and is not a sub-region of another GpuMatND.
*/
void create(SizeArray size, int type);
void release();
void swap(GpuMatND& m) noexcept;
/** @brief Creates a full copy of the array and the underlying data.
The method creates a full copy of the array. It mimics the behavior of Mat::clone(), i.e.
the original step is not taken into account. So, the array copy is a continuous array
occupying total()\*elemSize() bytes.
*/
GpuMatND clone() const;
/** @overload
This overload is non-blocking, so it may return even if the copy operation is not finished.
*/
GpuMatND clone(Stream& stream) const;
/** @brief Extracts a sub-matrix.
The operator makes a new header for the specified sub-array of \*this.
The operator is an O(1) operation, that is, no matrix data is copied.
@param ranges Array of selected ranges along each dimension.
*/
GpuMatND operator()(const std::vector<Range>& ranges) const;
/** @brief Creates a GpuMat header for a 2D plane part of an n-dim matrix.
@note The returned GpuMat is constructed with the constructor for user-allocated data.
That is, It does not perform reference counting.
@note This function does not increment this GpuMatND's reference counter.
*/
GpuMat createGpuMatHeader(IndexArray idx, Range rowRange, Range colRange) const;
/** @overload
Creates a GpuMat header if this GpuMatND is effectively 2D.
@note The returned GpuMat is constructed with the constructor for user-allocated data.
That is, It does not perform reference counting.
@note This function does not increment this GpuMatND's reference counter.
*/
GpuMat createGpuMatHeader() const;
/** @brief Extracts a 2D plane part of an n-dim matrix.
It differs from createGpuMatHeader(IndexArray, Range, Range) in that it clones a part of this
GpuMatND to the returned GpuMat.
@note This operator does not increment this GpuMatND's reference counter;
*/
GpuMat operator()(IndexArray idx, Range rowRange, Range colRange) const;
/** @brief Extracts a 2D plane part of an n-dim matrix if this GpuMatND is effectively 2D.
It differs from createGpuMatHeader() in that it clones a part of this GpuMatND.
@note This operator does not increment this GpuMatND's reference counter;
*/
operator GpuMat() const;
GpuMatND(const GpuMatND&) = default;
GpuMatND& operator=(const GpuMatND&) = default;
#if defined(__GNUC__) && __GNUC__ < 5
// error: function '...' defaulted on its first declaration with an exception-specification
// that differs from the implicit declaration '...'
GpuMatND(GpuMatND&&) = default;
GpuMatND& operator=(GpuMatND&&) = default;
#else
GpuMatND(GpuMatND&&) noexcept = default;
GpuMatND& operator=(GpuMatND&&) noexcept = default;
#endif
void upload(InputArray src);
void upload(InputArray src, Stream& stream);
void download(OutputArray dst) const;
void download(OutputArray dst, Stream& stream) const;
//! returns true iff the GpuMatND data is continuous
//! (i.e. when there are no gaps between successive rows)
bool isContinuous() const;
//! returns true if the matrix is a sub-matrix of another matrix
bool isSubmatrix() const;
//! returns element size in bytes
size_t elemSize() const;
//! returns the size of element channel in bytes
size_t elemSize1() const;
//! returns true if data is null
bool empty() const;
//! returns true if not empty and points to external(user-allocated) gpu memory
bool external() const;
//! returns pointer to the first byte of the GPU memory
uchar* getDevicePtr() const;
//! returns the total number of array elements
size_t total() const;
//! returns the size of underlying memory in bytes
size_t totalMemSize() const;
//! returns element type
int type() const;
private:
//! internal use
void setFields(SizeArray size, int type, StepArray step = StepArray());
public:
/*! includes several bit-fields:
- the magic signature
- continuity flag
- depth
- number of channels
*/
int flags;
//! matrix dimensionality
int dims;
//! shape of this array
SizeArray size;
/*! step values
Their semantics is identical to the semantics of step for Mat.
*/
StepArray step;
private:
/*! internal use
If this GpuMatND holds external memory, this is empty.
*/
std::shared_ptr<GpuData> data_;
/*! internal use
If this GpuMatND manages memory with reference counting, this value is
always equal to data_->data. If this GpuMatND holds external memory,
data_ is empty and data points to the external memory.
*/
uchar* data;
/*! internal use
If this GpuMatND is a sub-matrix of a larger matrix, this value is the
difference of the first byte between the sub-matrix and the whole matrix.
*/
size_t offset;
};
/** @brief Creates a continuous matrix.
@param rows Row count.
@@ -656,6 +859,18 @@ public:
//! creates a new asynchronous stream with custom allocator
CV_WRAP Stream(const Ptr<GpuMat::Allocator>& allocator);
/** @brief creates a new Stream using the cudaFlags argument to determine the behaviors of the stream
@note The cudaFlags parameter is passed to the underlying api cudaStreamCreateWithFlags() and
supports the same parameter values.
@code
// creates an OpenCV cuda::Stream that manages an asynchronous, non-blocking,
// non-default CUDA stream
cv::cuda::Stream cvStream(cudaStreamNonBlocking);
@endcode
*/
CV_WRAP Stream(const size_t cudaFlags);
/** @brief Returns true if the current stream queue is finished. Otherwise, it returns false.
*/
CV_WRAP bool queryIfComplete() const;
@@ -383,6 +383,92 @@ void swap(GpuMat& a, GpuMat& b)
a.swap(b);
}
//===================================================================================
// GpuMatND
//===================================================================================
inline
GpuMatND::GpuMatND() :
flags(0), dims(0), data(nullptr), offset(0)
{
}
inline
GpuMatND::GpuMatND(SizeArray _size, int _type) :
flags(0), dims(0), data(nullptr), offset(0)
{
create(std::move(_size), _type);
}
inline
void GpuMatND::swap(GpuMatND& m) noexcept
{
std::swap(*this, m);
}
inline
bool GpuMatND::isContinuous() const
{
return (flags & Mat::CONTINUOUS_FLAG) != 0;
}
inline
bool GpuMatND::isSubmatrix() const
{
return (flags & Mat::SUBMATRIX_FLAG) != 0;
}
inline
size_t GpuMatND::elemSize() const
{
return CV_ELEM_SIZE(flags);
}
inline
size_t GpuMatND::elemSize1() const
{
return CV_ELEM_SIZE1(flags);
}
inline
bool GpuMatND::empty() const
{
return data == nullptr;
}
inline
bool GpuMatND::external() const
{
return !empty() && data_.use_count() == 0;
}
inline
uchar* GpuMatND::getDevicePtr() const
{
return data + offset;
}
inline
size_t GpuMatND::total() const
{
size_t p = 1;
for(auto s : size)
p *= s;
return p;
}
inline
size_t GpuMatND::totalMemSize() const
{
return size[0] * step[0];
}
inline
int GpuMatND::type() const
{
return CV_MAT_TYPE(flags);
}
//===================================================================================
// HostMem
//===================================================================================
@@ -170,6 +170,7 @@
#if defined CV_CPU_COMPILE_RVV
# define CV_RVV 1
# include <riscv_vector.h>
#endif
#endif // CV_ENABLE_INTRINSICS && !CV_DISABLE_OPTIMIZATION && !__CUDACC__
@@ -45,6 +45,8 @@
#ifndef OPENCV_CORE_CVDEF_H
#define OPENCV_CORE_CVDEF_H
#include "opencv2/core/version.hpp"
//! @addtogroup core_utils
//! @{
@@ -388,7 +390,9 @@ typedef union Cv64suf
}
Cv64suf;
#ifndef OPENCV_ABI_COMPATIBILITY
#define OPENCV_ABI_COMPATIBILITY 400
#endif
#ifdef __OPENCV_BUILD
# define DISABLE_OPENCV_3_COMPATIBILITY
@@ -0,0 +1,979 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2020, Huawei Technologies Co., Ltd. All rights reserved.
// Third party copyrights are property of their respective owners.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Liangqian Kong <kongliangqian@huawei.com>
// Longbu Wang <wanglongbu@huawei.com>
#ifndef OPENCV_CORE_DUALQUATERNION_HPP
#define OPENCV_CORE_DUALQUATERNION_HPP
#include <opencv2/core/quaternion.hpp>
#include <opencv2/core/affine.hpp>
namespace cv{
//! @addtogroup core
//! @{
template <typename _Tp> class DualQuat;
template <typename _Tp> std::ostream& operator<<(std::ostream&, const DualQuat<_Tp>&);
/**
* Dual quaternions were introduced to describe rotation together with translation while ordinary
* quaternions can only describe rotation. It can be used for shortest path pose interpolation,
* local pose optimization or volumetric deformation. More details can be found
* - https://en.wikipedia.org/wiki/Dual_quaternion
* - ["A beginners guide to dual-quaternions: what they are, how they work, and how to use them for 3D character hierarchies", Ben Kenwright, 2012](https://borodust.org/public/shared/beginner_dual_quats.pdf)
* - ["Dual Quaternions", Yan-Bin Jia, 2013](http://web.cs.iastate.edu/~cs577/handouts/dual-quaternion.pdf)
* - ["Geometric Skinning with Approximate Dual Quaternion Blending", Kavan, 2008](https://www.cs.utah.edu/~ladislav/kavan08geometric/kavan08geometric)
* - http://rodolphe-vaillant.fr/?e=29
*
* A unit dual quaternion can be classically represented as:
* \f[
* \begin{equation}
* \begin{split}
* \sigma &= \left(r+\frac{\epsilon}{2}tr\right)\\
* &= [w, x, y, z, w\_, x\_, y\_, z\_]
* \end{split}
* \end{equation}
* \f]
* where \f$r, t\f$ represents the rotation (ordinary unit quaternion) and translation (pure ordinary quaternion) respectively.
*
* A general dual quaternions which consist of two quaternions is usually represented in form of:
* \f[
* \sigma = p + \epsilon q
* \f]
* where the introduced dual unit \f$\epsilon\f$ satisfies \f$\epsilon^2 = \epsilon^3 =...=0\f$, and \f$p, q\f$ are quaternions.
*
* Alternatively, dual quaternions can also be interpreted as four components which are all [dual numbers](https://www.cs.utah.edu/~ladislav/kavan08geometric/kavan08geometric):
* \f[
* \sigma = \hat{q}_w + \hat{q}_xi + \hat{q}_yj + \hat{q}_zk
* \f]
* If we set \f$\hat{q}_x, \hat{q}_y\f$ and \f$\hat{q}_z\f$ equal to 0, a dual quaternion is transformed to a dual number. see normalize().
*
* If you want to create a dual quaternion, you can use:
*
* ```
* using namespace cv;
* double angle = CV_PI;
*
* // create from eight number
* DualQuatd dq1(1, 2, 3, 4, 5, 6, 7, 8); //p = [1,2,3,4]. q=[5,6,7,8]
*
* // create from Vec
* Vec<double, 8> v{1,2,3,4,5,6,7,8};
* DualQuatd dq_v{v};
*
* // create from two quaternion
* Quatd p(1, 2, 3, 4);
* Quatd q(5, 6, 7, 8);
* DualQuatd dq2 = DualQuatd::createFromQuat(p, q);
*
* // create from an angle, an axis and a translation
* Vec3d axis{0, 0, 1};
* Vec3d trans{3, 4, 5};
* DualQuatd dq3 = DualQuatd::createFromAngleAxisTrans(angle, axis, trans);
*
* // If you already have an instance of class Affine3, then you can use
* Affine3d R = dq3.toAffine3();
* DualQuatd dq4 = DualQuatd::createFromAffine3(R);
*
* // or create directly by affine transformation matrix Rt
* // see createFromMat() in detail for the form of Rt
* Matx44d Rt = dq3.toMat();
* DualQuatd dq5 = DualQuatd::createFromMat(Rt);
*
* // Any rotation + translation movement can
* // be expressed as a rotation + translation around the same line in space (expressed by Plucker
* // coords), and here's a way to represent it this way.
* Vec3d axis{1, 1, 1}; // axis will be normalized in createFromPitch
* Vec3d trans{3, 4 ,5};
* axis = axis / std::sqrt(axis.dot(axis));// The formula for computing moment that I use below requires a normalized axis
* Vec3d moment = 1.0 / 2 * (trans.cross(axis) + axis.cross(trans.cross(axis)) *
* std::cos(rotation_angle / 2) / std::sin(rotation_angle / 2));
* double d = trans.dot(qaxis);
* DualQuatd dq6 = DualQuatd::createFromPitch(angle, d, axis, moment);
* ```
*
* A point \f$v=(x, y, z)\f$ in form of dual quaternion is \f$[1+\epsilon v]=[1,0,0,0,0,x,y,z]\f$.
* The transformation of a point \f$v_1\f$ to another point \f$v_2\f$ under the dual quaternion \f$\sigma\f$ is
* \f[
* 1 + \epsilon v_2 = \sigma * (1 + \epsilon v_1) * \sigma^{\star}
* \f]
* where \f$\sigma^{\star}=p^*-\epsilon q^*.\f$
*
* A line in the \f$Pl\ddot{u}cker\f$ coordinates \f$(\hat{l}, m)\f$ defined by the dual quaternion \f$l=\hat{l}+\epsilon m\f$.
* To transform a line, \f[l_2 = \sigma * l_1 * \sigma^*,\f] where \f$\sigma=r+\frac{\epsilon}{2}rt\f$ and
* \f$\sigma^*=p^*+\epsilon q^*\f$.
*
* To extract the Vec<double, 8> or Vec<float, 8>, see toVec();
*
* To extract the affine transformation matrix, see toMat();
*
* To extract the instance of Affine3, see toAffine3();
*
* If two quaternions \f$q_0, q_1\f$ are needed to be interpolated, you can use sclerp()
* ```
* DualQuatd::sclerp(q0, q1, t)
* ```
* or dqblend().
* ```
* DualQuatd::dqblend(q0, q1, t)
* ```
* With more than two dual quaternions to be blended, you can use generalize linear dual quaternion blending
* with the corresponding weights, i.e. gdqblend().
*
*/
template <typename _Tp>
class CV_EXPORTS DualQuat{
static_assert(std::is_floating_point<_Tp>::value, "Dual quaternion only make sense with type of float or double");
using value_type = _Tp;
public:
static constexpr _Tp CV_DUAL_QUAT_EPS = (_Tp)1.e-6;
DualQuat();
/**
* @brief create from eight same type numbers.
*/
DualQuat(const _Tp w, const _Tp x, const _Tp y, const _Tp z, const _Tp w_, const _Tp x_, const _Tp y_, const _Tp z_);
/**
* @brief create from a double or float vector.
*/
DualQuat(const Vec<_Tp, 8> &q);
_Tp w, x, y, z, w_, x_, y_, z_;
/**
* @brief create Dual Quaternion from two same type quaternions p and q.
* A Dual Quaternion \f$\sigma\f$ has the form:
* \f[\sigma = p + \epsilon q\f]
* where p and q are defined as follows:
* \f[\begin{equation}
* \begin{split}
* p &= w + x\boldsymbol{i} + y\boldsymbol{j} + z\boldsymbol{k}\\
* q &= w\_ + x\_\boldsymbol{i} + y\_\boldsymbol{j} + z\_\boldsymbol{k}.
* \end{split}
* \end{equation}
* \f]
* The p and q are the real part and dual part respectively.
* @param realPart a quaternion, real part of dual quaternion.
* @param dualPart a quaternion, dual part of dual quaternion.
* @sa Quat
*/
static DualQuat<_Tp> createFromQuat(const Quat<_Tp> &realPart, const Quat<_Tp> &dualPart);
/**
* @brief create a dual quaternion from a rotation angle \f$\theta\f$, a rotation axis
* \f$\boldsymbol{u}\f$ and a translation \f$\boldsymbol{t}\f$.
* It generates a dual quaternion \f$\sigma\f$ in the form of
* \f[\begin{equation}
* \begin{split}
* \sigma &= r + \frac{\epsilon}{2}\boldsymbol{t}r \\
* &= [\cos(\frac{\theta}{2}), \boldsymbol{u}\sin(\frac{\theta}{2})]
* + \frac{\epsilon}{2}[0, \boldsymbol{t}][[\cos(\frac{\theta}{2}),
* \boldsymbol{u}\sin(\frac{\theta}{2})]]\\
* &= \cos(\frac{\theta}{2}) + \boldsymbol{u}\sin(\frac{\theta}{2})
* + \frac{\epsilon}{2}(-(\boldsymbol{t} \cdot \boldsymbol{u})\sin(\frac{\theta}{2})
* + \boldsymbol{t}\cos(\frac{\theta}{2}) + \boldsymbol{u} \times \boldsymbol{t} \sin(\frac{\theta}{2})).
* \end{split}
* \end{equation}\f]
* @param angle rotation angle.
* @param axis rotation axis.
* @param translation a vector of length 3.
* @note Axis will be normalized in this function. And translation is applied
* after the rotation. Use @ref createFromQuat(r, r * t / 2) to create a dual quaternion
* which translation is applied before rotation.
* @sa Quat
*/
static DualQuat<_Tp> createFromAngleAxisTrans(const _Tp angle, const Vec<_Tp, 3> &axis, const Vec<_Tp, 3> &translation);
/**
* @brief Transform this dual quaternion to an affine transformation matrix \f$M\f$.
* Dual quaternion consists of a rotation \f$r=[a,b,c,d]\f$ and a translation \f$t=[\Delta x,\Delta y,\Delta z]\f$. The
* affine transformation matrix \f$M\f$ has the form
* \f[
* \begin{bmatrix}
* 1-2(e_2^2 +e_3^2) &2(e_1e_2-e_0e_3) &2(e_0e_2+e_1e_3) &\Delta x\\
* 2(e_0e_3+e_1e_2) &1-2(e_1^2+e_3^2) &2(e_2e_3-e_0e_1) &\Delta y\\
* 2(e_1e_3-e_0e_2) &2(e_0e_1+e_2e_3) &1-2(e_1^2-e_2^2) &\Delta z\\
* 0&0&0&1
* \end{bmatrix}
* \f]
* if A is a matrix consisting of n points to be transformed, this could be achieved by
* \f[
* new\_A = M * A
* \f]
* where A has the form
* \f[
* \begin{bmatrix}
* x_0& x_1& x_2&...&x_n\\
* y_0& y_1& y_2&...&y_n\\
* z_0& z_1& z_2&...&z_n\\
* 1&1&1&...&1
* \end{bmatrix}
* \f]
* where the same subscript represent the same point. The size of A should be \f$[4,n]\f$.
* and the same size for matrix new_A.
* @param _R 4x4 matrix that represents rotations and translation.
* @note Translation is applied after the rotation. Use createFromQuat(r, r * t / 2) to create
* a dual quaternion which translation is applied before rotation.
*/
static DualQuat<_Tp> createFromMat(InputArray _R);
/**
* @brief create dual quaternion from an affine matrix. The definition of affine matrix can refer to createFromMat()
*/
static DualQuat<_Tp> createFromAffine3(const Affine3<_Tp> &R);
/**
* @brief A dual quaternion is a vector in form of
* \f[
* \begin{equation}
* \begin{split}
* \sigma &=\boldsymbol{p} + \epsilon \boldsymbol{q}\\
* &= \cos\hat{\frac{\theta}{2}}+\overline{\hat{l}}\sin\frac{\hat{\theta}}{2}
* \end{split}
* \end{equation}
* \f]
* where \f$\hat{\theta}\f$ is dual angle and \f$\overline{\hat{l}}\f$ is dual axis:
* \f[
* \hat{\theta}=\theta + \epsilon d,\\
* \overline{\hat{l}}= \hat{l} +\epsilon m.
* \f]
* In this representation, \f$\theta\f$ is rotation angle and \f$(\hat{l},m)\f$ is the screw axis, d is the translation distance along the axis.
*
* @param angle rotation angle.
* @param d translation along the rotation axis.
* @param axis rotation axis represented by quaternion with w = 0.
* @param moment the moment of line, and it should be orthogonal to axis.
* @note Translation is applied after the rotation. Use createFromQuat(r, r * t / 2) to create
* a dual quaternion which translation is applied before rotation.
*/
static DualQuat<_Tp> createFromPitch(const _Tp angle, const _Tp d, const Vec<_Tp, 3> &axis, const Vec<_Tp, 3> &moment);
/**
* @brief return a quaternion which represent the real part of dual quaternion.
* The definition of real part is in createFromQuat().
* @sa createFromQuat, getDualPart
*/
Quat<_Tp> getRealPart() const;
/**
* @brief return a quaternion which represent the dual part of dual quaternion.
* The definition of dual part is in createFromQuat().
* @sa createFromQuat, getRealPart
*/
Quat<_Tp> getDualPart() const;
/**
* @brief return the conjugate of a dual quaternion.
* \f[
* \begin{equation}
* \begin{split}
* \sigma^* &= (p + \epsilon q)^*
* &= (p^* + \epsilon q^*)
* \end{split}
* \end{equation}
* \f]
* @param dq a dual quaternion.
*/
template <typename T>
friend DualQuat<T> conjugate(const DualQuat<T> &dq);
/**
* @brief return the conjugate of a dual quaternion.
* \f[
* \begin{equation}
* \begin{split}
* \sigma^* &= (p + \epsilon q)^*
* &= (p^* + \epsilon q^*)
* \end{split}
* \end{equation}
* \f]
*/
DualQuat<_Tp> conjugate() const;
/**
* @brief return the rotation in quaternion form.
*/
Quat<_Tp> getRotation(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
/**
* @brief return the translation vector.
* The rotation \f$r\f$ in this dual quaternion \f$\sigma\f$ is applied before translation \f$t\f$.
* The dual quaternion \f$\sigma\f$ is defined as
* \f[\begin{equation}
* \begin{split}
* \sigma &= p + \epsilon q \\
* &= r + \frac{\epsilon}{2}{t}r.
* \end{split}
* \end{equation}\f]
* Thus, the translation can be obtained as follows
* \f[t = 2qp^*.\f]
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion
* and this function will save some computations.
* @note This dual quaternion's translation is applied after the rotation.
*/
Vec<_Tp, 3> getTranslation(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
/**
* @brief return the norm \f$||\sigma||\f$ of dual quaternion \f$\sigma = p + \epsilon q\f$.
* \f[
* \begin{equation}
* \begin{split}
* ||\sigma|| &= \sqrt{\sigma * \sigma^*} \\
* &= ||p|| + \epsilon \frac{p \cdot q}{||p||}.
* \end{split}
* \end{equation}
* \f]
* Generally speaking, the norm of a not unit dual
* quaternion is a dual number. For convenience, we return it in the form of a dual quaternion
* , i.e.
* \f[ ||\sigma|| = [||p||, 0, 0, 0, \frac{p \cdot q}{||p||}, 0, 0, 0].\f]
*
* @note The data type of dual number is dual quaternion.
*/
DualQuat<_Tp> norm() const;
/**
* @brief return a normalized dual quaternion.
* A dual quaternion can be expressed as
* \f[
* \begin{equation}
* \begin{split}
* \sigma &= p + \epsilon q\\
* &=||\sigma||\left(r+\frac{1}{2}tr\right)
* \end{split}
* \end{equation}
* \f]
* where \f$r, t\f$ represents the rotation (ordinary quaternion) and translation (pure ordinary quaternion) respectively,
* and \f$||\sigma||\f$ is the norm of dual quaternion(a dual number).
* A dual quaternion is unit if and only if
* \f[
* ||p||=1, p \cdot q=0
* \f]
* where \f$\cdot\f$ means dot product.
* The process of normalization is
* \f[
* \sigma_{u}=\frac{\sigma}{||\sigma||}
* \f]
* Next, we simply proof \f$\sigma_u\f$ is a unit dual quaternion:
* \f[
* \renewcommand{\Im}{\operatorname{Im}}
* \begin{equation}
* \begin{split}
* \sigma_{u}=\frac{\sigma}{||\sigma||}&=\frac{p + \epsilon q}{||p||+\epsilon\frac{p\cdot q}{||p||}}\\
* &=\frac{p}{||p||}+\epsilon\left(\frac{q}{||p||}-p\frac{p\cdot q}{||p||^3}\right)\\
* &=\frac{p}{||p||}+\epsilon\frac{1}{||p||^2}\left(qp^{*}-p\cdot q\right)\frac{p}{||p||}\\
* &=\frac{p}{||p||}+\epsilon\frac{1}{||p||^2}\Im(qp^*)\frac{p}{||p||}.\\
* \end{split}
* \end{equation}
* \f]
* As expected, the real part is a rotation and dual part is a pure quaternion.
*/
DualQuat<_Tp> normalize() const;
/**
* @brief if \f$\sigma = p + \epsilon q\f$ is a dual quaternion, p is not zero,
* the inverse dual quaternion is
* \f[\sigma^{-1} = \frac{\sigma^*}{||\sigma||^2}, \f]
* or equivalentlly,
* \f[\sigma^{-1} = p^{-1} - \epsilon p^{-1}qp^{-1}.\f]
* @param dq a dual quaternion.
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, dual quaternion dq assume to be a unit dual quaternion
* and this function will save some computations.
*/
template <typename T>
friend DualQuat<T> inv(const DualQuat<T> &dq, QuatAssumeType assumeUnit);
/**
* @brief if \f$\sigma = p + \epsilon q\f$ is a dual quaternion, p is not zero,
* the inverse dual quaternion is
* \f[\sigma^{-1} = \frac{\sigma^*}{||\sigma||^2}, \f]
* or equivalentlly,
* \f[\sigma^{-1} = p^{-1} - \epsilon p^{-1}qp^{-1}.\f]
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion
* and this function will save some computations.
*/
DualQuat<_Tp> inv(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
/**
* @brief return the dot product of two dual quaternion.
* @param p other dual quaternion.
*/
_Tp dot(DualQuat<_Tp> p) const;
/**
** @brief return the value of \f$p^t\f$ where p is a dual quaternion.
* This could be calculated as:
* \f[
* p^t = \exp(t\ln p)
* \f]
* @param dq a dual quaternion.
* @param t index of power function.
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, dual quaternion dq assume to be a unit dual quaternion
* and this function will save some computations.
*/
template <typename T>
friend DualQuat<T> power(const DualQuat<T> &dq, const T t, QuatAssumeType assumeUnit);
/**
** @brief return the value of \f$p^t\f$ where p is a dual quaternion.
* This could be calculated as:
* \f[
* p^t = \exp(t\ln p)
* \f]
*
* @param t index of power function.
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion
* and this function will save some computations.
*/
DualQuat<_Tp> power(const _Tp t, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
/**
* @brief return the value of \f$p^q\f$ where p and q are dual quaternions.
* This could be calculated as:
* \f[
* p^q = \exp(q\ln p)
* \f]
* @param p a dual quaternion.
* @param q a dual quaternion.
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, dual quaternion p assume to be a dual unit quaternion
* and this function will save some computations.
*/
template <typename T>
friend DualQuat<T> power(const DualQuat<T>& p, const DualQuat<T>& q, QuatAssumeType assumeUnit);
/**
* @brief return the value of \f$p^q\f$ where p and q are dual quaternions.
* This could be calculated as:
* \f[
* p^q = \exp(q\ln p)
* \f]
*
* @param q a dual quaternion
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a dual unit quaternion
* and this function will save some computations.
*/
DualQuat<_Tp> power(const DualQuat<_Tp>& q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
/**
* @brief return the value of exponential function value
* @param dq a dual quaternion.
*/
template <typename T>
friend DualQuat<T> exp(const DualQuat<T> &dq);
/**
* @brief return the value of exponential function value
*/
DualQuat<_Tp> exp() const;
/**
* @brief return the value of logarithm function value
*
* @param dq a dual quaternion.
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, dual quaternion dq assume to be a unit dual quaternion
* and this function will save some computations.
*/
template <typename T>
friend DualQuat<T> log(const DualQuat<T> &dq, QuatAssumeType assumeUnit);
/**
* @brief return the value of logarithm function value
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion
* and this function will save some computations.
*/
DualQuat<_Tp> log(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
/**
* @brief Transform this dual quaternion to a vector.
*/
Vec<_Tp, 8> toVec() const;
/**
* @brief Transform this dual quaternion to a affine transformation matrix
* the form of matrix, see createFromMat().
*/
Matx<_Tp, 4, 4> toMat(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
/**
* @brief Transform this dual quaternion to a instance of Affine3.
*/
Affine3<_Tp> toAffine3(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
/**
* @brief The screw linear interpolation(ScLERP) is an extension of spherical linear interpolation of dual quaternion.
* If \f$\sigma_1\f$ and \f$\sigma_2\f$ are two dual quaternions representing the initial and final pose.
* The interpolation of ScLERP function can be defined as:
* \f[
* ScLERP(t;\sigma_1,\sigma_2) = \sigma_1 * (\sigma_1^{-1} * \sigma_2)^t, t\in[0,1]
* \f]
*
* @param q1 a dual quaternion represents a initial pose.
* @param q2 a dual quaternion represents a final pose.
* @param t interpolation parameter
* @param directChange if true, it always return the shortest path.
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion
* and this function will save some computations.
*
* For example
* ```
* double angle1 = CV_PI / 2;
* Vec3d axis{0, 0, 1};
* Vec3d t(0, 0, 3);
* DualQuatd initial = DualQuatd::createFromAngleAxisTrans(angle1, axis, t);
* double angle2 = CV_PI;
* DualQuatd final = DualQuatd::createFromAngleAxisTrans(angle2, axis, t);
* DualQuatd inter = DualQuatd::sclerp(initial, final, 0.5);
* ```
*/
static DualQuat<_Tp> sclerp(const DualQuat<_Tp> &q1, const DualQuat<_Tp> &q2, const _Tp t,
bool directChange=true, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT);
/**
* @brief The method of Dual Quaternion linear Blending(DQB) is to compute a transformation between dual quaternion
* \f$q_1\f$ and \f$q_2\f$ and can be defined as:
* \f[
* DQB(t;{\boldsymbol{q}}_1,{\boldsymbol{q}}_2)=
* \frac{(1-t){\boldsymbol{q}}_1+t{\boldsymbol{q}}_2}{||(1-t){\boldsymbol{q}}_1+t{\boldsymbol{q}}_2||}.
* \f]
* where \f$q_1\f$ and \f$q_2\f$ are unit dual quaternions representing the input transformations.
* If you want to use DQB that works for more than two rigid transformations, see @ref gdqblend
*
* @param q1 a unit dual quaternion representing the input transformations.
* @param q2 a unit dual quaternion representing the input transformations.
* @param t parameter \f$t\in[0,1]\f$.
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion
* and this function will save some computations.
*
* @sa gdqblend
*/
static DualQuat<_Tp> dqblend(const DualQuat<_Tp> &q1, const DualQuat<_Tp> &q2, const _Tp t,
QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT);
/**
* @brief The generalized Dual Quaternion linear Blending works for more than two rigid transformations.
* If these transformations are expressed as unit dual quaternions \f$q_1,...,q_n\f$ with convex weights
* \f$w = (w_1,...,w_n)\f$, the generalized DQB is simply
* \f[
* gDQB(\boldsymbol{w};{\boldsymbol{q}}_1,...,{\boldsymbol{q}}_n)=\frac{w_1{\boldsymbol{q}}_1+...+w_n{\boldsymbol{q}}_n}
* {||w_1{\boldsymbol{q}}_1+...+w_n{\boldsymbol{q}}_n||}.
* \f]
* @param dualquat vector of dual quaternions
* @param weights vector of weights, the size of weights should be the same as dualquat, and the weights should
* satisfy \f$\sum_0^n w_{i} = 1\f$ and \f$w_i>0\f$.
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, these dual quaternions assume to be unit quaternions
* and this function will save some computations.
* @note the type of weights' element should be the same as the date type of dual quaternion inside the dualquat.
*/
template <int cn>
static DualQuat<_Tp> gdqblend(const Vec<DualQuat<_Tp>, cn> &dualquat, InputArray weights,
QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT);
/**
* @brief The generalized Dual Quaternion linear Blending works for more than two rigid transformations.
* If these transformations are expressed as unit dual quaternions \f$q_1,...,q_n\f$ with convex weights
* \f$w = (w_1,...,w_n)\f$, the generalized DQB is simply
* \f[
* gDQB(\boldsymbol{w};{\boldsymbol{q}}_1,...,{\boldsymbol{q}}_n)=\frac{w_1{\boldsymbol{q}}_1+...+w_n{\boldsymbol{q}}_n}
* {||w_1{\boldsymbol{q}}_1+...+w_n{\boldsymbol{q}}_n||}.
* \f]
* @param dualquat The dual quaternions which have 8 channels and 1 row or 1 col.
* @param weights vector of weights, the size of weights should be the same as dualquat, and the weights should
* satisfy \f$\sum_0^n w_{i} = 1\f$ and \f$w_i>0\f$.
* @param assumeUnit if @ref QUAT_ASSUME_UNIT, these dual quaternions assume to be unit quaternions
* and this function will save some computations.
* @note the type of weights' element should be the same as the date type of dual quaternion inside the dualquat.
*/
static DualQuat<_Tp> gdqblend(InputArray dualquat, InputArray weights,
QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT);
/**
* @brief Return opposite dual quaternion \f$-p\f$
* which satisfies \f$p + (-p) = 0.\f$
*
* For example
* ```
* DualQuatd q{1, 2, 3, 4, 5, 6, 7, 8};
* std::cout << -q << std::endl; // [-1, -2, -3, -4, -5, -6, -7, -8]
* ```
*/
DualQuat<_Tp> operator-() const;
/**
* @brief return true if two dual quaternions p and q are nearly equal, i.e. when the absolute
* value of each \f$p_i\f$ and \f$q_i\f$ is less than CV_DUAL_QUAT_EPS.
*/
bool operator==(const DualQuat<_Tp>&) const;
/**
* @brief Subtraction operator of two dual quaternions p and q.
* It returns a new dual quaternion that each value is the sum of \f$p_i\f$ and \f$-q_i\f$.
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12};
* std::cout << p - q << std::endl; //[-4, -4, -4, -4, 4, -4, -4, -4]
* ```
*/
DualQuat<_Tp> operator-(const DualQuat<_Tp>&) const;
/**
* @brief Subtraction assignment operator of two dual quaternions p and q.
* It subtracts right operand from the left operand and assign the result to left operand.
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12};
* p -= q; // equivalent to p = p - q
* std::cout << p << std::endl; //[-4, -4, -4, -4, 4, -4, -4, -4]
*
* ```
*/
DualQuat<_Tp>& operator-=(const DualQuat<_Tp>&);
/**
* @brief Addition operator of two dual quaternions p and q.
* It returns a new dual quaternion that each value is the sum of \f$p_i\f$ and \f$q_i\f$.
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12};
* std::cout << p + q << std::endl; //[6, 8, 10, 12, 14, 16, 18, 20]
* ```
*/
DualQuat<_Tp> operator+(const DualQuat<_Tp>&) const;
/**
* @brief Addition assignment operator of two dual quaternions p and q.
* It adds right operand to the left operand and assign the result to left operand.
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12};
* p += q; // equivalent to p = p + q
* std::cout << p << std::endl; //[6, 8, 10, 12, 14, 16, 18, 20]
*
* ```
*/
DualQuat<_Tp>& operator+=(const DualQuat<_Tp>&);
/**
* @brief Multiplication assignment operator of two quaternions.
* It multiplies right operand with the left operand and assign the result to left operand.
*
* Rule of dual quaternion multiplication:
* The dual quaternion can be written as an ordered pair of quaternions [A, B]. Thus
* \f[
* \begin{equation}
* \begin{split}
* p * q &= [A, B][C, D]\\
* &=[AC, AD + BC]
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12};
* p *= q;
* std::cout << p << std::endl; //[-60, 12, 30, 24, -216, 80, 124, 120]
* ```
*/
DualQuat<_Tp>& operator*=(const DualQuat<_Tp>&);
/**
* @brief Multiplication assignment operator of a quaternions and a scalar.
* It multiplies right operand with the left operand and assign the result to left operand.
*
* Rule of dual quaternion multiplication with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p * s &= [w, x, y, z, w\_, x\_, y\_, z\_] * s\\
* &=[w s, x s, y s, z s, w\_ \space s, x\_ \space s, y\_ \space s, z\_ \space s].
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* double s = 2.0;
* p *= s;
* std::cout << p << std::endl; //[2, 4, 6, 8, 10, 12, 14, 16]
* ```
* @note the type of scalar should be equal to the dual quaternion.
*/
DualQuat<_Tp> operator*=(const _Tp s);
/**
* @brief Multiplication operator of two dual quaternions q and p.
* Multiplies values on either side of the operator.
*
* Rule of dual quaternion multiplication:
* The dual quaternion can be written as an ordered pair of quaternions [A, B]. Thus
* \f[
* \begin{equation}
* \begin{split}
* p * q &= [A, B][C, D]\\
* &=[AC, AD + BC]
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12};
* std::cout << p * q << std::endl; //[-60, 12, 30, 24, -216, 80, 124, 120]
* ```
*/
DualQuat<_Tp> operator*(const DualQuat<_Tp>&) const;
/**
* @brief Division operator of a dual quaternions and a scalar.
* It divides left operand with the right operand and assign the result to left operand.
*
* Rule of dual quaternion division with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p / s &= [w, x, y, z, w\_, x\_, y\_, z\_] / s\\
* &=[w/s, x/s, y/s, z/s, w\_/s, x\_/s, y\_/s, z\_/s].
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* double s = 2.0;
* p /= s; // equivalent to p = p / s
* std::cout << p << std::endl; //[0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4]
* ```
* @note the type of scalar should be equal to this dual quaternion.
*/
DualQuat<_Tp> operator/(const _Tp s) const;
/**
* @brief Division operator of two dual quaternions p and q.
* Divides left hand operand by right hand operand.
*
* Rule of dual quaternion division with a dual quaternion:
* \f[
* \begin{equation}
* \begin{split}
* p / q &= p * q.inv()\\
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12};
* std::cout << p / q << std::endl; // equivalent to p * q.inv()
* ```
*/
DualQuat<_Tp> operator/(const DualQuat<_Tp>&) const;
/**
* @brief Division assignment operator of two dual quaternions p and q;
* It divides left operand with the right operand and assign the result to left operand.
*
* Rule of dual quaternion division with a quaternion:
* \f[
* \begin{equation}
* \begin{split}
* p / q&= p * q.inv()\\
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12};
* p /= q; // equivalent to p = p * q.inv()
* std::cout << p << std::endl;
* ```
*/
DualQuat<_Tp>& operator/=(const DualQuat<_Tp>&);
/**
* @brief Division assignment operator of a dual quaternions and a scalar.
* It divides left operand with the right operand and assign the result to left operand.
*
* Rule of dual quaternion division with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p / s &= [w, x, y, z, w\_, x\_, y\_ ,z\_] / s\\
* &=[w / s, x / s, y / s, z / s, w\_ / \space s, x\_ / \space s, y\_ / \space s, z\_ / \space s].
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* double s = 2.0;;
* p /= s; // equivalent to p = p / s
* std::cout << p << std::endl; //[0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0]
* ```
* @note the type of scalar should be equal to the dual quaternion.
*/
Quat<_Tp>& operator/=(const _Tp s);
/**
* @brief Addition operator of a scalar and a dual quaternions.
* Adds right hand operand from left hand operand.
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* double scalar = 2.0;
* std::cout << scalar + p << std::endl; //[3.0, 2, 3, 4, 5, 6, 7, 8]
* ```
* @note the type of scalar should be equal to the dual quaternion.
*/
template <typename T>
friend DualQuat<T> cv::operator+(const T s, const DualQuat<T>&);
/**
* @brief Addition operator of a dual quaternions and a scalar.
* Adds right hand operand from left hand operand.
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* double scalar = 2.0;
* std::cout << p + scalar << std::endl; //[3.0, 2, 3, 4, 5, 6, 7, 8]
* ```
* @note the type of scalar should be equal to the dual quaternion.
*/
template <typename T>
friend DualQuat<T> cv::operator+(const DualQuat<T>&, const T s);
/**
* @brief Multiplication operator of a scalar and a dual quaternions.
* It multiplies right operand with the left operand and assign the result to left operand.
*
* Rule of dual quaternion multiplication with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p * s &= [w, x, y, z, w\_, x\_, y\_, z\_] * s\\
* &=[w s, x s, y s, z s, w\_ \space s, x\_ \space s, y\_ \space s, z\_ \space s].
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* double s = 2.0;
* std::cout << s * p << std::endl; //[2, 4, 6, 8, 10, 12, 14, 16]
* ```
* @note the type of scalar should be equal to the dual quaternion.
*/
template <typename T>
friend DualQuat<T> cv::operator*(const T s, const DualQuat<T>&);
/**
* @brief Subtraction operator of a dual quaternion and a scalar.
* Subtracts right hand operand from left hand operand.
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* double scalar = 2.0;
* std::cout << p - scalar << std::endl; //[-1, 2, 3, 4, 5, 6, 7, 8]
* ```
* @note the type of scalar should be equal to the dual quaternion.
*/
template <typename T>
friend DualQuat<T> cv::operator-(const DualQuat<T>&, const T s);
/**
* @brief Subtraction operator of a scalar and a dual quaternions.
* Subtracts right hand operand from left hand operand.
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* double scalar = 2.0;
* std::cout << scalar - p << std::endl; //[1.0, -2, -3, -4, -5, -6, -7, -8]
* ```
* @note the type of scalar should be equal to the dual quaternion.
*/
template <typename T>
friend DualQuat<T> cv::operator-(const T s, const DualQuat<T>&);
/**
* @brief Multiplication operator of a dual quaternions and a scalar.
* It multiplies right operand with the left operand and assign the result to left operand.
*
* Rule of dual quaternion multiplication with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p * s &= [w, x, y, z, w\_, x\_, y\_, z\_] * s\\
* &=[w s, x s, y s, z s, w\_ \space s, x\_ \space s, y\_ \space s, z\_ \space s].
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8};
* double s = 2.0;
* std::cout << p * s << std::endl; //[2, 4, 6, 8, 10, 12, 14, 16]
* ```
* @note the type of scalar should be equal to the dual quaternion.
*/
template <typename T>
friend DualQuat<T> cv::operator*(const DualQuat<T>&, const T s);
template <typename S>
friend std::ostream& cv::operator<<(std::ostream&, const DualQuat<S>&);
};
using DualQuatd = DualQuat<double>;
using DualQuatf = DualQuat<float>;
//! @} core
}//namespace
#include "dualquaternion.inl.hpp"
#endif /* OPENCV_CORE_QUATERNION_HPP */
@@ -0,0 +1,487 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2020, Huawei Technologies Co., Ltd. All rights reserved.
// Third party copyrights are property of their respective owners.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Liangqian Kong <kongliangqian@huawei.com>
// Longbu Wang <wanglongbu@huawei.com>
#ifndef OPENCV_CORE_DUALQUATERNION_INL_HPP
#define OPENCV_CORE_DUALQUATERNION_INL_HPP
#ifndef OPENCV_CORE_DUALQUATERNION_HPP
#error This is not a standalone header. Include dualquaternion.hpp instead.
#endif
///////////////////////////////////////////////////////////////////////////////////////
//Implementation
namespace cv {
template <typename T>
DualQuat<T>::DualQuat():w(0), x(0), y(0), z(0), w_(0), x_(0), y_(0), z_(0){};
template <typename T>
DualQuat<T>::DualQuat(const T vw, const T vx, const T vy, const T vz, const T _w, const T _x, const T _y, const T _z):
w(vw), x(vx), y(vy), z(vz), w_(_w), x_(_x), y_(_y), z_(_z){};
template <typename T>
DualQuat<T>::DualQuat(const Vec<T, 8> &q):w(q[0]), x(q[1]), y(q[2]), z(q[3]),
w_(q[4]), x_(q[5]), y_(q[6]), z_(q[7]){};
template <typename T>
DualQuat<T> DualQuat<T>::createFromQuat(const Quat<T> &realPart, const Quat<T> &dualPart)
{
T w = realPart.w;
T x = realPart.x;
T y = realPart.y;
T z = realPart.z;
T w_ = dualPart.w;
T x_ = dualPart.x;
T y_ = dualPart.y;
T z_ = dualPart.z;
return DualQuat<T>(w, x, y, z, w_, x_, y_, z_);
}
template <typename T>
DualQuat<T> DualQuat<T>::createFromAngleAxisTrans(const T angle, const Vec<T, 3> &axis, const Vec<T, 3> &trans)
{
Quat<T> r = Quat<T>::createFromAngleAxis(angle, axis);
Quat<T> t{0, trans[0], trans[1], trans[2]};
return createFromQuat(r, t * r / 2);
}
template <typename T>
DualQuat<T> DualQuat<T>::createFromMat(InputArray _R)
{
CV_CheckTypeEQ(_R.type(), cv::traits::Type<T>::value, "");
if (_R.size() != Size(4, 4))
{
CV_Error(Error::StsBadArg, "The input matrix must have 4 columns and 4 rows");
}
Mat R = _R.getMat();
Quat<T> r = Quat<T>::createFromRotMat(R.colRange(0, 3).rowRange(0, 3));
Quat<T> trans(0, R.at<T>(0, 3), R.at<T>(1, 3), R.at<T>(2, 3));
return createFromQuat(r, trans * r / 2);
}
template <typename T>
DualQuat<T> DualQuat<T>::createFromAffine3(const Affine3<T> &R)
{
return createFromMat(R.matrix);
}
template <typename T>
DualQuat<T> DualQuat<T>::createFromPitch(const T angle, const T d, const Vec<T, 3> &axis, const Vec<T, 3> &moment)
{
T half_angle = angle / 2, half_d = d / 2;
Quat<T> qaxis = Quat<T>(0, axis[0], axis[1], axis[2]).normalize();
Quat<T> qmoment = Quat<T>(0, moment[0], moment[1], moment[2]);
qmoment -= qaxis * axis.dot(moment);
Quat<T> dual = -half_d * std::sin(half_angle) + std::sin(half_angle) * qmoment +
half_d * std::cos(half_angle) * qaxis;
return createFromQuat(Quat<T>::createFromAngleAxis(angle, axis), dual);
}
template <typename T>
inline bool DualQuat<T>::operator==(const DualQuat<T> &q) const
{
return (abs(w - q.w) < CV_DUAL_QUAT_EPS && abs(x - q.x) < CV_DUAL_QUAT_EPS &&
abs(y - q.y) < CV_DUAL_QUAT_EPS && abs(z - q.z) < CV_DUAL_QUAT_EPS &&
abs(w_ - q.w_) < CV_DUAL_QUAT_EPS && abs(x_ - q.x_) < CV_DUAL_QUAT_EPS &&
abs(y_ - q.y_) < CV_DUAL_QUAT_EPS && abs(z_ - q.z_) < CV_DUAL_QUAT_EPS);
}
template <typename T>
inline Quat<T> DualQuat<T>::getRealPart() const
{
return Quat<T>(w, x, y, z);
}
template <typename T>
inline Quat<T> DualQuat<T>::getDualPart() const
{
return Quat<T>(w_, x_, y_, z_);
}
template <typename T>
inline DualQuat<T> conjugate(const DualQuat<T> &dq)
{
return dq.conjugate();
}
template <typename T>
inline DualQuat<T> DualQuat<T>::conjugate() const
{
return DualQuat<T>(w, -x, -y, -z, w_, -x_, -y_, -z_);
}
template <typename T>
DualQuat<T> DualQuat<T>::norm() const
{
Quat<T> real = getRealPart();
T realNorm = real.norm();
Quat<T> dual = getDualPart();
if (realNorm < CV_DUAL_QUAT_EPS){
return DualQuat<T>(0, 0, 0, 0, 0, 0, 0, 0);
}
return DualQuat<T>(realNorm, 0, 0, 0, real.dot(dual) / realNorm, 0, 0, 0);
}
template <typename T>
inline Quat<T> DualQuat<T>::getRotation(QuatAssumeType assumeUnit) const
{
if (assumeUnit)
{
return getRealPart();
}
return getRealPart().normalize();
}
template <typename T>
inline Vec<T, 3> DualQuat<T>::getTranslation(QuatAssumeType assumeUnit) const
{
Quat<T> trans = 2.0 * (getDualPart() * getRealPart().inv(assumeUnit));
return Vec<T, 3>{trans[1], trans[2], trans[3]};
}
template <typename T>
DualQuat<T> DualQuat<T>::normalize() const
{
Quat<T> p = getRealPart();
Quat<T> q = getDualPart();
T p_norm = p.norm();
if (p_norm < CV_DUAL_QUAT_EPS)
{
CV_Error(Error::StsBadArg, "Cannot normalize this dual quaternion: the norm is too small.");
}
Quat<T> p_nr = p / p_norm;
Quat<T> q_nr = q / p_norm;
return createFromQuat(p_nr, q_nr - p_nr * p_nr.dot(q_nr));
}
template <typename T>
inline T DualQuat<T>::dot(DualQuat<T> q) const
{
return q.w * w + q.x * x + q.y * y + q.z * z + q.w_ * w_ + q.x_ * x_ + q.y_ * y_ + q.z_ * z_;
}
template <typename T>
inline DualQuat<T> inv(const DualQuat<T> &dq, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT)
{
return dq.inv(assumeUnit);
}
template <typename T>
inline DualQuat<T> DualQuat<T>::inv(QuatAssumeType assumeUnit) const
{
Quat<T> real = getRealPart();
Quat<T> dual = getDualPart();
return createFromQuat(real.inv(assumeUnit), -real.inv(assumeUnit) * dual * real.inv(assumeUnit));
}
template <typename T>
inline DualQuat<T> DualQuat<T>::operator-(const DualQuat<T> &q) const
{
return DualQuat<T>(w - q.w, x - q.x, y - q.y, z - q.z, w_ - q.w_, x_ - q.x_, y_ - q.y_, z_ - q.z_);
}
template <typename T>
inline DualQuat<T> DualQuat<T>::operator-() const
{
return DualQuat<T>(-w, -x, -y, -z, -w_, -x_, -y_, -z_);
}
template <typename T>
inline DualQuat<T> DualQuat<T>::operator+(const DualQuat<T> &q) const
{
return DualQuat<T>(w + q.w, x + q.x, y + q.y, z + q.z, w_ + q.w_, x_ + q.x_, y_ + q.y_, z_ + q.z_);
}
template <typename T>
inline DualQuat<T>& DualQuat<T>::operator+=(const DualQuat<T> &q)
{
*this = *this + q;
return *this;
}
template <typename T>
inline DualQuat<T> DualQuat<T>::operator*(const DualQuat<T> &q) const
{
Quat<T> A = getRealPart();
Quat<T> B = getDualPart();
Quat<T> C = q.getRealPart();
Quat<T> D = q.getDualPart();
return DualQuat<T>::createFromQuat(A * C, A * D + B * C);
}
template <typename T>
inline DualQuat<T>& DualQuat<T>::operator*=(const DualQuat<T> &q)
{
*this = *this * q;
return *this;
}
template <typename T>
inline DualQuat<T> operator+(const T a, const DualQuat<T> &q)
{
return DualQuat<T>(a + q.w, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_);
}
template <typename T>
inline DualQuat<T> operator+(const DualQuat<T> &q, const T a)
{
return DualQuat<T>(a + q.w, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_);
}
template <typename T>
inline DualQuat<T> operator-(const DualQuat<T> &q, const T a)
{
return DualQuat<T>(q.w - a, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_);
}
template <typename T>
inline DualQuat<T>& DualQuat<T>::operator-=(const DualQuat<T> &q)
{
*this = *this - q;
return *this;
}
template <typename T>
inline DualQuat<T> operator-(const T a, const DualQuat<T> &q)
{
return DualQuat<T>(a - q.w, -q.x, -q.y, -q.z, -q.w_, -q.x_, -q.y_, -q.z_);
}
template <typename T>
inline DualQuat<T> operator*(const T a, const DualQuat<T> &q)
{
return DualQuat<T>(q.w * a, q.x * a, q.y * a, q.z * a, q.w_ * a, q.x_ * a, q.y_ * a, q.z_ * a);
}
template <typename T>
inline DualQuat<T> operator*(const DualQuat<T> &q, const T a)
{
return DualQuat<T>(q.w * a, q.x * a, q.y * a, q.z * a, q.w_ * a, q.x_ * a, q.y_ * a, q.z_ * a);
}
template <typename T>
inline DualQuat<T> DualQuat<T>::operator/(const T a) const
{
return DualQuat<T>(w / a, x / a, y / a, z / a, w_ / a, x_ / a, y_ / a, z_ / a);
}
template <typename T>
inline DualQuat<T> DualQuat<T>::operator/(const DualQuat<T> &q) const
{
return *this * q.inv();
}
template <typename T>
inline DualQuat<T>& DualQuat<T>::operator/=(const DualQuat<T> &q)
{
*this = *this / q;
return *this;
}
template <typename T>
std::ostream & operator<<(std::ostream &os, const DualQuat<T> &q)
{
os << "DualQuat " << Vec<T, 8>{q.w, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_};
return os;
}
template <typename T>
inline DualQuat<T> exp(const DualQuat<T> &dq)
{
return dq.exp();
}
namespace detail {
template <typename _Tp>
Matx<_Tp, 4, 4> jacob_exp(const Quat<_Tp> &q)
{
_Tp nv = std::sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
_Tp sinc_nv = abs(nv) < cv::DualQuat<_Tp>::CV_DUAL_QUAT_EPS ? 1 - nv * nv / 6 : std::sin(nv) / nv;
_Tp csiii_nv = abs(nv) < cv::DualQuat<_Tp>::CV_DUAL_QUAT_EPS ? -(_Tp)1.0 / 3 : (std::cos(nv) - sinc_nv) / nv / nv;
Matx<_Tp, 4, 4> J_exp_quat {
std::cos(nv), -sinc_nv * q.x, -sinc_nv * q.y, -sinc_nv * q.z,
sinc_nv * q.x, csiii_nv * q.x * q.x + sinc_nv, csiii_nv * q.x * q.y, csiii_nv * q.x * q.z,
sinc_nv * q.y, csiii_nv * q.y * q.x, csiii_nv * q.y * q.y + sinc_nv, csiii_nv * q.y * q.z,
sinc_nv * q.z, csiii_nv * q.z * q.x, csiii_nv * q.z * q.y, csiii_nv * q.z * q.z + sinc_nv
};
return std::exp(q.w) * J_exp_quat;
}
} // namespace detail
template <typename T>
DualQuat<T> DualQuat<T>::exp() const
{
Quat<T> real = getRealPart();
return createFromQuat(real.exp(), Quat<T>(detail::jacob_exp(real) * getDualPart().toVec()));
}
template <typename T>
DualQuat<T> log(const DualQuat<T> &dq, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT)
{
return dq.log(assumeUnit);
}
template <typename T>
DualQuat<T> DualQuat<T>::log(QuatAssumeType assumeUnit) const
{
Quat<T> plog = getRealPart().log(assumeUnit);
Matx<T, 4, 4> jacob = detail::jacob_exp(plog);
return createFromQuat(plog, Quat<T>(jacob.inv() * getDualPart().toVec()));
}
template <typename T>
inline DualQuat<T> power(const DualQuat<T> &dq, const T t, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT)
{
return dq.power(t, assumeUnit);
}
template <typename T>
inline DualQuat<T> DualQuat<T>::power(const T t, QuatAssumeType assumeUnit) const
{
return (t * log(assumeUnit)).exp();
}
template <typename T>
inline DualQuat<T> power(const DualQuat<T> &p, const DualQuat<T> &q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT)
{
return p.power(q, assumeUnit);
}
template <typename T>
inline DualQuat<T> DualQuat<T>::power(const DualQuat<T> &q, QuatAssumeType assumeUnit) const
{
return (q * log(assumeUnit)).exp();
}
template <typename T>
inline Vec<T, 8> DualQuat<T>::toVec() const
{
return Vec<T, 8>(w, x, y, z, w_, x_, y_, z_);
}
template <typename T>
Affine3<T> DualQuat<T>::toAffine3(QuatAssumeType assumeUnit) const
{
return Affine3<T>(toMat(assumeUnit));
}
template <typename T>
Matx<T, 4, 4> DualQuat<T>::toMat(QuatAssumeType assumeUnit) const
{
Matx<T, 4, 4> rot44 = getRotation(assumeUnit).toRotMat4x4();
Vec<T, 3> translation = getTranslation(assumeUnit);
rot44(0, 3) = translation[0];
rot44(1, 3) = translation[1];
rot44(2, 3) = translation[2];
return rot44;
}
template <typename T>
DualQuat<T> DualQuat<T>::sclerp(const DualQuat<T> &q0, const DualQuat<T> &q1, const T t, bool directChange, QuatAssumeType assumeUnit)
{
DualQuat<T> v0(q0), v1(q1);
if (!assumeUnit)
{
v0 = v0.normalize();
v1 = v1.normalize();
}
Quat<T> v0Real = v0.getRealPart();
Quat<T> v1Real = v1.getRealPart();
if (directChange && v1Real.dot(v0Real) < 0)
{
v0 = -v0;
}
DualQuat<T> v0inv1 = v0.inv() * v1;
return v0 * v0inv1.power(t, QUAT_ASSUME_UNIT);
}
template <typename T>
DualQuat<T> DualQuat<T>::dqblend(const DualQuat<T> &q1, const DualQuat<T> &q2, const T t, QuatAssumeType assumeUnit)
{
DualQuat<T> v1(q1), v2(q2);
if (!assumeUnit)
{
v1 = v1.normalize();
v2 = v2.normalize();
}
if (v1.getRotation(assumeUnit).dot(v2.getRotation(assumeUnit)) < 0)
{
return ((1 - t) * v1 - t * v2).normalize();
}
return ((1 - t) * v1 + t * v2).normalize();
}
template <typename T>
DualQuat<T> DualQuat<T>::gdqblend(InputArray _dualquat, InputArray _weight, QuatAssumeType assumeUnit)
{
CV_CheckTypeEQ(_weight.type(), cv::traits::Type<T>::value, "");
CV_CheckTypeEQ(_dualquat.type(), CV_MAKETYPE(CV_MAT_DEPTH(cv::traits::Type<T>::value), 8), "");
Size dq_s = _dualquat.size();
if (dq_s != _weight.size() || (dq_s.height != 1 && dq_s.width != 1))
{
CV_Error(Error::StsBadArg, "The size of weight must be the same as dualquat, both of them should be (1, n) or (n, 1)");
}
Mat dualquat = _dualquat.getMat(), weight = _weight.getMat();
const int cn = std::max(dq_s.width, dq_s.height);
if (!assumeUnit)
{
for (int i = 0; i < cn; ++i)
{
dualquat.at<Vec<T, 8>>(i) = DualQuat<T>{dualquat.at<Vec<T, 8>>(i)}.normalize().toVec();
}
}
Vec<T, 8> dq_blend = dualquat.at<Vec<T, 8>>(0) * weight.at<T>(0);
Quat<T> q0 = DualQuat<T> {dualquat.at<Vec<T, 8>>(0)}.getRotation(assumeUnit);
for (int i = 1; i < cn; ++i)
{
T k = q0.dot(DualQuat<T>{dualquat.at<Vec<T, 8>>(i)}.getRotation(assumeUnit)) < 0 ? -1: 1;
dq_blend = dq_blend + dualquat.at<Vec<T, 8>>(i) * k * weight.at<T>(i);
}
return DualQuat<T>{dq_blend}.normalize();
}
template <typename T>
template <int cn>
DualQuat<T> DualQuat<T>::gdqblend(const Vec<DualQuat<T>, cn> &_dualquat, InputArray _weight, QuatAssumeType assumeUnit)
{
Vec<DualQuat<T>, cn> dualquat(_dualquat);
if (cn == 0)
{
return DualQuat<T>(1, 0, 0, 0, 0, 0, 0, 0);
}
Mat dualquat_mat(cn, 1, CV_64FC(8));
for (int i = 0; i < cn ; ++i)
{
dualquat_mat.at<Vec<T, 8>>(i) = dualquat[i].toVec();
}
return gdqblend(dualquat_mat, _weight, assumeUnit);
}
} //namespace cv
#endif /*OPENCV_CORE_DUALQUATERNION_INL_HPP*/
@@ -76,6 +76,9 @@
#if defined __PPC64__ && defined __GNUC__ && defined _ARCH_PWR8 \
&& !defined(OPENCV_SKIP_INCLUDE_ALTIVEC_H)
#include <altivec.h>
#undef vector
#undef bool
#undef pixel
#endif
#if defined(CV_INLINE_ROUND_FLT)
+252 -74
View File
@@ -104,7 +104,7 @@ template<typename _Tp> struct V_TypeTraits
{
};
#define CV_INTRIN_DEF_TYPE_TRAITS(type, int_type_, uint_type_, abs_type_, w_type_, q_type_, sum_type_, nlanes128_) \
#define CV_INTRIN_DEF_TYPE_TRAITS(type, int_type_, uint_type_, abs_type_, w_type_, q_type_, sum_type_) \
template<> struct V_TypeTraits<type> \
{ \
typedef type value_type; \
@@ -114,7 +114,6 @@ template<typename _Tp> struct V_TypeTraits
typedef w_type_ w_type; \
typedef q_type_ q_type; \
typedef sum_type_ sum_type; \
enum { nlanes128 = nlanes128_ }; \
\
static inline int_type reinterpret_int(type x) \
{ \
@@ -131,7 +130,7 @@ template<typename _Tp> struct V_TypeTraits
} \
}
#define CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(type, int_type_, uint_type_, abs_type_, w_type_, sum_type_, nlanes128_) \
#define CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(type, int_type_, uint_type_, abs_type_, w_type_, sum_type_) \
template<> struct V_TypeTraits<type> \
{ \
typedef type value_type; \
@@ -140,7 +139,6 @@ template<typename _Tp> struct V_TypeTraits
typedef uint_type_ uint_type; \
typedef w_type_ w_type; \
typedef sum_type_ sum_type; \
enum { nlanes128 = nlanes128_ }; \
\
static inline int_type reinterpret_int(type x) \
{ \
@@ -157,16 +155,16 @@ template<typename _Tp> struct V_TypeTraits
} \
}
CV_INTRIN_DEF_TYPE_TRAITS(uchar, schar, uchar, uchar, ushort, unsigned, unsigned, 16);
CV_INTRIN_DEF_TYPE_TRAITS(schar, schar, uchar, uchar, short, int, int, 16);
CV_INTRIN_DEF_TYPE_TRAITS(ushort, short, ushort, ushort, unsigned, uint64, unsigned, 8);
CV_INTRIN_DEF_TYPE_TRAITS(short, short, ushort, ushort, int, int64, int, 8);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(unsigned, int, unsigned, unsigned, uint64, unsigned, 4);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(int, int, unsigned, unsigned, int64, int, 4);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(float, int, unsigned, float, double, float, 4);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(uint64, int64, uint64, uint64, void, uint64, 2);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(int64, int64, uint64, uint64, void, int64, 2);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(double, int64, uint64, double, void, double, 2);
CV_INTRIN_DEF_TYPE_TRAITS(uchar, schar, uchar, uchar, ushort, unsigned, unsigned);
CV_INTRIN_DEF_TYPE_TRAITS(schar, schar, uchar, uchar, short, int, int);
CV_INTRIN_DEF_TYPE_TRAITS(ushort, short, ushort, ushort, unsigned, uint64, unsigned);
CV_INTRIN_DEF_TYPE_TRAITS(short, short, ushort, ushort, int, int64, int);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(unsigned, int, unsigned, unsigned, uint64, unsigned);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(int, int, unsigned, unsigned, int64, int);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(float, int, unsigned, float, double, float);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(uint64, int64, uint64, uint64, void, uint64);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(int64, int64, uint64, uint64, void, int64);
CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(double, int64, uint64, double, void, double);
#ifndef CV_DOXYGEN
@@ -202,7 +200,7 @@ using namespace CV_CPU_OPTIMIZATION_HAL_NAMESPACE;
# undef CV_RVV
#endif
#if (CV_SSE2 || CV_NEON || CV_VSX || CV_MSA || CV_WASM_SIMD) && !defined(CV_FORCE_SIMD128_CPP)
#if (CV_SSE2 || CV_NEON || CV_VSX || CV_MSA || CV_WASM_SIMD || CV_RVV) && !defined(CV_FORCE_SIMD128_CPP)
#define CV__SIMD_FORWARD 128
#include "opencv2/core/hal/intrin_forward.hpp"
#endif
@@ -314,54 +312,6 @@ CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN
//==================================================================================================
#define CV_INTRIN_DEFINE_WIDE_INTRIN(typ, vtyp, short_typ, prefix, loadsfx) \
inline vtyp vx_setall_##short_typ(typ v) { return prefix##_setall_##short_typ(v); } \
inline vtyp vx_setzero_##short_typ() { return prefix##_setzero_##short_typ(); } \
inline vtyp vx_##loadsfx(const typ* ptr) { return prefix##_##loadsfx(ptr); } \
inline vtyp vx_##loadsfx##_aligned(const typ* ptr) { return prefix##_##loadsfx##_aligned(ptr); } \
inline vtyp vx_##loadsfx##_low(const typ* ptr) { return prefix##_##loadsfx##_low(ptr); } \
inline vtyp vx_##loadsfx##_halves(const typ* ptr0, const typ* ptr1) { return prefix##_##loadsfx##_halves(ptr0, ptr1); } \
inline void vx_store(typ* ptr, const vtyp& v) { return v_store(ptr, v); } \
inline void vx_store_aligned(typ* ptr, const vtyp& v) { return v_store_aligned(ptr, v); } \
inline vtyp vx_lut(const typ* ptr, const int* idx) { return prefix##_lut(ptr, idx); } \
inline vtyp vx_lut_pairs(const typ* ptr, const int* idx) { return prefix##_lut_pairs(ptr, idx); }
#define CV_INTRIN_DEFINE_WIDE_LUT_QUAD(typ, vtyp, prefix) \
inline vtyp vx_lut_quads(const typ* ptr, const int* idx) { return prefix##_lut_quads(ptr, idx); }
#define CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(typ, wtyp, prefix) \
inline wtyp vx_load_expand(const typ* ptr) { return prefix##_load_expand(ptr); }
#define CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND_Q(typ, qtyp, prefix) \
inline qtyp vx_load_expand_q(const typ* ptr) { return prefix##_load_expand_q(ptr); }
#define CV_INTRIN_DEFINE_WIDE_INTRIN_WITH_EXPAND(typ, vtyp, short_typ, wtyp, qtyp, prefix, loadsfx) \
CV_INTRIN_DEFINE_WIDE_INTRIN(typ, vtyp, short_typ, prefix, loadsfx) \
CV_INTRIN_DEFINE_WIDE_LUT_QUAD(typ, vtyp, prefix) \
CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(typ, wtyp, prefix) \
CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND_Q(typ, qtyp, prefix)
#define CV_INTRIN_DEFINE_WIDE_INTRIN_ALL_TYPES(prefix) \
CV_INTRIN_DEFINE_WIDE_INTRIN_WITH_EXPAND(uchar, v_uint8, u8, v_uint16, v_uint32, prefix, load) \
CV_INTRIN_DEFINE_WIDE_INTRIN_WITH_EXPAND(schar, v_int8, s8, v_int16, v_int32, prefix, load) \
CV_INTRIN_DEFINE_WIDE_INTRIN(ushort, v_uint16, u16, prefix, load) \
CV_INTRIN_DEFINE_WIDE_LUT_QUAD(ushort, v_uint16, prefix) \
CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(ushort, v_uint32, prefix) \
CV_INTRIN_DEFINE_WIDE_INTRIN(short, v_int16, s16, prefix, load) \
CV_INTRIN_DEFINE_WIDE_LUT_QUAD(short, v_int16, prefix) \
CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(short, v_int32, prefix) \
CV_INTRIN_DEFINE_WIDE_INTRIN(int, v_int32, s32, prefix, load) \
CV_INTRIN_DEFINE_WIDE_LUT_QUAD(int, v_int32, prefix) \
CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(int, v_int64, prefix) \
CV_INTRIN_DEFINE_WIDE_INTRIN(unsigned, v_uint32, u32, prefix, load) \
CV_INTRIN_DEFINE_WIDE_LUT_QUAD(unsigned, v_uint32, prefix) \
CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(unsigned, v_uint64, prefix) \
CV_INTRIN_DEFINE_WIDE_INTRIN(float, v_float32, f32, prefix, load) \
CV_INTRIN_DEFINE_WIDE_LUT_QUAD(float, v_float32, prefix) \
CV_INTRIN_DEFINE_WIDE_INTRIN(int64, v_int64, s64, prefix, load) \
CV_INTRIN_DEFINE_WIDE_INTRIN(uint64, v_uint64, u64, prefix, load) \
CV_INTRIN_DEFINE_WIDE_LOAD_EXPAND(float16_t, v_float32, prefix)
template<typename _Tp> struct V_RegTraits
{
};
@@ -421,6 +371,7 @@ template<typename _Tp> struct V_RegTraits
CV_DEF_REG_TRAITS(v512, v_int64x8, int64, s64, v_uint64x8, void, void, v_int64x8, void);
CV_DEF_REG_TRAITS(v512, v_float64x8, double, f64, v_float64x8, void, void, v_int64x8, v_int32x16);
#endif
//! @endcond
#if CV_SIMD512 && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 512)
#define CV__SIMD_NAMESPACE simd512
@@ -429,21 +380,33 @@ namespace CV__SIMD_NAMESPACE {
#define CV_SIMD_64F CV_SIMD512_64F
#define CV_SIMD_FP16 CV_SIMD512_FP16
#define CV_SIMD_WIDTH 64
//! @addtogroup core_hal_intrin
//! @{
//! @brief Maximum available vector register capacity 8-bit unsigned integer values
typedef v_uint8x64 v_uint8;
//! @brief Maximum available vector register capacity 8-bit signed integer values
typedef v_int8x64 v_int8;
//! @brief Maximum available vector register capacity 16-bit unsigned integer values
typedef v_uint16x32 v_uint16;
//! @brief Maximum available vector register capacity 16-bit signed integer values
typedef v_int16x32 v_int16;
//! @brief Maximum available vector register capacity 32-bit unsigned integer values
typedef v_uint32x16 v_uint32;
//! @brief Maximum available vector register capacity 32-bit signed integer values
typedef v_int32x16 v_int32;
//! @brief Maximum available vector register capacity 64-bit unsigned integer values
typedef v_uint64x8 v_uint64;
//! @brief Maximum available vector register capacity 64-bit signed integer values
typedef v_int64x8 v_int64;
//! @brief Maximum available vector register capacity 32-bit floating point values (single precision)
typedef v_float32x16 v_float32;
CV_INTRIN_DEFINE_WIDE_INTRIN_ALL_TYPES(v512)
#if CV_SIMD512_64F
#if CV_SIMD512_64F
//! @brief Maximum available vector register capacity 64-bit floating point values (double precision)
typedef v_float64x8 v_float64;
CV_INTRIN_DEFINE_WIDE_INTRIN(double, v_float64, f64, v512, load)
#endif
inline void vx_cleanup() { v512_cleanup(); }
#endif
//! @}
#define VXPREFIX(func) v512##func
} // namespace
using namespace CV__SIMD_NAMESPACE;
#elif CV_SIMD256 && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 256)
@@ -453,21 +416,33 @@ namespace CV__SIMD_NAMESPACE {
#define CV_SIMD_64F CV_SIMD256_64F
#define CV_SIMD_FP16 CV_SIMD256_FP16
#define CV_SIMD_WIDTH 32
//! @addtogroup core_hal_intrin
//! @{
//! @brief Maximum available vector register capacity 8-bit unsigned integer values
typedef v_uint8x32 v_uint8;
//! @brief Maximum available vector register capacity 8-bit signed integer values
typedef v_int8x32 v_int8;
//! @brief Maximum available vector register capacity 16-bit unsigned integer values
typedef v_uint16x16 v_uint16;
//! @brief Maximum available vector register capacity 16-bit signed integer values
typedef v_int16x16 v_int16;
//! @brief Maximum available vector register capacity 32-bit unsigned integer values
typedef v_uint32x8 v_uint32;
//! @brief Maximum available vector register capacity 32-bit signed integer values
typedef v_int32x8 v_int32;
//! @brief Maximum available vector register capacity 64-bit unsigned integer values
typedef v_uint64x4 v_uint64;
//! @brief Maximum available vector register capacity 64-bit signed integer values
typedef v_int64x4 v_int64;
//! @brief Maximum available vector register capacity 32-bit floating point values (single precision)
typedef v_float32x8 v_float32;
CV_INTRIN_DEFINE_WIDE_INTRIN_ALL_TYPES(v256)
#if CV_SIMD256_64F
//! @brief Maximum available vector register capacity 64-bit floating point values (double precision)
typedef v_float64x4 v_float64;
CV_INTRIN_DEFINE_WIDE_INTRIN(double, v_float64, f64, v256, load)
#endif
inline void vx_cleanup() { v256_cleanup(); }
//! @}
#define VXPREFIX(func) v256##func
} // namespace
using namespace CV__SIMD_NAMESPACE;
#elif (CV_SIMD128 || CV_SIMD128_CPP) && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 128)
@@ -480,25 +455,228 @@ namespace CV__SIMD_NAMESPACE {
#define CV_SIMD CV_SIMD128
#define CV_SIMD_64F CV_SIMD128_64F
#define CV_SIMD_WIDTH 16
//! @addtogroup core_hal_intrin
//! @{
//! @brief Maximum available vector register capacity 8-bit unsigned integer values
typedef v_uint8x16 v_uint8;
//! @brief Maximum available vector register capacity 8-bit signed integer values
typedef v_int8x16 v_int8;
//! @brief Maximum available vector register capacity 16-bit unsigned integer values
typedef v_uint16x8 v_uint16;
//! @brief Maximum available vector register capacity 16-bit signed integer values
typedef v_int16x8 v_int16;
//! @brief Maximum available vector register capacity 32-bit unsigned integer values
typedef v_uint32x4 v_uint32;
//! @brief Maximum available vector register capacity 32-bit signed integer values
typedef v_int32x4 v_int32;
//! @brief Maximum available vector register capacity 64-bit unsigned integer values
typedef v_uint64x2 v_uint64;
//! @brief Maximum available vector register capacity 64-bit signed integer values
typedef v_int64x2 v_int64;
//! @brief Maximum available vector register capacity 32-bit floating point values (single precision)
typedef v_float32x4 v_float32;
CV_INTRIN_DEFINE_WIDE_INTRIN_ALL_TYPES(v)
#if CV_SIMD128_64F
//! @brief Maximum available vector register capacity 64-bit floating point values (double precision)
typedef v_float64x2 v_float64;
CV_INTRIN_DEFINE_WIDE_INTRIN(double, v_float64, f64, v, load)
#endif
inline void vx_cleanup() { v_cleanup(); }
//! @}
#define VXPREFIX(func) v##func
} // namespace
using namespace CV__SIMD_NAMESPACE;
#endif
namespace CV__SIMD_NAMESPACE {
//! @addtogroup core_hal_intrin
//! @{
//! @name Wide init with value
//! @{
//! @brief Create maximum available capacity vector with elements set to a specific value
inline v_uint8 vx_setall_u8(uchar v) { return VXPREFIX(_setall_u8)(v); }
inline v_int8 vx_setall_s8(schar v) { return VXPREFIX(_setall_s8)(v); }
inline v_uint16 vx_setall_u16(ushort v) { return VXPREFIX(_setall_u16)(v); }
inline v_int16 vx_setall_s16(short v) { return VXPREFIX(_setall_s16)(v); }
inline v_int32 vx_setall_s32(int v) { return VXPREFIX(_setall_s32)(v); }
inline v_uint32 vx_setall_u32(unsigned v) { return VXPREFIX(_setall_u32)(v); }
inline v_float32 vx_setall_f32(float v) { return VXPREFIX(_setall_f32)(v); }
inline v_int64 vx_setall_s64(int64 v) { return VXPREFIX(_setall_s64)(v); }
inline v_uint64 vx_setall_u64(uint64 v) { return VXPREFIX(_setall_u64)(v); }
#if CV_SIMD_64F
inline v_float64 vx_setall_f64(double v) { return VXPREFIX(_setall_f64)(v); }
#endif
//! @}
//! @name Wide init with zero
//! @{
//! @brief Create maximum available capacity vector with elements set to zero
inline v_uint8 vx_setzero_u8() { return VXPREFIX(_setzero_u8)(); }
inline v_int8 vx_setzero_s8() { return VXPREFIX(_setzero_s8)(); }
inline v_uint16 vx_setzero_u16() { return VXPREFIX(_setzero_u16)(); }
inline v_int16 vx_setzero_s16() { return VXPREFIX(_setzero_s16)(); }
inline v_int32 vx_setzero_s32() { return VXPREFIX(_setzero_s32)(); }
inline v_uint32 vx_setzero_u32() { return VXPREFIX(_setzero_u32)(); }
inline v_float32 vx_setzero_f32() { return VXPREFIX(_setzero_f32)(); }
inline v_int64 vx_setzero_s64() { return VXPREFIX(_setzero_s64)(); }
inline v_uint64 vx_setzero_u64() { return VXPREFIX(_setzero_u64)(); }
#if CV_SIMD_64F
inline v_float64 vx_setzero_f64() { return VXPREFIX(_setzero_f64)(); }
#endif
//! @}
//! @name Wide load from memory
//! @{
//! @brief Load maximum available capacity register contents from memory
inline v_uint8 vx_load(const uchar * ptr) { return VXPREFIX(_load)(ptr); }
inline v_int8 vx_load(const schar * ptr) { return VXPREFIX(_load)(ptr); }
inline v_uint16 vx_load(const ushort * ptr) { return VXPREFIX(_load)(ptr); }
inline v_int16 vx_load(const short * ptr) { return VXPREFIX(_load)(ptr); }
inline v_int32 vx_load(const int * ptr) { return VXPREFIX(_load)(ptr); }
inline v_uint32 vx_load(const unsigned * ptr) { return VXPREFIX(_load)(ptr); }
inline v_float32 vx_load(const float * ptr) { return VXPREFIX(_load)(ptr); }
inline v_int64 vx_load(const int64 * ptr) { return VXPREFIX(_load)(ptr); }
inline v_uint64 vx_load(const uint64 * ptr) { return VXPREFIX(_load)(ptr); }
#if CV_SIMD_64F
inline v_float64 vx_load(const double * ptr) { return VXPREFIX(_load)(ptr); }
#endif
//! @}
//! @name Wide load from memory(aligned)
//! @{
//! @brief Load maximum available capacity register contents from memory(aligned)
inline v_uint8 vx_load_aligned(const uchar * ptr) { return VXPREFIX(_load_aligned)(ptr); }
inline v_int8 vx_load_aligned(const schar * ptr) { return VXPREFIX(_load_aligned)(ptr); }
inline v_uint16 vx_load_aligned(const ushort * ptr) { return VXPREFIX(_load_aligned)(ptr); }
inline v_int16 vx_load_aligned(const short * ptr) { return VXPREFIX(_load_aligned)(ptr); }
inline v_int32 vx_load_aligned(const int * ptr) { return VXPREFIX(_load_aligned)(ptr); }
inline v_uint32 vx_load_aligned(const unsigned * ptr) { return VXPREFIX(_load_aligned)(ptr); }
inline v_float32 vx_load_aligned(const float * ptr) { return VXPREFIX(_load_aligned)(ptr); }
inline v_int64 vx_load_aligned(const int64 * ptr) { return VXPREFIX(_load_aligned)(ptr); }
inline v_uint64 vx_load_aligned(const uint64 * ptr) { return VXPREFIX(_load_aligned)(ptr); }
#if CV_SIMD_64F
inline v_float64 vx_load_aligned(const double * ptr) { return VXPREFIX(_load_aligned)(ptr); }
#endif
//! @}
//! @name Wide load lower half from memory
//! @{
//! @brief Load lower half of maximum available capacity register from memory
inline v_uint8 vx_load_low(const uchar * ptr) { return VXPREFIX(_load_low)(ptr); }
inline v_int8 vx_load_low(const schar * ptr) { return VXPREFIX(_load_low)(ptr); }
inline v_uint16 vx_load_low(const ushort * ptr) { return VXPREFIX(_load_low)(ptr); }
inline v_int16 vx_load_low(const short * ptr) { return VXPREFIX(_load_low)(ptr); }
inline v_int32 vx_load_low(const int * ptr) { return VXPREFIX(_load_low)(ptr); }
inline v_uint32 vx_load_low(const unsigned * ptr) { return VXPREFIX(_load_low)(ptr); }
inline v_float32 vx_load_low(const float * ptr) { return VXPREFIX(_load_low)(ptr); }
inline v_int64 vx_load_low(const int64 * ptr) { return VXPREFIX(_load_low)(ptr); }
inline v_uint64 vx_load_low(const uint64 * ptr) { return VXPREFIX(_load_low)(ptr); }
#if CV_SIMD_64F
inline v_float64 vx_load_low(const double * ptr) { return VXPREFIX(_load_low)(ptr); }
#endif
//! @}
//! @name Wide load halfs from memory
//! @{
//! @brief Load maximum available capacity register contents from two memory blocks
inline v_uint8 vx_load_halves(const uchar * ptr0, const uchar * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); }
inline v_int8 vx_load_halves(const schar * ptr0, const schar * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); }
inline v_uint16 vx_load_halves(const ushort * ptr0, const ushort * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); }
inline v_int16 vx_load_halves(const short * ptr0, const short * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); }
inline v_int32 vx_load_halves(const int * ptr0, const int * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); }
inline v_uint32 vx_load_halves(const unsigned * ptr0, const unsigned * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); }
inline v_float32 vx_load_halves(const float * ptr0, const float * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); }
inline v_int64 vx_load_halves(const int64 * ptr0, const int64 * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); }
inline v_uint64 vx_load_halves(const uint64 * ptr0, const uint64 * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); }
#if CV_SIMD_64F
inline v_float64 vx_load_halves(const double * ptr0, const double * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); }
#endif
//! @}
//! @name Wide LUT of elements
//! @{
//! @brief Load maximum available capacity register contents with array elements by provided indexes
inline v_uint8 vx_lut(const uchar * ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); }
inline v_int8 vx_lut(const schar * ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); }
inline v_uint16 vx_lut(const ushort * ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); }
inline v_int16 vx_lut(const short* ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); }
inline v_int32 vx_lut(const int* ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); }
inline v_uint32 vx_lut(const unsigned* ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); }
inline v_float32 vx_lut(const float* ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); }
inline v_int64 vx_lut(const int64 * ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); }
inline v_uint64 vx_lut(const uint64 * ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); }
#if CV_SIMD_64F
inline v_float64 vx_lut(const double* ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); }
#endif
//! @}
//! @name Wide LUT of element pairs
//! @{
//! @brief Load maximum available capacity register contents with array element pairs by provided indexes
inline v_uint8 vx_lut_pairs(const uchar * ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); }
inline v_int8 vx_lut_pairs(const schar * ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); }
inline v_uint16 vx_lut_pairs(const ushort * ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); }
inline v_int16 vx_lut_pairs(const short* ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); }
inline v_int32 vx_lut_pairs(const int* ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); }
inline v_uint32 vx_lut_pairs(const unsigned* ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); }
inline v_float32 vx_lut_pairs(const float* ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); }
inline v_int64 vx_lut_pairs(const int64 * ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); }
inline v_uint64 vx_lut_pairs(const uint64 * ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); }
#if CV_SIMD_64F
inline v_float64 vx_lut_pairs(const double* ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); }
#endif
//! @}
//! @name Wide LUT of element quads
//! @{
//! @brief Load maximum available capacity register contents with array element quads by provided indexes
inline v_uint8 vx_lut_quads(const uchar* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); }
inline v_int8 vx_lut_quads(const schar* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); }
inline v_uint16 vx_lut_quads(const ushort* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); }
inline v_int16 vx_lut_quads(const short* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); }
inline v_int32 vx_lut_quads(const int* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); }
inline v_uint32 vx_lut_quads(const unsigned* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); }
inline v_float32 vx_lut_quads(const float* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); }
//! @}
//! @name Wide load with double expansion
//! @{
//! @brief Load maximum available capacity register contents from memory with double expand
inline v_uint16 vx_load_expand(const uchar * ptr) { return VXPREFIX(_load_expand)(ptr); }
inline v_int16 vx_load_expand(const schar * ptr) { return VXPREFIX(_load_expand)(ptr); }
inline v_uint32 vx_load_expand(const ushort * ptr) { return VXPREFIX(_load_expand)(ptr); }
inline v_int32 vx_load_expand(const short* ptr) { return VXPREFIX(_load_expand)(ptr); }
inline v_int64 vx_load_expand(const int* ptr) { return VXPREFIX(_load_expand)(ptr); }
inline v_uint64 vx_load_expand(const unsigned* ptr) { return VXPREFIX(_load_expand)(ptr); }
inline v_float32 vx_load_expand(const float16_t * ptr) { return VXPREFIX(_load_expand)(ptr); }
//! @}
//! @name Wide load with quad expansion
//! @{
//! @brief Load maximum available capacity register contents from memory with quad expand
inline v_uint32 vx_load_expand_q(const uchar * ptr) { return VXPREFIX(_load_expand_q)(ptr); }
inline v_int32 vx_load_expand_q(const schar * ptr) { return VXPREFIX(_load_expand_q)(ptr); }
//! @}
/** @brief SIMD processing state cleanup call */
inline void vx_cleanup() { VXPREFIX(_cleanup)(); }
//! @cond IGNORED
// backward compatibility
template<typename _Tp, typename _Tvec> static inline
void vx_store(_Tp* dst, const _Tvec& v) { return v_store(dst, v); }
// backward compatibility
template<typename _Tp, typename _Tvec> static inline
void vx_store_aligned(_Tp* dst, const _Tvec& v) { return v_store_aligned(dst, v); }
//! @endcond
//! @}
#undef VXPREFIX
} // namespace
//! @cond IGNORED
#ifndef CV_SIMD_64F
#define CV_SIMD_64F 0
#endif
File diff suppressed because it is too large Load Diff
@@ -62,6 +62,22 @@ CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN
#define CV_SIMD128_64F 0
#endif
// The following macro checks if the code is being compiled for the
// AArch64 execution state of Armv8, to enable the 128-bit
// intrinsics. The macro `__ARM_64BIT_STATE` is the one recommended by
// the Arm C Language Extension (ACLE) specifications [1] to check the
// availability of 128-bit intrinsics, and it is supporrted by clang
// and gcc. The macro `_M_ARM64` is the equivalent one for Microsoft
// Visual Studio [2] .
//
// [1] https://developer.arm.com/documentation/101028/0012/13--Advanced-SIMD--Neon--intrinsics
// [2] https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
#if defined(__ARM_64BIT_STATE) || defined(_M_ARM64)
#define CV_NEON_AARCH64 1
#else
#define CV_NEON_AARCH64 0
#endif
// TODO
#define CV_NEON_DOT 0
@@ -726,41 +742,61 @@ inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b,
// 16 >> 32
inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b)
{
#if CV_NEON_AARCH64
int32x4_t p = vmull_s16(vget_low_s16(a.val), vget_low_s16(b.val));
return v_int32x4(vmlal_high_s16(p, a.val, b.val));
#else
int16x4_t a0 = vget_low_s16(a.val);
int16x4_t a1 = vget_high_s16(a.val);
int16x4_t b0 = vget_low_s16(b.val);
int16x4_t b1 = vget_high_s16(b.val);
int32x4_t p = vmull_s16(a0, b0);
return v_int32x4(vmlal_s16(p, a1, b1));
#endif
}
inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c)
{
#if CV_NEON_AARCH64
int32x4_t p = vmlal_s16(c.val, vget_low_s16(a.val), vget_low_s16(b.val));
return v_int32x4(vmlal_high_s16(p, a.val, b.val));
#else
int16x4_t a0 = vget_low_s16(a.val);
int16x4_t a1 = vget_high_s16(a.val);
int16x4_t b0 = vget_low_s16(b.val);
int16x4_t b1 = vget_high_s16(b.val);
int32x4_t p = vmlal_s16(c.val, a0, b0);
return v_int32x4(vmlal_s16(p, a1, b1));
#endif
}
// 32 >> 64
inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b)
{
#if CV_NEON_AARCH64
int64x2_t p = vmull_s32(vget_low_s32(a.val), vget_low_s32(b.val));
return v_int64x2(vmlal_high_s32(p, a.val, b.val));
#else
int32x2_t a0 = vget_low_s32(a.val);
int32x2_t a1 = vget_high_s32(a.val);
int32x2_t b0 = vget_low_s32(b.val);
int32x2_t b1 = vget_high_s32(b.val);
int64x2_t p = vmull_s32(a0, b0);
return v_int64x2(vmlal_s32(p, a1, b1));
#endif
}
inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c)
{
#if CV_NEON_AARCH64
int64x2_t p = vmlal_s32(c.val, vget_low_s32(a.val), vget_low_s32(b.val));
return v_int64x2(vmlal_high_s32(p, a.val, b.val));
#else
int32x2_t a0 = vget_low_s32(a.val);
int32x2_t a1 = vget_high_s32(a.val);
int32x2_t b0 = vget_low_s32(b.val);
int32x2_t b1 = vget_high_s32(b.val);
int64x2_t p = vmlal_s32(c.val, a0, b0);
return v_int64x2(vmlal_s32(p, a1, b1));
#endif
}
// 8 >> 32
@@ -1292,7 +1328,7 @@ inline int64 v_reduce_sum(const v_int64x2& a)
#if CV_SIMD128_64F
inline double v_reduce_sum(const v_float64x2& a)
{
return vgetq_lane_f64(a.val, 0) + vgetq_lane_f64(a.val, 1);
return vaddvq_f64(a.val);
}
#endif
@@ -1503,6 +1539,26 @@ OPENCV_HAL_IMPL_NEON_SELECT(v_float32x4, f32, u32)
OPENCV_HAL_IMPL_NEON_SELECT(v_float64x2, f64, u64)
#endif
#if CV_NEON_AARCH64
#define OPENCV_HAL_IMPL_NEON_EXPAND(_Tpvec, _Tpwvec, _Tp, suffix) \
inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \
{ \
b0.val = vmovl_##suffix(vget_low_##suffix(a.val)); \
b1.val = vmovl_high_##suffix(a.val); \
} \
inline _Tpwvec v_expand_low(const _Tpvec& a) \
{ \
return _Tpwvec(vmovl_##suffix(vget_low_##suffix(a.val))); \
} \
inline _Tpwvec v_expand_high(const _Tpvec& a) \
{ \
return _Tpwvec(vmovl_high_##suffix(a.val)); \
} \
inline _Tpwvec v_load_expand(const _Tp* ptr) \
{ \
return _Tpwvec(vmovl_##suffix(vld1_##suffix(ptr))); \
}
#else
#define OPENCV_HAL_IMPL_NEON_EXPAND(_Tpvec, _Tpwvec, _Tp, suffix) \
inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \
{ \
@@ -1521,6 +1577,7 @@ inline _Tpwvec v_load_expand(const _Tp* ptr) \
{ \
return _Tpwvec(vmovl_##suffix(vld1_##suffix(ptr))); \
}
#endif
OPENCV_HAL_IMPL_NEON_EXPAND(v_uint8x16, v_uint16x8, uchar, u8)
OPENCV_HAL_IMPL_NEON_EXPAND(v_int8x16, v_int16x8, schar, s8)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -27,6 +27,14 @@ Using this approach OpenCV provides some basic low level functionality for exter
#define CV_API_CALL
#endif
#ifndef CV_PLUGIN_EXPORTS
#if (defined _WIN32 || defined WINCE || defined __CYGWIN__)
# define CV_PLUGIN_EXPORTS __declspec(dllexport)
#elif defined __GNUC__ && __GNUC__ >= 4
# define CV_PLUGIN_EXPORTS __attribute__ ((visibility ("default")))
#endif
#endif
typedef enum cvResult
{
CV_ERROR_FAIL = -1, //!< Some error occurred (TODO Require to fill exception information)
+29 -29
View File
@@ -170,7 +170,9 @@ public:
STD_VECTOR = 3 << KIND_SHIFT,
STD_VECTOR_VECTOR = 4 << KIND_SHIFT,
STD_VECTOR_MAT = 5 << KIND_SHIFT,
EXPR = 6 << KIND_SHIFT, //!< removed
#if OPENCV_ABI_COMPATIBILITY < 500
EXPR = 6 << KIND_SHIFT, //!< removed: https://github.com/opencv/opencv/pull/17046
#endif
OPENGL_BUFFER = 7 << KIND_SHIFT,
CUDA_HOST_MEM = 8 << KIND_SHIFT,
CUDA_GPU_MAT = 9 << KIND_SHIFT,
@@ -178,7 +180,9 @@ public:
STD_VECTOR_UMAT =11 << KIND_SHIFT,
STD_BOOL_VECTOR =12 << KIND_SHIFT,
STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT,
STD_ARRAY =14 << KIND_SHIFT,
#if OPENCV_ABI_COMPATIBILITY < 500
STD_ARRAY =14 << KIND_SHIFT, //!< removed: https://github.com/opencv/opencv/issues/18897
#endif
STD_ARRAY_MAT =15 << KIND_SHIFT
};
@@ -572,24 +576,24 @@ CV_ENUM_FLAGS(UMatData::MemoryFlag)
struct CV_EXPORTS MatSize
{
explicit MatSize(int* _p);
int dims() const;
explicit MatSize(int* _p) CV_NOEXCEPT;
int dims() const CV_NOEXCEPT;
Size operator()() const;
const int& operator[](int i) const;
int& operator[](int i);
operator const int*() const; // TODO OpenCV 4.0: drop this
bool operator == (const MatSize& sz) const;
bool operator != (const MatSize& sz) const;
operator const int*() const CV_NOEXCEPT; // TODO OpenCV 4.0: drop this
bool operator == (const MatSize& sz) const CV_NOEXCEPT;
bool operator != (const MatSize& sz) const CV_NOEXCEPT;
int* p;
};
struct CV_EXPORTS MatStep
{
MatStep();
explicit MatStep(size_t s);
const size_t& operator[](int i) const;
size_t& operator[](int i);
MatStep() CV_NOEXCEPT;
explicit MatStep(size_t s) CV_NOEXCEPT;
const size_t& operator[](int i) const CV_NOEXCEPT;
size_t& operator[](int i) CV_NOEXCEPT;
operator size_t() const;
MatStep& operator = (size_t s);
@@ -694,11 +698,16 @@ sub-matrices.
-# Process "foreign" data using OpenCV (for example, when you implement a DirectShow\* filter or
a processing module for gstreamer, and so on). For example:
@code
void process_video_frame(const unsigned char* pixels,
int width, int height, int step)
Mat process_video_frame(const unsigned char* pixels,
int width, int height, int step)
{
Mat img(height, width, CV_8UC3, pixels, step);
GaussianBlur(img, img, Size(7,7), 1.5, 1.5);
// wrap input buffer
Mat img(height, width, CV_8UC3, (unsigned char*)pixels, step);
Mat result;
GaussianBlur(img, result, Size(7, 7), 1.5, 1.5);
return result;
}
@endcode
-# Quickly initialize small matrices and/or get a super-fast element access.
@@ -798,7 +807,7 @@ public:
The constructed matrix can further be assigned to another matrix or matrix expression or can be
allocated with Mat::create . In the former case, the old content is de-referenced.
*/
Mat();
Mat() CV_NOEXCEPT;
/** @overload
@param rows Number of rows in a 2D array.
@@ -2184,7 +2193,7 @@ public:
typedef MatConstIterator_<_Tp> const_iterator;
//! default constructor
Mat_();
Mat_() CV_NOEXCEPT;
//! equivalent to Mat(_rows, _cols, DataType<_Tp>::type)
Mat_(int _rows, int _cols);
//! constructor that sets each matrix element to specified value
@@ -2376,7 +2385,7 @@ class CV_EXPORTS UMat
{
public:
//! default constructor
UMat(UMatUsageFlags usageFlags = USAGE_DEFAULT);
UMat(UMatUsageFlags usageFlags = USAGE_DEFAULT) CV_NOEXCEPT;
//! constructs 2D matrix of the specified size and type
// (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.)
UMat(int rows, int cols, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT);
@@ -2397,20 +2406,11 @@ public:
UMat(const UMat& m, const Rect& roi);
UMat(const UMat& m, const Range* ranges);
UMat(const UMat& m, const std::vector<Range>& ranges);
// FIXIT copyData=false is not implemented, drop this in favor of cv::Mat (OpenCV 5.0)
//! builds matrix from std::vector with or without copying the data
template<typename _Tp> explicit UMat(const std::vector<_Tp>& vec, bool copyData=false);
//! builds matrix from cv::Vec; the data is copied by default
template<typename _Tp, int n> explicit UMat(const Vec<_Tp, n>& vec, bool copyData=true);
//! builds matrix from cv::Matx; the data is copied by default
template<typename _Tp, int m, int n> explicit UMat(const Matx<_Tp, m, n>& mtx, bool copyData=true);
//! builds matrix from a 2D point
template<typename _Tp> explicit UMat(const Point_<_Tp>& pt, bool copyData=true);
//! builds matrix from a 3D point
template<typename _Tp> explicit UMat(const Point3_<_Tp>& pt, bool copyData=true);
//! builds matrix from comma initializer
template<typename _Tp> explicit UMat(const MatCommaInitializer_<_Tp>& commaInitializer);
//! destructor - calls release()
~UMat();
//! assignment operators
+18 -18
View File
@@ -111,7 +111,7 @@ _InputArray::_InputArray(const std::vector<_Tp>& vec)
template<typename _Tp, std::size_t _Nm> inline
_InputArray::_InputArray(const std::array<_Tp, _Nm>& arr)
{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_READ, arr.data(), Size(1, _Nm)); }
{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_READ, arr.data(), Size(1, _Nm)); }
template<std::size_t _Nm> inline
_InputArray::_InputArray(const std::array<Mat, _Nm>& arr)
@@ -169,7 +169,7 @@ template<typename _Tp, std::size_t _Nm> inline
_InputArray _InputArray::rawIn(const std::array<_Tp, _Nm>& arr)
{
_InputArray v;
v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_READ;
v.flags = FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_READ;
v.obj = (void*)arr.data();
v.sz = Size(1, _Nm);
return v;
@@ -191,7 +191,7 @@ inline bool _InputArray::isUMatVector() const { return kind() == _InputArray::S
inline bool _InputArray::isMatx() const { return kind() == _InputArray::MATX; }
inline bool _InputArray::isVector() const { return kind() == _InputArray::STD_VECTOR ||
kind() == _InputArray::STD_BOOL_VECTOR ||
kind() == _InputArray::STD_ARRAY; }
(kind() == _InputArray::MATX && (sz.width <= 1 || sz.height <= 1)); }
inline bool _InputArray::isGpuMat() const { return kind() == _InputArray::CUDA_GPU_MAT; }
inline bool _InputArray::isGpuMatVector() const { return kind() == _InputArray::STD_VECTOR_CUDA_GPU_MAT; }
@@ -210,7 +210,7 @@ _OutputArray::_OutputArray(std::vector<_Tp>& vec)
template<typename _Tp, std::size_t _Nm> inline
_OutputArray::_OutputArray(std::array<_Tp, _Nm>& arr)
{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); }
{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); }
template<std::size_t _Nm> inline
_OutputArray::_OutputArray(std::array<Mat, _Nm>& arr)
@@ -242,7 +242,7 @@ _OutputArray::_OutputArray(const std::vector<_Tp>& vec)
template<typename _Tp, std::size_t _Nm> inline
_OutputArray::_OutputArray(const std::array<_Tp, _Nm>& arr)
{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); }
{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); }
template<std::size_t _Nm> inline
_OutputArray::_OutputArray(const std::array<Mat, _Nm>& arr)
@@ -315,7 +315,7 @@ template<typename _Tp, std::size_t _Nm> inline
_OutputArray _OutputArray::rawOut(std::array<_Tp, _Nm>& arr)
{
_OutputArray v;
v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_WRITE;
v.flags = FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE;
v.obj = (void*)arr.data();
v.sz = Size(1, _Nm);
return v;
@@ -336,7 +336,7 @@ _InputOutputArray::_InputOutputArray(std::vector<_Tp>& vec)
template<typename _Tp, std::size_t _Nm> inline
_InputOutputArray::_InputOutputArray(std::array<_Tp, _Nm>& arr)
{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); }
{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); }
template<std::size_t _Nm> inline
_InputOutputArray::_InputOutputArray(std::array<Mat, _Nm>& arr)
@@ -368,7 +368,7 @@ _InputOutputArray::_InputOutputArray(const std::vector<_Tp>& vec)
template<typename _Tp, std::size_t _Nm> inline
_InputOutputArray::_InputOutputArray(const std::array<_Tp, _Nm>& arr)
{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); }
{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); }
template<std::size_t _Nm> inline
_InputOutputArray::_InputOutputArray(const std::array<Mat, _Nm>& arr)
@@ -443,7 +443,7 @@ template<typename _Tp, std::size_t _Nm> inline
_InputOutputArray _InputOutputArray::rawInOut(std::array<_Tp, _Nm>& arr)
{
_InputOutputArray v;
v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_RW;
v.flags = FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW;
v.obj = (void*)arr.data();
v.sz = Size(1, _Nm);
return v;
@@ -1116,11 +1116,11 @@ void Mat::push_back(const std::vector<_Tp>& v)
///////////////////////////// MatSize ////////////////////////////
inline
MatSize::MatSize(int* _p)
MatSize::MatSize(int* _p) CV_NOEXCEPT
: p(_p) {}
inline
int MatSize::dims() const
int MatSize::dims() const CV_NOEXCEPT
{
return (p - 1)[0];
}
@@ -1153,13 +1153,13 @@ int& MatSize::operator[](int i)
}
inline
MatSize::operator const int*() const
MatSize::operator const int*() const CV_NOEXCEPT
{
return p;
}
inline
bool MatSize::operator != (const MatSize& sz) const
bool MatSize::operator != (const MatSize& sz) const CV_NOEXCEPT
{
return !(*this == sz);
}
@@ -1169,25 +1169,25 @@ bool MatSize::operator != (const MatSize& sz) const
///////////////////////////// MatStep ////////////////////////////
inline
MatStep::MatStep()
MatStep::MatStep() CV_NOEXCEPT
{
p = buf; p[0] = p[1] = 0;
}
inline
MatStep::MatStep(size_t s)
MatStep::MatStep(size_t s) CV_NOEXCEPT
{
p = buf; p[0] = s; p[1] = 0;
}
inline
const size_t& MatStep::operator[](int i) const
const size_t& MatStep::operator[](int i) const CV_NOEXCEPT
{
return p[i];
}
inline
size_t& MatStep::operator[](int i)
size_t& MatStep::operator[](int i) CV_NOEXCEPT
{
return p[i];
}
@@ -1210,7 +1210,7 @@ inline MatStep& MatStep::operator = (size_t s)
////////////////////////////// Mat_<_Tp> ////////////////////////////
template<typename _Tp> inline
Mat_<_Tp>::Mat_()
Mat_<_Tp>::Mat_() CV_NOEXCEPT
: Mat()
{
flags = (flags & ~CV_MAT_TYPE_MASK) + traits::Type<_Tp>::value;
+37 -13
View File
@@ -70,10 +70,12 @@ class CV_EXPORTS Image2D;
class CV_EXPORTS_W_SIMPLE Device
{
public:
CV_WRAP Device();
CV_WRAP Device() CV_NOEXCEPT;
explicit Device(void* d);
Device(const Device& d);
Device& operator = (const Device& d);
Device(Device&& d) CV_NOEXCEPT;
Device& operator = (Device&& d) CV_NOEXCEPT;
CV_WRAP ~Device();
void set(void* d);
@@ -245,11 +247,13 @@ protected:
class CV_EXPORTS Context
{
public:
Context();
Context() CV_NOEXCEPT;
explicit Context(int dtype); //!< @deprecated
~Context();
Context(const Context& c);
Context& operator= (const Context& c);
Context(Context&& c) CV_NOEXCEPT;
Context& operator = (Context&& c) CV_NOEXCEPT;
/** @deprecated */
bool create();
@@ -298,10 +302,12 @@ public:
class CV_EXPORTS Platform
{
public:
Platform();
Platform() CV_NOEXCEPT;
~Platform();
Platform(const Platform& p);
Platform& operator = (const Platform& p);
Platform(Platform&& p) CV_NOEXCEPT;
Platform& operator = (Platform&& p) CV_NOEXCEPT;
void* ptr() const;
@@ -357,11 +363,13 @@ void initializeContextFromHandle(Context& ctx, void* platform, void* context, vo
class CV_EXPORTS Queue
{
public:
Queue();
Queue() CV_NOEXCEPT;
explicit Queue(const Context& c, const Device& d=Device());
~Queue();
Queue(const Queue& q);
Queue& operator = (const Queue& q);
Queue(Queue&& q) CV_NOEXCEPT;
Queue& operator = (Queue&& q) CV_NOEXCEPT;
bool create(const Context& c=Context(), const Device& d=Device());
void finish();
@@ -384,7 +392,7 @@ class CV_EXPORTS KernelArg
public:
enum { LOCAL=1, READ_ONLY=2, WRITE_ONLY=4, READ_WRITE=6, CONSTANT=8, PTR_ONLY = 16, NO_SIZE=256 };
KernelArg(int _flags, UMat* _m, int wscale=1, int iwscale=1, const void* _obj=0, size_t _sz=0);
KernelArg();
KernelArg() CV_NOEXCEPT;
static KernelArg Local(size_t localMemSize)
{ return KernelArg(LOCAL, 0, 1, 1, 0, localMemSize); }
@@ -421,13 +429,15 @@ public:
class CV_EXPORTS Kernel
{
public:
Kernel();
Kernel() CV_NOEXCEPT;
Kernel(const char* kname, const Program& prog);
Kernel(const char* kname, const ProgramSource& prog,
const String& buildopts = String(), String* errmsg=0);
~Kernel();
Kernel(const Kernel& k);
Kernel& operator = (const Kernel& k);
Kernel(Kernel&& k) CV_NOEXCEPT;
Kernel& operator = (Kernel&& k) CV_NOEXCEPT;
bool empty() const;
bool create(const char* kname, const Program& prog);
@@ -498,12 +508,13 @@ protected:
class CV_EXPORTS Program
{
public:
Program();
Program() CV_NOEXCEPT;
Program(const ProgramSource& src,
const String& buildflags, String& errmsg);
Program(const Program& prog);
Program& operator = (const Program& prog);
Program(Program&& prog) CV_NOEXCEPT;
Program& operator = (Program&& prog) CV_NOEXCEPT;
~Program();
bool create(const ProgramSource& src,
@@ -544,13 +555,15 @@ class CV_EXPORTS ProgramSource
public:
typedef uint64 hash_t; // deprecated
ProgramSource();
ProgramSource() CV_NOEXCEPT;
explicit ProgramSource(const String& module, const String& name, const String& codeStr, const String& codeHash);
explicit ProgramSource(const String& prog); // deprecated
explicit ProgramSource(const char* prog); // deprecated
~ProgramSource();
ProgramSource(const ProgramSource& prog);
ProgramSource& operator = (const ProgramSource& prog);
ProgramSource(ProgramSource&& prog) CV_NOEXCEPT;
ProgramSource& operator = (ProgramSource&& prog) CV_NOEXCEPT;
const String& source() const; // deprecated
hash_t hash() const; // deprecated
@@ -614,7 +627,7 @@ protected:
class CV_EXPORTS PlatformInfo
{
public:
PlatformInfo();
PlatformInfo() CV_NOEXCEPT;
/**
* @param id pointer cl_platform_id (cl_platform_id*)
*/
@@ -623,10 +636,17 @@ public:
PlatformInfo(const PlatformInfo& i);
PlatformInfo& operator =(const PlatformInfo& i);
PlatformInfo(PlatformInfo&& i) CV_NOEXCEPT;
PlatformInfo& operator = (PlatformInfo&& i) CV_NOEXCEPT;
String name() const;
String vendor() const;
/// See CL_PLATFORM_VERSION
String version() const;
int versionMajor() const;
int versionMinor() const;
int deviceNumber() const;
void getDevice(Device& device, int d) const;
@@ -678,7 +698,7 @@ CV_EXPORTS void buildOptionsAddMatrixDescription(String& buildOptions, const Str
class CV_EXPORTS Image2D
{
public:
Image2D();
Image2D() CV_NOEXCEPT;
/**
@param src UMat object from which to get image properties and data
@@ -691,6 +711,8 @@ public:
~Image2D();
Image2D & operator = (const Image2D & i);
Image2D(Image2D &&) CV_NOEXCEPT;
Image2D &operator=(Image2D &&) CV_NOEXCEPT;
/** Indicates if creating an aliased image should succeed.
Depends on the underlying platform and the dimensions of the UMat.
@@ -743,9 +765,11 @@ public:
/** Get associated ocl::Context */
Context& getContext() const;
/** Get associated ocl::Device */
/** Get the single default associated ocl::Device */
Device& getDevice() const;
/** Get associated ocl::Queue */
/** Get the single ocl::Queue that is associated with the ocl::Context and
* the single default ocl::Device
*/
Queue& getQueue() const;
bool useOpenCL() const;
@@ -0,0 +1,72 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_CORE_PARALLEL_FOR_OPENMP_HPP
#define OPENCV_CORE_PARALLEL_FOR_OPENMP_HPP
#include "opencv2/core/parallel/parallel_backend.hpp"
#if !defined(_OPENMP) && !defined(OPENCV_SKIP_OPENMP_PRESENSE_CHECK)
#error "This file must be compiled with enabled OpenMP"
#endif
#include <omp.h>
namespace cv { namespace parallel { namespace openmp {
/** OpenMP parallel_for API implementation
*
* @sa setParallelForBackend
* @ingroup core_parallel_backend
*/
class ParallelForBackend : public ParallelForAPI
{
protected:
int numThreads;
int numThreadsMax;
public:
ParallelForBackend()
{
numThreads = 0;
numThreadsMax = omp_get_max_threads();
}
virtual ~ParallelForBackend() {}
virtual void parallel_for(int tasks, FN_parallel_for_body_cb_t body_callback, void* callback_data) CV_OVERRIDE
{
#pragma omp parallel for schedule(dynamic) num_threads(numThreads > 0 ? numThreads : numThreadsMax)
for (int i = 0; i < tasks; ++i)
body_callback(i, i + 1, callback_data);
}
virtual int getThreadNum() const CV_OVERRIDE
{
return omp_get_thread_num();
}
virtual int getNumThreads() const CV_OVERRIDE
{
return numThreads > 0
? numThreads
: numThreadsMax;
}
virtual int setNumThreads(int nThreads) CV_OVERRIDE
{
int oldNumThreads = numThreads;
numThreads = nThreads;
// nothing needed as numThreads is used in #pragma omp parallel for directly
return oldNumThreads;
}
const char* getName() const CV_OVERRIDE
{
return "openmp";
}
};
}}} // namespace
#endif // OPENCV_CORE_PARALLEL_FOR_OPENMP_HPP
@@ -0,0 +1,153 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_CORE_PARALLEL_FOR_TBB_HPP
#define OPENCV_CORE_PARALLEL_FOR_TBB_HPP
#include "opencv2/core/parallel/parallel_backend.hpp"
#include <opencv2/core/utils/logger.hpp>
#ifndef TBB_SUPPRESS_DEPRECATED_MESSAGES // supress warning
#define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
#endif
#include "tbb/tbb.h"
#if !defined(TBB_INTERFACE_VERSION)
#error "Unknows/unsupported TBB version"
#endif
#if TBB_INTERFACE_VERSION >= 8000
#include "tbb/task_arena.h"
#endif
namespace cv { namespace parallel { namespace tbb {
using namespace ::tbb;
#if TBB_INTERFACE_VERSION >= 8000
static tbb::task_arena& getArena()
{
static tbb::task_arena tbbArena(tbb::task_arena::automatic);
return tbbArena;
}
#else
static tbb::task_scheduler_init& getScheduler()
{
static tbb::task_scheduler_init tbbScheduler(tbb::task_scheduler_init::deferred);
return tbbScheduler;
}
#endif
/** OpenMP parallel_for API implementation
*
* @sa setParallelForBackend
* @ingroup core_parallel_backend
*/
class ParallelForBackend : public ParallelForAPI
{
protected:
int numThreads;
int numThreadsMax;
public:
ParallelForBackend()
{
CV_LOG_INFO(NULL, "Initializing TBB parallel backend: TBB_INTERFACE_VERSION=" << TBB_INTERFACE_VERSION);
numThreads = 0;
#if TBB_INTERFACE_VERSION >= 8000
(void)getArena();
#else
(void)getScheduler();
#endif
}
virtual ~ParallelForBackend() {}
class CallbackProxy
{
const FN_parallel_for_body_cb_t& callback;
void* const callback_data;
const int tasks;
public:
inline CallbackProxy(int tasks_, FN_parallel_for_body_cb_t& callback_, void* callback_data_)
: callback(callback_), callback_data(callback_data_), tasks(tasks_)
{
// nothing
}
void operator()(const tbb::blocked_range<int>& range) const
{
this->callback(range.begin(), range.end(), callback_data);
}
void operator()() const
{
tbb::parallel_for(tbb::blocked_range<int>(0, tasks), *this);
}
};
virtual void parallel_for(int tasks, FN_parallel_for_body_cb_t body_callback, void* callback_data) CV_OVERRIDE
{
CallbackProxy task(tasks, body_callback, callback_data);
#if TBB_INTERFACE_VERSION >= 8000
getArena().execute(task);
#else
task();
#endif
}
virtual int getThreadNum() const CV_OVERRIDE
{
#if TBB_INTERFACE_VERSION >= 9100
return tbb::this_task_arena::current_thread_index();
#elif TBB_INTERFACE_VERSION >= 8000
return tbb::task_arena::current_thread_index();
#else
return 0;
#endif
}
virtual int getNumThreads() const CV_OVERRIDE
{
#if TBB_INTERFACE_VERSION >= 9100
return getArena().max_concurrency();
#elif TBB_INTERFACE_VERSION >= 8000
return numThreads > 0
? numThreads
: tbb::task_scheduler_init::default_num_threads();
#else
return getScheduler().is_active()
? numThreads
: tbb::task_scheduler_init::default_num_threads();
#endif
}
virtual int setNumThreads(int nThreads) CV_OVERRIDE
{
int oldNumThreads = numThreads;
numThreads = nThreads;
#if TBB_INTERFACE_VERSION >= 8000
auto& tbbArena = getArena();
if (tbbArena.is_active())
tbbArena.terminate();
if (numThreads > 0)
tbbArena.initialize(numThreads);
#else
auto& tbbScheduler = getScheduler();
if (tbbScheduler.is_active())
tbbScheduler.terminate();
if (numThreads > 0)
tbbScheduler.initialize(numThreads);
#endif
return oldNumThreads;
}
const char* getName() const CV_OVERRIDE
{
return "tbb";
}
};
}}} // namespace
#endif // OPENCV_CORE_PARALLEL_FOR_TBB_HPP
@@ -0,0 +1,90 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_CORE_PARALLEL_BACKEND_HPP
#define OPENCV_CORE_PARALLEL_BACKEND_HPP
#include "opencv2/core/cvdef.h"
#include <memory>
namespace cv { namespace parallel {
#ifndef CV_API_CALL
#define CV_API_CALL
#endif
/** @addtogroup core_parallel_backend
* @{
* API below is provided to resolve problem of CPU resource over-subscription by multiple thread pools from different multi-threading frameworks.
* This is common problem for cases when OpenCV compiled threading framework is different from the Users Applications framework.
*
* Applications can replace OpenCV `parallel_for()` backend with own implementation (to reuse Application's thread pool).
*
*
* ### Backend API usage examples
*
* #### Intel TBB
*
* - include header with simple implementation of TBB backend:
* @snippet parallel_backend/example-tbb.cpp tbb_include
* - execute backend replacement code:
* @snippet parallel_backend/example-tbb.cpp tbb_backend
* - configuration of compiler/linker options is responsibility of Application's scripts
*
* #### OpenMP
*
* - include header with simple implementation of OpenMP backend:
* @snippet parallel_backend/example-openmp.cpp openmp_include
* - execute backend replacement code:
* @snippet parallel_backend/example-openmp.cpp openmp_backend
* - Configuration of compiler/linker options is responsibility of Application's scripts
*
*
* ### Plugins support
*
* Runtime configuration options:
* - change backend priority: `OPENCV_PARALLEL_PRIORITY_<backend>=9999`
* - disable backend: `OPENCV_PARALLEL_PRIORITY_<backend>=0`
* - specify list of backends with high priority (>100000): `OPENCV_PARALLEL_PRIORITY_LIST=TBB,OPENMP`. Unknown backends are registered as new plugins.
*
*/
/** Interface for parallel_for backends implementations
*
* @sa setParallelForBackend
*/
class CV_EXPORTS ParallelForAPI
{
public:
virtual ~ParallelForAPI();
typedef void (CV_API_CALL *FN_parallel_for_body_cb_t)(int start, int end, void* data);
virtual void parallel_for(int tasks, FN_parallel_for_body_cb_t body_callback, void* callback_data) = 0;
virtual int getThreadNum() const = 0;
virtual int getNumThreads() const = 0;
virtual int setNumThreads(int nThreads) = 0;
virtual const char* getName() const = 0;
};
/** @brief Replace OpenCV parallel_for backend
*
* Application can replace OpenCV `parallel_for()` backend with own implementation.
*
* @note This call is not thread-safe. Consider calling this function from the `main()` before any other OpenCV processing functions (and without any other created threads).
*/
CV_EXPORTS void setParallelForBackend(const std::shared_ptr<ParallelForAPI>& api, bool propagateNumThreads = true);
/** @brief Change OpenCV parallel_for backend
*
* @note This call is not thread-safe. Consider calling this function from the `main()` before any other OpenCV processing functions (and without any other created threads).
*/
CV_EXPORTS_W bool setParallelForBackend(const std::string& backendName, bool propagateNumThreads = true);
//! @}
}} // namespace
#endif // OPENCV_CORE_PARALLEL_BACKEND_HPP
+529 -27
View File
@@ -27,6 +27,7 @@
#define OPENCV_CORE_QUATERNION_HPP
#include <opencv2/core.hpp>
#include <opencv2/core/utils/logger.hpp>
#include <iostream>
namespace cv
{
@@ -51,6 +52,83 @@ enum QuatAssumeType
QUAT_ASSUME_UNIT
};
class QuatEnum
{
public:
/** @brief Enum of Euler angles type.
*
* Without considering the possibility of using two different convertions for the definition of the rotation axes ,
* there exists twelve possible sequences of rotation axes, divided into two groups:
* - Proper Euler angles (Z-X-Z, X-Y-X, Y-Z-Y, Z-Y-Z, X-Z-X, Y-X-Y)
* - TaitBryan angles (X-Y-Z, Y-Z-X, Z-X-Y, X-Z-Y, Z-Y-X, Y-X-Z).
*
* The three elemental rotations may be [extrinsic](https://en.wikipedia.org/wiki/Euler_angles#Definition_by_extrinsic_rotations)
* (rotations about the axes *xyz* of the original coordinate system, which is assumed to remain motionless),
* or [intrinsic](https://en.wikipedia.org/wiki/Euler_angles#Definition_by_intrinsic_rotations)(rotations about the axes of the rotating coordinate system *XYZ*, solidary with the moving body, which changes its orientation after each elemental rotation).
*
*
* Extrinsic and intrinsic rotations are relevant.
*
* The definition of the Euler angles is as following,
* - \f$\theta_1 \f$ represents the first rotation angle,
* - \f$\theta_2 \f$ represents the second rotation angle,
* - \f$\theta_3 \f$ represents the third rotation angle.
*
* For intrinsic rotations in the order of X-Y-Z, the rotation matrix R can be calculated by:\f[R =X(\theta_1) Y(\theta_2) Z(\theta_3) \f]
* For extrinsic rotations in the order of X-Y-Z, the rotation matrix R can be calculated by:\f[R =Z({\theta_3}) Y({\theta_2}) X({\theta_1})\f]
* where
* \f[X({\theta})={\begin{bmatrix}1&0&0\\0&\cos {\theta_1} &-\sin {\theta_1} \\0&\sin {\theta_1} &\cos {\theta_1} \\\end{bmatrix}},
* Y({\theta})={\begin{bmatrix}\cos \theta_{2}&0&\sin \theta_{2}\\0&1 &0 \\\ -sin \theta_2& 0&\cos \theta_{2} \\\end{bmatrix}},
* Z({\theta})={\begin{bmatrix}\cos\theta_{3} &-\sin \theta_3&0\\\sin \theta_3 &\cos \theta_3 &0\\0&0&1\\\end{bmatrix}}.
* \f]
*
* The function is designed according to this set of conventions:
* - [Right handed](https://en.wikipedia.org/wiki/Right_hand_rule) reference frames are adopted, and the [right hand rule](https://en.wikipedia.org/wiki/Right_hand_rule) is used to determine the sign of angles.
* - Each matrix is meant to represent an [active rotation](https://en.wikipedia.org/wiki/Active_and_passive_transformation) (the composing and composed matrices
* are supposed to act on the coordinates of vectors defined in the initial fixed reference frame and give as a result the coordinates of a rotated vector defined in the same reference frame).
* - For \f$\theta_1\f$ and \f$\theta_3\f$, the valid range is (π,π].
*
* For \f$\theta_2\f$, the valid range is [π/2,π/2] or [0,π].
*
* For TaitBryan angles, the valid range of \f$\theta_2\f$ is [π/2,π/2]. When transforming a quaternion to Euler angles, the solution of Euler angles is unique in condition of \f$ \theta_2 \in (π/2,π/2)\f$ .
* If \f$\theta_2 = π/2 \f$ or \f$ \theta_2 = π/2\f$, there are infinite solutions. The common name for this situation is gimbal lock.
* For Proper Euler angles,the valid range of \f$\theta_2\f$ is in [0,π]. The solutions of Euler angles are unique in condition of \f$ \theta_2 \in (0,π)\f$ . If \f$\theta_2 =0 \f$ or \f$\theta_2 =π \f$,
* there are infinite solutions and gimbal lock will occur.
*/
enum EulerAnglesType
{
INT_XYZ, ///< Intrinsic rotations with the Euler angles type X-Y-Z
INT_XZY, ///< Intrinsic rotations with the Euler angles type X-Z-Y
INT_YXZ, ///< Intrinsic rotations with the Euler angles type Y-X-Z
INT_YZX, ///< Intrinsic rotations with the Euler angles type Y-Z-X
INT_ZXY, ///< Intrinsic rotations with the Euler angles type Z-X-Y
INT_ZYX, ///< Intrinsic rotations with the Euler angles type Z-Y-X
INT_XYX, ///< Intrinsic rotations with the Euler angles type X-Y-X
INT_XZX, ///< Intrinsic rotations with the Euler angles type X-Z-X
INT_YXY, ///< Intrinsic rotations with the Euler angles type Y-X-Y
INT_YZY, ///< Intrinsic rotations with the Euler angles type Y-Z-Y
INT_ZXZ, ///< Intrinsic rotations with the Euler angles type Z-X-Z
INT_ZYZ, ///< Intrinsic rotations with the Euler angles type Z-Y-Z
EXT_XYZ, ///< Extrinsic rotations with the Euler angles type X-Y-Z
EXT_XZY, ///< Extrinsic rotations with the Euler angles type X-Z-Y
EXT_YXZ, ///< Extrinsic rotations with the Euler angles type Y-X-Z
EXT_YZX, ///< Extrinsic rotations with the Euler angles type Y-Z-X
EXT_ZXY, ///< Extrinsic rotations with the Euler angles type Z-X-Y
EXT_ZYX, ///< Extrinsic rotations with the Euler angles type Z-Y-X
EXT_XYX, ///< Extrinsic rotations with the Euler angles type X-Y-X
EXT_XZX, ///< Extrinsic rotations with the Euler angles type X-Z-X
EXT_YXY, ///< Extrinsic rotations with the Euler angles type Y-X-Y
EXT_YZY, ///< Extrinsic rotations with the Euler angles type Y-Z-Y
EXT_ZXZ, ///< Extrinsic rotations with the Euler angles type Z-X-Z
EXT_ZYZ, ///< Extrinsic rotations with the Euler angles type Z-Y-Z
#ifndef CV_DOXYGEN
EULER_ANGLES_MAX_VALUE
#endif
};
};
template <typename _Tp> class Quat;
template <typename _Tp> std::ostream& operator<<(std::ostream&, const Quat<_Tp>&);
@@ -133,9 +211,9 @@ class Quat
{
static_assert(std::is_floating_point<_Tp>::value, "Quaternion only make sense with type of float or double");
using value_type = _Tp;
public:
static constexpr _Tp CV_QUAT_EPS = (_Tp)1.e-6;
static constexpr _Tp CV_QUAT_CONVERT_THRESHOLD = (_Tp)1.e-6;
Quat();
@@ -182,6 +260,41 @@ public:
*/
static Quat<_Tp> createFromRvec(InputArray rvec);
/**
* @brief
* from Euler angles
*
* A quaternion can be generated from Euler angles by combining the quaternion representations of the Euler rotations.
*
* For example, if we use intrinsic rotations in the order of X-Y-Z,\f$\theta_1 \f$ is rotation around the X-axis, \f$\theta_2 \f$ is rotation around the Y-axis,
* \f$\theta_3 \f$ is rotation around the Z-axis. The final quaternion q can be calculated by
*
* \f[ {q} = q_{X, \theta_1} q_{Y, \theta_2} q_{Z, \theta_3}\f]
* where \f$ q_{X, \theta_1} \f$ is created from @ref createFromXRot, \f$ q_{Y, \theta_2} \f$ is created from @ref createFromYRot,
* \f$ q_{Z, \theta_3} \f$ is created from @ref createFromZRot.
* @param angles the Euler angles in a vector of length 3
* @param eulerAnglesType the convertion Euler angles type
*/
static Quat<_Tp> createFromEulerAngles(const Vec<_Tp, 3> &angles, QuatEnum::EulerAnglesType eulerAnglesType);
/**
* @brief get a quaternion from a rotation about the Y-axis by \f$\theta\f$ .
* \f[q = \cos(\theta/2)+0 i+ sin(\theta/2) j +0k \f]
*/
static Quat<_Tp> createFromYRot(const _Tp theta);
/**
* @brief get a quaternion from a rotation about the X-axis by \f$\theta\f$ .
* \f[q = \cos(\theta/2)+sin(\theta/2) i +0 j +0 k \f]
*/
static Quat<_Tp> createFromXRot(const _Tp theta);
/**
* @brief get a quaternion from a rotation about the Z-axis by \f$\theta\f$.
* \f[q = \cos(\theta/2)+0 i +0 j +sin(\theta/2) k \f]
*/
static Quat<_Tp> createFromZRot(const _Tp theta);
/**
* @brief a way to get element.
* @param index over a range [0, 3].
@@ -277,17 +390,18 @@ public:
* For example
* ```
* Quatd q(1,2,3,4);
* power(q, 2);
* power(q, 2.0);
*
* QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT;
* double angle = CV_PI;
* Vec3d axis{0, 0, 1};
* Quatd q1 = Quatd::createFromAngleAxis(angle, axis); //generate a unit quat by axis and angle
* power(q1, 2, assumeUnit);//This assumeUnit means q1 is a unit quaternion.
* power(q1, 2.0, assumeUnit);//This assumeUnit means q1 is a unit quaternion.
* ```
* @note the type of the index should be the same as the quaternion.
*/
template <typename T, typename _T>
friend Quat<T> power(const Quat<T> &q, _T x, QuatAssumeType assumeUnit);
template <typename T>
friend Quat<T> power(const Quat<T> &q, const T x, QuatAssumeType assumeUnit);
/**
* @brief return the value of power function with index \f$x\f$.
@@ -298,17 +412,16 @@ public:
* For example
* ```
* Quatd q(1,2,3,4);
* q.power(2);
* q.power(2.0);
*
* QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT;
* double angle = CV_PI;
* Vec3d axis{0, 0, 1};
* Quatd q1 = Quatd::createFromAngleAxis(angle, axis); //generate a unit quat by axis and angle
* q1.power(2, assumeUnit); //This assumeUnt means q1 is a unit quaternion
* q1.power(2.0, assumeUnit); //This assumeUnt means q1 is a unit quaternion
* ```
*/
template <typename _T>
Quat<_Tp> power(_T x, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
Quat<_Tp> power(const _Tp x, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
/**
* @brief return \f$\sqrt{q}\f$.
@@ -811,8 +924,8 @@ public:
/**
* @brief transform a quaternion to a 3x3 rotation matrix.
* @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and
* this function will save some computations. Otherwise, this function will normalized this
* quaternion at first then to do the transformation.
* this function will save some computations. Otherwise, this function will normalize this
* quaternion at first then do the transformation.
*
* @note Matrix A which is to be rotated should have the form
* \f[\begin{bmatrix}
@@ -845,8 +958,8 @@ public:
/**
* @brief transform a quaternion to a 4x4 rotation matrix.
* @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and
* this function will save some computations. Otherwise, this function will normalized this
* quaternion at first then to do the transformation.
* this function will save some computations. Otherwise, this function will normalize this
* quaternion at first then do the transformation.
*
* The operations is similar as toRotMat3x3
* except that the points matrix should have the form
@@ -859,6 +972,7 @@ public:
*
* @sa toRotMat3x3
*/
Matx<_Tp, 4, 4> toRotMat4x4(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const;
/**
@@ -1073,46 +1187,434 @@ public:
const Quat<_Tp> &q2, const Quat<_Tp> &q3,
const _Tp t, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT);
/**
* @brief Return opposite quaternion \f$-p\f$
* which satisfies \f$p + (-p) = 0.\f$
*
* For example
* ```
* Quatd q{1, 2, 3, 4};
* std::cout << -q << std::endl; // [-1, -2, -3, -4]
* ```
*/
Quat<_Tp> operator-() const;
/**
* @brief return true if two quaternions p and q are nearly equal, i.e. when the absolute
* value of each \f$p_i\f$ and \f$q_i\f$ is less than CV_QUAT_EPS.
*/
bool operator==(const Quat<_Tp>&) const;
/**
* @brief Addition operator of two quaternions p and q.
* It returns a new quaternion that each value is the sum of \f$p_i\f$ and \f$q_i\f$.
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* Quatd q{5, 6, 7, 8};
* std::cout << p + q << std::endl; //[6, 8, 10, 12]
* ```
*/
Quat<_Tp> operator+(const Quat<_Tp>&) const;
/**
* @brief Addition assignment operator of two quaternions p and q.
* It adds right operand to the left operand and assign the result to left operand.
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* Quatd q{5, 6, 7, 8};
* p += q; // equivalent to p = p + q
* std::cout << p << std::endl; //[6, 8, 10, 12]
*
* ```
*/
Quat<_Tp>& operator+=(const Quat<_Tp>&);
/**
* @brief Subtraction operator of two quaternions p and q.
* It returns a new quaternion that each value is the sum of \f$p_i\f$ and \f$-q_i\f$.
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* Quatd q{5, 6, 7, 8};
* std::cout << p - q << std::endl; //[-4, -4, -4, -4]
* ```
*/
Quat<_Tp> operator-(const Quat<_Tp>&) const;
/**
* @brief Subtraction assignment operator of two quaternions p and q.
* It subtracts right operand from the left operand and assign the result to left operand.
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* Quatd q{5, 6, 7, 8};
* p -= q; // equivalent to p = p - q
* std::cout << p << std::endl; //[-4, -4, -4, -4]
*
* ```
*/
Quat<_Tp>& operator-=(const Quat<_Tp>&);
/**
* @brief Multiplication assignment operator of two quaternions q and p.
* It multiplies right operand with the left operand and assign the result to left operand.
*
* Rule of quaternion multiplication:
* \f[
* \begin{equation}
* \begin{split}
* p * q &= [p_0, \boldsymbol{u}]*[q_0, \boldsymbol{v}]\\
* &=[p_0q_0 - \boldsymbol{u}\cdot \boldsymbol{v}, p_0\boldsymbol{v} + q_0\boldsymbol{u}+ \boldsymbol{u}\times \boldsymbol{v}].
* \end{split}
* \end{equation}
* \f]
* where \f$\cdot\f$ means dot product and \f$\times \f$ means cross product.
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* Quatd q{5, 6, 7, 8};
* p *= q; // equivalent to p = p * q
* std::cout << p << std::endl; //[-60, 12, 30, 24]
* ```
*/
Quat<_Tp>& operator*=(const Quat<_Tp>&);
Quat<_Tp>& operator*=(const _Tp&);
/**
* @brief Multiplication assignment operator of a quaternions and a scalar.
* It multiplies right operand with the left operand and assign the result to left operand.
*
* Rule of quaternion multiplication with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p * s &= [w, x, y, z] * s\\
* &=[w * s, x * s, y * s, z * s].
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* double s = 2.0;
* p *= s; // equivalent to p = p * s
* std::cout << p << std::endl; //[2.0, 4.0, 6.0, 8.0]
* ```
* @note the type of scalar should be equal to the quaternion.
*/
Quat<_Tp>& operator*=(const _Tp s);
/**
* @brief Multiplication operator of two quaternions q and p.
* Multiplies values on either side of the operator.
*
* Rule of quaternion multiplication:
* \f[
* \begin{equation}
* \begin{split}
* p * q &= [p_0, \boldsymbol{u}]*[q_0, \boldsymbol{v}]\\
* &=[p_0q_0 - \boldsymbol{u}\cdot \boldsymbol{v}, p_0\boldsymbol{v} + q_0\boldsymbol{u}+ \boldsymbol{u}\times \boldsymbol{v}].
* \end{split}
* \end{equation}
* \f]
* where \f$\cdot\f$ means dot product and \f$\times \f$ means cross product.
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* Quatd q{5, 6, 7, 8};
* std::cout << p * q << std::endl; //[-60, 12, 30, 24]
* ```
*/
Quat<_Tp> operator*(const Quat<_Tp>&) const;
Quat<_Tp> operator/(const _Tp&) const;
/**
* @brief Division operator of a quaternions and a scalar.
* It divides left operand with the right operand and assign the result to left operand.
*
* Rule of quaternion division with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p / s &= [w, x, y, z] / s\\
* &=[w/s, x/s, y/s, z/s].
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* double s = 2.0;
* p /= s; // equivalent to p = p / s
* std::cout << p << std::endl; //[0.5, 1, 1.5, 2]
* ```
* @note the type of scalar should be equal to this quaternion.
*/
Quat<_Tp> operator/(const _Tp s) const;
/**
* @brief Division operator of two quaternions p and q.
* Divides left hand operand by right hand operand.
*
* Rule of quaternion division with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p / q &= p * q.inv()\\
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* Quatd q{5, 6, 7, 8};
* std::cout << p / q << std::endl; // equivalent to p * q.inv()
* ```
*/
Quat<_Tp> operator/(const Quat<_Tp>&) const;
Quat<_Tp>& operator/=(const _Tp&);
/**
* @brief Division assignment operator of a quaternions and a scalar.
* It divides left operand with the right operand and assign the result to left operand.
*
* Rule of quaternion division with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p / s &= [w, x, y, z] / s\\
* &=[w / s, x / s, y / s, z / s].
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* double s = 2.0;;
* p /= s; // equivalent to p = p / s
* std::cout << p << std::endl; //[0.5, 1.0, 1.5, 2.0]
* ```
* @note the type of scalar should be equal to the quaternion.
*/
Quat<_Tp>& operator/=(const _Tp s);
/**
* @brief Division assignment operator of two quaternions p and q;
* It divides left operand with the right operand and assign the result to left operand.
*
* Rule of quaternion division with a quaternion:
* \f[
* \begin{equation}
* \begin{split}
* p / q&= p * q.inv()\\
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* Quatd q{5, 6, 7, 8};
* p /= q; // equivalent to p = p * q.inv()
* std::cout << p << std::endl;
* ```
*/
Quat<_Tp>& operator/=(const Quat<_Tp>&);
_Tp& operator[](std::size_t n);
const _Tp& operator[](std::size_t n) const;
template <typename S, typename T>
friend Quat<S> cv::operator*(const T, const Quat<S>&);
/**
* @brief Subtraction operator of a scalar and a quaternions.
* Subtracts right hand operand from left hand operand.
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* double scalar = 2.0;
* std::cout << scalar - p << std::endl; //[1.0, -2, -3, -4]
* ```
* @note the type of scalar should be equal to the quaternion.
*/
template <typename T>
friend Quat<T> cv::operator-(const T s, const Quat<T>&);
template <typename S, typename T>
friend Quat<S> cv::operator*(const Quat<S>&, const T);
/**
* @brief Subtraction operator of a quaternions and a scalar.
* Subtracts right hand operand from left hand operand.
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* double scalar = 2.0;
* std::cout << p - scalar << std::endl; //[-1.0, 2, 3, 4]
* ```
* @note the type of scalar should be equal to the quaternion.
*/
template <typename T>
friend Quat<T> cv::operator-(const Quat<T>&, const T s);
/**
* @brief Addition operator of a quaternions and a scalar.
* Adds right hand operand from left hand operand.
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* double scalar = 2.0;
* std::cout << scalar + p << std::endl; //[3.0, 2, 3, 4]
* ```
* @note the type of scalar should be equal to the quaternion.
*/
template <typename T>
friend Quat<T> cv::operator+(const T s, const Quat<T>&);
/**
* @brief Addition operator of a quaternions and a scalar.
* Adds right hand operand from left hand operand.
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* double scalar = 2.0;
* std::cout << p + scalar << std::endl; //[3.0, 2, 3, 4]
* ```
* @note the type of scalar should be equal to the quaternion.
*/
template <typename T>
friend Quat<T> cv::operator+(const Quat<T>&, const T s);
/**
* @brief Multiplication operator of a scalar and a quaternions.
* It multiplies right operand with the left operand and assign the result to left operand.
*
* Rule of quaternion multiplication with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p * s &= [w, x, y, z] * s\\
* &=[w * s, x * s, y * s, z * s].
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* double s = 2.0;
* std::cout << s * p << std::endl; //[2.0, 4.0, 6.0, 8.0]
* ```
* @note the type of scalar should be equal to the quaternion.
*/
template <typename T>
friend Quat<T> cv::operator*(const T s, const Quat<T>&);
/**
* @brief Multiplication operator of a quaternion and a scalar.
* It multiplies right operand with the left operand and assign the result to left operand.
*
* Rule of quaternion multiplication with a scalar:
* \f[
* \begin{equation}
* \begin{split}
* p * s &= [w, x, y, z] * s\\
* &=[w * s, x * s, y * s, z * s].
* \end{split}
* \end{equation}
* \f]
*
* For example
* ```
* Quatd p{1, 2, 3, 4};
* double s = 2.0;
* std::cout << p * s << std::endl; //[2.0, 4.0, 6.0, 8.0]
* ```
* @note the type of scalar should be equal to the quaternion.
*/
template <typename T>
friend Quat<T> cv::operator*(const Quat<T>&, const T s);
template <typename S>
friend std::ostream& cv::operator<<(std::ostream&, const Quat<S>&);
/**
* @brief Transform a quaternion q to Euler angles.
*
*
* When transforming a quaternion \f$q = w + x\boldsymbol{i} + y\boldsymbol{j} + z\boldsymbol{k}\f$ to Euler angles, rotation matrix M can be calculated by:
* \f[ \begin{aligned} {M} &={\begin{bmatrix}1-2(y^{2}+z^{2})&2(xy-zx)&2(xz+yw)\\2(xy+zw)&1-2(x^{2}+z^{2})&2(yz-xw)\\2(xz-yw)&2(yz+xw)&1-2(x^{2}+y^{2})\end{bmatrix}}\end{aligned}.\f]
* On the other hand, the rotation matrix can be obtained from Euler angles.
* Using intrinsic rotations with Euler angles type XYZ as an example,
* \f$\theta_1 \f$, \f$\theta_2 \f$, \f$\theta_3 \f$ are three angles for Euler angles, the rotation matrix R can be calculated by:\f[R =X(\theta_1)Y(\theta_2)Z(\theta_3)
* ={\begin{bmatrix}\cos\theta_{2}\cos\theta_{3}&-\cos\theta_{2}\sin\theta_{3}&\sin\theta_{2}\\\cos\theta_{1}\sin\theta_{3}+\cos\theta_{3}\sin\theta_{1}\sin\theta_{2}&\cos\theta_{1}\cos\theta_{3}-\sin\theta_{1}\sin\theta_{2}\sin\theta_{3}&-\cos\theta_{2}\sin\theta_{1}\\\sin\theta_{1}\sin\theta_{3}-\cos\theta_{1}\cos\theta_{3}\sin\theta_{2}&\cos\theta_{3}\sin\theta_{1}+\cos\theta_{1}\sin\theta_{2}\sin\theta_{3}&\cos\theta_{1}\cos_{2}\end{bmatrix}}\f]
* Rotation matrix M and R are equal. As long as \f$ s_{2} \neq 1 \f$, by comparing each element of two matrices ,the solution is\f$\begin{cases} \theta_1 = \arctan2(-m_{23},m_{33})\\\theta_2 = arcsin(m_{13}) \\\theta_3 = \arctan2(-m_{12},m_{11}) \end{cases}\f$.
*
* When \f$ s_{2}=1\f$ or \f$ s_{2}=-1\f$, the gimbal lock occurs. The function will prompt "WARNING: Gimbal Lock will occur. Euler angles is non-unique. For intrinsic rotations, we set the third angle to 0, and for external rotation, we set the first angle to 0.".
*
* When \f$ s_{2}=1\f$ ,
* The rotation matrix R is \f$R = {\begin{bmatrix}0&0&1\\\sin(\theta_1+\theta_3)&\cos(\theta_1+\theta_3)&0\\-\cos(\theta_1+\theta_3)&\sin(\theta_1+\theta_3)&0\end{bmatrix}}\f$.
*
* The number of solutions is infinite with the condition \f$\begin{cases} \theta_1+\theta_3 = \arctan2(m_{21},m_{22})\\ \theta_2=\pi/2 \end{cases}\ \f$.
*
* We set \f$ \theta_3 = 0\f$, the solution is \f$\begin{cases} \theta_1=\arctan2(m_{21},m_{22})\\ \theta_2=\pi/2\\ \theta_3=0 \end{cases}\f$.
*
* When \f$ s_{2}=-1\f$,
* The rotation matrix R is \f$X_{1}Y_{2}Z_{3}={\begin{bmatrix}0&0&-1\\-\sin(\theta_1-\theta_3)&\cos(\theta_1-\theta_3)&0\\\cos(\theta_1-\theta_3)&\sin(\theta_1-\theta_3)&0\end{bmatrix}}\f$.
*
* The number of solutions is infinite with the condition \f$\begin{cases} \theta_1+\theta_3 = \arctan2(m_{32},m_{22})\\ \theta_2=\pi/2 \end{cases}\ \f$.
*
* We set \f$ \theta_3 = 0\f$, the solution is \f$ \begin{cases}\theta_1=\arctan2(m_{32},m_{22}) \\ \theta_2=-\pi/2\\ \theta_3=0\end{cases}\f$.
*
* Since \f$ sin \theta\in [-1,1] \f$ and \f$ cos \theta \in [-1,1] \f$, the unnormalized quaternion will cause computational troubles. For this reason, this function will normalize the quaternion at first and @ref QuatAssumeType is not needed.
*
* When the gimbal lock occurs, we set \f$\theta_3 = 0\f$ for intrinsic rotations or \f$\theta_1 = 0\f$ for extrinsic rotations.
*
* As a result, for every Euler angles type, we can get solution as shown in the following table.
* EulerAnglesType | Ordinary | \f$\theta_2 = π/2\f$ | \f$\theta_2 = -π/2\f$
* ------------- | -------------| -------------| -------------
* INT_XYZ|\f$ \theta_1 = \arctan2(-m_{23},m_{33})\\\theta_2 = \arcsin(m_{13}) \\\theta_3= \arctan2(-m_{12},m_{11}) \f$|\f$ \theta_1=\arctan2(m_{21},m_{22})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(m_{32},m_{22})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$
* INT_XZY|\f$ \theta_1 = \arctan2(m_{32},m_{22})\\\theta_2 = -\arcsin(m_{12}) \\\theta_3= \arctan2(m_{13},m_{11}) \f$|\f$ \theta_1=\arctan2(m_{31},m_{33})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(-m_{23},m_{33})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$
* INT_YXZ|\f$ \theta_1 = \arctan2(m_{13},m_{33})\\\theta_2 = -\arcsin(m_{23}) \\\theta_3= \arctan2(m_{21},m_{22}) \f$|\f$ \theta_1=\arctan2(m_{12},m_{11})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(-m_{12},m_{11})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$
* INT_YZX|\f$ \theta_1 = \arctan2(-m_{31},m_{11})\\\theta_2 = \arcsin(m_{21}) \\\theta_3= \arctan2(-m_{23},m_{22}) \f$|\f$ \theta_1=\arctan2(m_{13},m_{33})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(m_{13},m_{12})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$
* INT_ZXY|\f$ \theta_1 = \arctan2(-m_{12},m_{22})\\\theta_2 = \arcsin(m_{32}) \\\theta_3= \arctan2(-m_{31},m_{33}) \f$|\f$ \theta_1=\arctan2(m_{21},m_{11})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(m_{21},m_{11})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$
* INT_ZYX|\f$ \theta_1 = \arctan2(m_{21},m_{11})\\\theta_2 = \arcsin(-m_{31}) \\\theta_3= \arctan2(m_{32},m_{33}) \f$|\f$ \theta_1=\arctan2(m_{23},m_{22})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(-m_{12},m_{22})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$
* EXT_XYZ|\f$ \theta_1 = \arctan2(m_{32},m_{33})\\\theta_2 = \arcsin(-m_{31}) \\\ \theta_3 = \arctan2(m_{21},m_{11})\f$|\f$ \theta_1= 0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{23},m_{22}) \f$|\f$ \theta_1=0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(-m_{12},m_{22}) \f$
* EXT_XZY|\f$ \theta_1 = \arctan2(-m_{23},m_{22})\\\theta_2 = \arcsin(m_{21}) \\\theta_3= \arctan2(-m_{31},m_{11})\f$|\f$ \theta_1= 0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{13},m_{33}) \f$|\f$ \theta_1=0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(m_{13},m_{12}) \f$
* EXT_YXZ|\f$ \theta_1 = \arctan2(-m_{31},m_{33}) \\\theta_2 = \arcsin(m_{32}) \\\theta_3= \arctan2(-m_{12},m_{22})\f$|\f$ \theta_1= 0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{21},m_{11}) \f$|\f$ \theta_1=0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(m_{21},m_{11}) \f$
* EXT_YZX|\f$ \theta_1 = \arctan2(m_{13},m_{11})\\\theta_2 = -\arcsin(m_{12}) \\\theta_3= \arctan2(m_{32},m_{22})\f$|\f$ \theta_1= 0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{31},m_{33}) \f$|\f$ \theta_1=0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(-m_{23},m_{33}) \f$
* EXT_ZXY|\f$ \theta_1 = \arctan2(m_{21},m_{22})\\\theta_2 = -\arcsin(m_{23}) \\\theta_3= \arctan2(m_{13},m_{33})\f$|\f$ \theta_1= 0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{12},m_{11}) \f$|\f$ \theta_1= 0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(-m_{12},m_{11}) \f$
* EXT_ZYX|\f$ \theta_1 = \arctan2(-m_{12},m_{11})\\\theta_2 = \arcsin(m_{13}) \\\theta_3= \arctan2(-m_{23},m_{33})\f$|\f$ \theta_1=0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{21},m_{22}) \f$|\f$ \theta_1=0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(m_{32},m_{22}) \f$
*
* EulerAnglesType | Ordinary | \f$\theta_2 = 0\f$ | \f$\theta_2 = π\f$
* ------------- | -------------| -------------| -------------
* INT_XYX| \f$ \theta_1 = \arctan2(m_{21},-m_{31})\\\theta_2 =\arccos(m_{11}) \\\theta_3 = \arctan2(m_{12},m_{13}) \f$| \f$ \theta_1=\arctan2(m_{32},m_{33})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(m_{23},m_{22})\\ \theta_2=\pi\\ \theta_3=0 \f$
* INT_XZX| \f$ \theta_1 = \arctan2(m_{31},m_{21})\\\theta_2 = \arccos(m_{11}) \\\theta_3 = \arctan2(m_{13},-m_{12}) \f$| \f$ \theta_1=\arctan2(m_{32},m_{33})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(-m_{32},m_{33})\\ \theta_2=\pi\\ \theta_3=0 \f$
* INT_YXY| \f$ \theta_1 = \arctan2(m_{12},m_{32})\\\theta_2 = \arccos(m_{22}) \\\theta_3 = \arctan2(m_{21},-m_{23}) \f$| \f$ \theta_1=\arctan2(m_{13},m_{11})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(-m_{31},m_{11})\\ \theta_2=\pi\\ \theta_3=0 \f$
* INT_YZY| \f$ \theta_1 = \arctan2(m_{32},-m_{12})\\\theta_2 = \arccos(m_{22}) \\\theta_3 =\arctan2(m_{23},m_{21}) \f$| \f$ \theta_1=\arctan2(m_{13},m_{11})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(m_{13},-m_{11})\\ \theta_2=\pi\\ \theta_3=0 \f$
* INT_ZXZ| \f$ \theta_1 = \arctan2(-m_{13},m_{23})\\\theta_2 = \arccos(m_{33}) \\\theta_3 =\arctan2(m_{31},m_{32}) \f$| \f$ \theta_1=\arctan2(m_{21},m_{22})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(m_{21},m_{11})\\ \theta_2=\pi\\ \theta_3=0 \f$
* INT_ZYZ| \f$ \theta_1 = \arctan2(m_{23},m_{13})\\\theta_2 = \arccos(m_{33}) \\\theta_3 = \arctan2(m_{32},-m_{31}) \f$| \f$ \theta_1=\arctan2(m_{21},m_{11})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(m_{21},m_{11})\\ \theta_2=\pi\\ \theta_3=0 \f$
* EXT_XYX| \f$ \theta_1 = \arctan2(m_{12},m_{13}) \\\theta_2 = \arccos(m_{11}) \\\theta_3 = \arctan2(m_{21},-m_{31})\f$| \f$ \theta_1=0\\ \theta_2=0\\ \theta_3=\arctan2(m_{32},m_{33}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3= \arctan2(m_{23},m_{22}) \f$
* EXT_XZX| \f$ \theta_1 = \arctan2(m_{13},-m_{12})\\\theta_2 = \arccos(m_{11}) \\\theta_3 = \arctan2(m_{31},m_{21})\f$| \f$ \theta_1= 0\\ \theta_2=0\\ \theta_3=\arctan2(m_{32},m_{33}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3=\arctan2(-m_{32},m_{33}) \f$
* EXT_YXY| \f$ \theta_1 = \arctan2(m_{21},-m_{23})\\\theta_2 = \arccos(m_{22}) \\\theta_3 = \arctan2(m_{12},m_{32}) \f$| \f$ \theta_1= 0\\ \theta_2=0\\ \theta_3=\arctan2(m_{13},m_{11}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3=\arctan2(-m_{31},m_{11}) \f$
* EXT_YZY| \f$ \theta_1 = \arctan2(m_{23},m_{21}) \\\theta_2 = \arccos(m_{22}) \\\theta_3 = \arctan2(m_{32},-m_{12}) \f$| \f$ \theta_1= 0\\ \theta_2=0\\ \theta_3=\arctan2(m_{13},m_{11}) \f$| \f$ \theta_1=0\\ \theta_2=\pi\\ \theta_3=\arctan2(m_{13},-m_{11}) \f$
* EXT_ZXZ| \f$ \theta_1 = \arctan2(m_{31},m_{32}) \\\theta_2 = \arccos(m_{33}) \\\theta_3 = \arctan2(-m_{13},m_{23})\f$| \f$ \theta_1=0\\ \theta_2=0\\ \theta_3=\arctan2(m_{21},m_{22}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3=\arctan2(m_{21},m_{11}) \f$
* EXT_ZYZ| \f$ \theta_1 = \arctan2(m_{32},-m_{31})\\\theta_2 = \arccos(m_{33}) \\\theta_3 = \arctan2(m_{23},m_{13}) \f$| \f$ \theta_1=0\\ \theta_2=0\\ \theta_3=\arctan2(m_{21},m_{11}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3=\arctan2(m_{21},m_{11}) \f$
*
* @param eulerAnglesType the convertion Euler angles type
*/
Vec<_Tp, 3> toEulerAngles(QuatEnum::EulerAnglesType eulerAnglesType);
_Tp w, x, y, z;
};
@@ -1165,8 +1667,8 @@ Quat<T> exp(const Quat<T> &q);
template <typename T>
Quat<T> log(const Quat<T> &q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT);
template <typename T, typename _T>
Quat<T> power(const Quat<T>& q, _T x, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT);
template <typename T>
Quat<T> power(const Quat<T>& q, const T x, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT);
template <typename T>
Quat<T> crossProduct(const Quat<T> &p, const Quat<T> &q);
@@ -1174,11 +1676,11 @@ Quat<T> crossProduct(const Quat<T> &p, const Quat<T> &q);
template <typename S>
Quat<S> sqrt(const Quat<S> &q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT);
template <typename S, typename T>
Quat<S> operator*(const T, const Quat<S>&);
template <typename T>
Quat<T> operator*(const T, const Quat<T>&);
template <typename S, typename T>
Quat<S> operator*(const Quat<S>&, const T);
template <typename T>
Quat<T> operator*(const Quat<T>&, const T);
template <typename S>
std::ostream& operator<<(std::ostream&, const Quat<S>&);
@@ -148,6 +148,30 @@ inline Quat<T> Quat<T>::operator+(const Quat<T> &q1) const
return Quat<T>(w + q1.w, x + q1.x, y + q1.y, z + q1.z);
}
template <typename T>
inline Quat<T> operator+(const T a, const Quat<T>& q)
{
return Quat<T>(q.w + a, q.x, q.y, q.z);
}
template <typename T>
inline Quat<T> operator+(const Quat<T>& q, const T a)
{
return Quat<T>(q.w + a, q.x, q.y, q.z);
}
template <typename T>
inline Quat<T> operator-(const T a, const Quat<T>& q)
{
return Quat<T>(a - q.w, -q.x, -q.y, -q.z);
}
template <typename T>
inline Quat<T> operator-(const Quat<T>& q, const T a)
{
return Quat<T>(q.w - a, q.x, q.y, q.z);
}
template <typename T>
inline Quat<T> Quat<T>::operator-(const Quat<T> &q1) const
{
@@ -183,14 +207,14 @@ inline Quat<T> Quat<T>::operator*(const Quat<T> &q1) const
}
template <typename T, typename S>
Quat<T> operator*(const Quat<T> &q1, const S a)
template <typename T>
Quat<T> operator*(const Quat<T> &q1, const T a)
{
return Quat<T>(a * q1.w, a * q1.x, a * q1.y, a * q1.z);
}
template <typename T, typename S>
Quat<T> operator*(const S a, const Quat<T> &q1)
template <typename T>
Quat<T> operator*(const T a, const Quat<T> &q1)
{
return Quat<T>(a * q1.w, a * q1.x, a * q1.y, a * q1.z);
}
@@ -221,7 +245,7 @@ inline Quat<T>& Quat<T>::operator/=(const Quat<T> &q1)
return *this;
}
template <typename T>
Quat<T>& Quat<T>::operator*=(const T &q1)
Quat<T>& Quat<T>::operator*=(const T q1)
{
w *= q1;
x *= q1;
@@ -231,7 +255,7 @@ Quat<T>& Quat<T>::operator*=(const T &q1)
}
template <typename T>
inline Quat<T>& Quat<T>::operator/=(const T &a)
inline Quat<T>& Quat<T>::operator/=(const T a)
{
const T a_inv = 1.0 / a;
w *= a_inv;
@@ -242,7 +266,7 @@ inline Quat<T>& Quat<T>::operator/=(const T &a)
}
template <typename T>
inline Quat<T> Quat<T>::operator/(const T &a) const
inline Quat<T> Quat<T>::operator/(const T a) const
{
const T a_inv = 1.0 / a;
return Quat<T>(w * a_inv, x * a_inv, y * a_inv, z * a_inv);
@@ -353,15 +377,14 @@ Quat<T> Quat<T>::log(QuatAssumeType assumeUnit) const
return Quat<T>(std::log(qNorm), v[0] * k, v[1] * k, v[2] *k);
}
template <typename T, typename _T>
inline Quat<T> power(const Quat<T> &q1, _T alpha, QuatAssumeType assumeUnit)
template <typename T>
inline Quat<T> power(const Quat<T> &q1, const T alpha, QuatAssumeType assumeUnit)
{
return q1.power(alpha, assumeUnit);
}
template <typename T>
template <typename _T>
inline Quat<T> Quat<T>::power(_T alpha, QuatAssumeType assumeUnit) const
inline Quat<T> Quat<T>::power(const T alpha, QuatAssumeType assumeUnit) const
{
if (x * x + y * y + z * z > CV_QUAT_EPS)
{
@@ -843,6 +866,197 @@ Quat<T> Quat<T>::spline(const Quat<T> &q0, const Quat<T> &q1, const Quat<T> &q2,
return squad(vec[1], s1, s2, vec[2], t, assumeUnit, QUAT_ASSUME_NOT_UNIT);
}
namespace detail {
template <typename T> static
Quat<T> createFromAxisRot(int axis, const T theta)
{
if (axis == 0)
return Quat<T>::createFromXRot(theta);
if (axis == 1)
return Quat<T>::createFromYRot(theta);
if (axis == 2)
return Quat<T>::createFromZRot(theta);
CV_Assert(0);
}
inline bool isIntAngleType(QuatEnum::EulerAnglesType eulerAnglesType)
{
return eulerAnglesType < QuatEnum::EXT_XYZ;
}
inline bool isTaitBryan(QuatEnum::EulerAnglesType eulerAnglesType)
{
return eulerAnglesType/6 == 1 || eulerAnglesType/6 == 3;
}
} // namespace detail
template <typename T>
Quat<T> Quat<T>::createFromYRot(const T theta)
{
return Quat<T>{std::cos(theta * 0.5f), 0, std::sin(theta * 0.5f), 0};
}
template <typename T>
Quat<T> Quat<T>::createFromXRot(const T theta){
return Quat<T>{std::cos(theta * 0.5f), std::sin(theta * 0.5f), 0, 0};
}
template <typename T>
Quat<T> Quat<T>::createFromZRot(const T theta){
return Quat<T>{std::cos(theta * 0.5f), 0, 0, std::sin(theta * 0.5f)};
}
template <typename T>
Quat<T> Quat<T>::createFromEulerAngles(const Vec<T, 3> &angles, QuatEnum::EulerAnglesType eulerAnglesType) {
CV_Assert(eulerAnglesType < QuatEnum::EulerAnglesType::EULER_ANGLES_MAX_VALUE);
static const int rotationAxis[24][3] = {
{0, 1, 2}, ///< Intrinsic rotations with the Euler angles type X-Y-Z
{0, 2, 1}, ///< Intrinsic rotations with the Euler angles type X-Z-Y
{1, 0, 2}, ///< Intrinsic rotations with the Euler angles type Y-X-Z
{1, 2, 0}, ///< Intrinsic rotations with the Euler angles type Y-Z-X
{2, 0, 1}, ///< Intrinsic rotations with the Euler angles type Z-X-Y
{2, 1, 0}, ///< Intrinsic rotations with the Euler angles type Z-Y-X
{0, 1, 0}, ///< Intrinsic rotations with the Euler angles type X-Y-X
{0, 2, 0}, ///< Intrinsic rotations with the Euler angles type X-Z-X
{1, 0, 1}, ///< Intrinsic rotations with the Euler angles type Y-X-Y
{1, 2, 1}, ///< Intrinsic rotations with the Euler angles type Y-Z-Y
{2, 0, 2}, ///< Intrinsic rotations with the Euler angles type Z-X-Z
{2, 1, 2}, ///< Intrinsic rotations with the Euler angles type Z-Y-Z
{0, 1, 2}, ///< Extrinsic rotations with the Euler angles type X-Y-Z
{0, 2, 1}, ///< Extrinsic rotations with the Euler angles type X-Z-Y
{1, 0, 2}, ///< Extrinsic rotations with the Euler angles type Y-X-Z
{1, 2, 0}, ///< Extrinsic rotations with the Euler angles type Y-Z-X
{2, 0, 1}, ///< Extrinsic rotations with the Euler angles type Z-X-Y
{2, 1, 0}, ///< Extrinsic rotations with the Euler angles type Z-Y-X
{0, 1, 0}, ///< Extrinsic rotations with the Euler angles type X-Y-X
{0, 2, 0}, ///< Extrinsic rotations with the Euler angles type X-Z-X
{1, 0, 1}, ///< Extrinsic rotations with the Euler angles type Y-X-Y
{1, 2, 1}, ///< Extrinsic rotations with the Euler angles type Y-Z-Y
{2, 0, 2}, ///< Extrinsic rotations with the Euler angles type Z-X-Z
{2, 1, 2} ///< Extrinsic rotations with the Euler angles type Z-Y-Z
};
Quat<T> q1 = detail::createFromAxisRot(rotationAxis[eulerAnglesType][0], angles(0));
Quat<T> q2 = detail::createFromAxisRot(rotationAxis[eulerAnglesType][1], angles(1));
Quat<T> q3 = detail::createFromAxisRot(rotationAxis[eulerAnglesType][2], angles(2));
if (detail::isIntAngleType(eulerAnglesType))
{
return q1 * q2 * q3;
}
else // (!detail::isIntAngleType<T>(eulerAnglesType))
{
return q3 * q2 * q1;
}
}
template <typename T>
Vec<T, 3> Quat<T>::toEulerAngles(QuatEnum::EulerAnglesType eulerAnglesType){
CV_Assert(eulerAnglesType < QuatEnum::EulerAnglesType::EULER_ANGLES_MAX_VALUE);
Matx33d R = toRotMat3x3();
enum {
C_ZERO,
C_PI,
C_PI_2,
N_CONSTANTS,
R_0_0 = N_CONSTANTS, R_0_1, R_0_2,
R_1_0, R_1_1, R_1_2,
R_2_0, R_2_1, R_2_2
};
static const T constants_[N_CONSTANTS] = {
0, // C_ZERO
(T)CV_PI, // C_PI
(T)(CV_PI * 0.5) // C_PI_2, -C_PI_2
};
static const int rotationR_[24][12] = {
{+R_0_2, +R_1_0, +R_1_1, C_PI_2, +R_2_1, +R_1_1, -C_PI_2, -R_1_2, +R_2_2, +R_0_2, -R_0_1, +R_0_0}, // INT_XYZ
{+R_0_1, -R_1_2, +R_2_2, -C_PI_2, +R_2_0, +R_2_2, C_PI_2, +R_2_1, +R_1_1, -R_0_1, +R_0_2, +R_0_0}, // INT_XZY
{+R_1_2, -R_0_1, +R_0_0, -C_PI_2, +R_0_1, +R_0_0, C_PI_2, +R_0_2, +R_2_2, -R_1_2, +R_1_0, +R_1_1}, // INT_YXZ
{+R_1_0, +R_0_2, +R_2_2, C_PI_2, +R_0_2, +R_0_1, -C_PI_2, -R_2_0, +R_0_0, +R_1_0, -R_1_2, +R_1_1}, // INT_YZX
{+R_2_1, +R_1_0, +R_0_0, C_PI_2, +R_1_0, +R_0_0, -C_PI_2, -R_0_1, +R_1_1, +R_2_1, -R_2_0, +R_2_2}, // INT_ZXY
{+R_2_0, -R_0_1, +R_1_1, -C_PI_2, +R_1_2, +R_1_1, C_PI_2, +R_1_0, +R_0_0, -R_2_0, +R_2_1, +R_2_2}, // INT_ZYX
{+R_0_0, +R_2_1, +R_2_2, C_ZERO, +R_1_2, +R_1_1, C_PI, +R_1_0, -R_2_0, +R_0_0, +R_0_1, +R_0_2}, // INT_XYX
{+R_0_0, +R_2_1, +R_2_2, C_ZERO, -R_2_1, +R_2_2, C_PI, +R_2_0, +R_1_0, +R_0_0, +R_0_2, -R_0_1}, // INT_XZX
{+R_1_1, +R_0_2, +R_0_0, C_ZERO, -R_2_0, +R_0_0, C_PI, +R_0_1, +R_2_1, +R_1_1, +R_1_0, -R_1_2}, // INT_YXY
{+R_1_1, +R_0_2, +R_0_0, C_ZERO, +R_0_2, -R_0_0, C_PI, +R_2_1, -R_0_1, +R_1_1, +R_1_2, +R_1_0}, // INT_YZY
{+R_2_2, +R_1_0, +R_1_1, C_ZERO, +R_1_0, +R_0_0, C_PI, +R_0_2, -R_1_2, +R_2_2, +R_2_0, +R_2_1}, // INT_ZXZ
{+R_2_2, +R_1_0, +R_0_0, C_ZERO, +R_1_0, +R_0_0, C_PI, +R_1_2, +R_0_2, +R_2_2, +R_2_1, -R_2_0}, // INT_ZYZ
{+R_2_0, -C_PI_2, -R_0_1, +R_1_1, C_PI_2, +R_1_2, +R_1_1, +R_2_1, +R_2_2, -R_2_0, +R_1_0, +R_0_0}, // EXT_XYZ
{+R_1_0, C_PI_2, +R_0_2, +R_2_2, -C_PI_2, +R_0_2, +R_0_1, -R_1_2, +R_1_1, +R_1_0, -R_2_0, +R_0_0}, // EXT_XZY
{+R_2_1, C_PI_2, +R_1_0, +R_0_0, -C_PI_2, +R_1_0, +R_0_0, -R_2_0, +R_2_2, +R_2_1, -R_0_1, +R_1_1}, // EXT_YXZ
{+R_0_2, -C_PI_2, -R_1_2, +R_2_2, C_PI_2, +R_2_0, +R_2_2, +R_0_2, +R_0_0, -R_0_1, +R_2_1, +R_1_1}, // EXT_YZX
{+R_1_2, -C_PI_2, -R_0_1, +R_0_0, C_PI_2, +R_0_1, +R_0_0, +R_1_0, +R_1_1, -R_1_2, +R_0_2, +R_2_2}, // EXT_ZXY
{+R_0_2, C_PI_2, +R_1_0, +R_1_1, -C_PI_2, +R_2_1, +R_1_1, -R_0_1, +R_0_0, +R_0_2, -R_1_2, +R_2_2}, // EXT_ZYX
{+R_0_0, C_ZERO, +R_2_1, +R_2_2, C_PI, +R_1_2, +R_1_1, +R_0_1, +R_0_2, +R_0_0, +R_1_0, -R_2_0}, // EXT_XYX
{+R_0_0, C_ZERO, +R_2_1, +R_2_2, C_PI, +R_2_1, +R_2_2, +R_0_2, -R_0_1, +R_0_0, +R_2_0, +R_1_0}, // EXT_XZX
{+R_1_1, C_ZERO, +R_0_2, +R_0_0, C_PI, -R_2_0, +R_0_0, +R_1_0, -R_1_2, +R_1_1, +R_0_1, +R_2_1}, // EXT_YXY
{+R_1_1, C_ZERO, +R_0_2, +R_0_0, C_PI, +R_0_2, -R_0_0, +R_1_2, +R_1_0, +R_1_1, +R_2_1, -R_0_1}, // EXT_YZY
{+R_2_2, C_ZERO, +R_1_0, +R_1_1, C_PI, +R_1_0, +R_0_0, +R_2_0, +R_2_1, +R_2_2, +R_0_2, -R_1_2}, // EXT_ZXZ
{+R_2_2, C_ZERO, +R_1_0, +R_0_0, C_PI, +R_1_0, +R_0_0, +R_2_1, -R_2_0, +R_2_2, +R_1_2, +R_0_2}, // EXT_ZYZ
};
T rotationR[12];
for (int i = 0; i < 12; i++)
{
int id = rotationR_[eulerAnglesType][i];
unsigned idx = std::abs(id);
T value = 0.0f;
if (idx < N_CONSTANTS)
{
value = constants_[idx];
}
else
{
unsigned r_idx = idx - N_CONSTANTS;
CV_DbgAssert(r_idx < 9);
value = R.val[r_idx];
}
bool isNegative = id < 0;
if (isNegative)
value = -value;
rotationR[i] = value;
}
Vec<T, 3> angles;
if (detail::isIntAngleType(eulerAnglesType))
{
if (abs(rotationR[0] - 1) < CV_QUAT_CONVERT_THRESHOLD)
{
CV_LOG_WARNING(NULL,"Gimbal Lock occurs. Euler angles are non-unique, we set the third angle to 0");
angles = {std::atan2(rotationR[1], rotationR[2]), rotationR[3], 0};
return angles;
}
else if(abs(rotationR[0] + 1) < CV_QUAT_CONVERT_THRESHOLD)
{
CV_LOG_WARNING(NULL,"Gimbal Lock occurs. Euler angles are non-unique, we set the third angle to 0");
angles = {std::atan2(rotationR[4], rotationR[5]), rotationR[6], 0};
return angles;
}
}
else // (!detail::isIntAngleType<T>(eulerAnglesType))
{
if (abs(rotationR[0] - 1) < CV_QUAT_CONVERT_THRESHOLD)
{
CV_LOG_WARNING(NULL,"Gimbal Lock occurs. Euler angles are non-unique, we set the first angle to 0");
angles = {0, rotationR[1], std::atan2(rotationR[2], rotationR[3])};
return angles;
}
else if (abs(rotationR[0] + 1) < CV_QUAT_CONVERT_THRESHOLD)
{
CV_LOG_WARNING(NULL,"Gimbal Lock occurs. Euler angles are non-unique, we set the first angle to 0");
angles = {0, rotationR[4], std::atan2(rotationR[5], rotationR[6])};
return angles;
}
}
angles(0) = std::atan2(rotationR[7], rotationR[8]);
if (detail::isTaitBryan(eulerAnglesType))
angles(1) = std::acos(rotationR[9]);
else
angles(1) = std::asin(rotationR[9]);
angles(2) = std::atan2(rotationR[10], rotationR[11]);
return angles;
}
} // namepsace
//! @endcond
@@ -40,7 +40,6 @@ Notes:
#endif
#include "opencv2/core/cvdef.h"
#include "opencv2/core/version.hpp"
#ifdef OPENCV_SIMD_CONFIG_HEADER
#include CVAUX_STR(OPENCV_SIMD_CONFIG_HEADER)
+15 -4
View File
@@ -570,6 +570,8 @@ static inline size_t getElemSize(int type) { return (size_t)CV_ELEM_SIZE(type);
/////////////////////////////// Parallel Primitives //////////////////////////////////
/** @brief Base class for parallel data processors
@ingroup core_parallel
*/
class CV_EXPORTS ParallelLoopBody
{
@@ -579,17 +581,23 @@ public:
};
/** @brief Parallel data processor
@ingroup core_parallel
*/
CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body, double nstripes=-1.);
//! @ingroup core_parallel
class ParallelLoopBodyLambdaWrapper : public ParallelLoopBody
{
private:
std::function<void(const Range&)> m_functor;
public:
ParallelLoopBodyLambdaWrapper(std::function<void(const Range&)> functor) :
m_functor(functor)
{ }
inline
ParallelLoopBodyLambdaWrapper(std::function<void(const Range&)> functor)
: m_functor(functor)
{
// nothing
}
virtual void operator() (const cv::Range& range) const CV_OVERRIDE
{
@@ -597,11 +605,14 @@ public:
}
};
inline void parallel_for_(const Range& range, std::function<void(const Range&)> functor, double nstripes=-1.)
//! @ingroup core_parallel
static inline
void parallel_for_(const Range& range, std::function<void(const Range&)> functor, double nstripes=-1.)
{
parallel_for_(range, ParallelLoopBodyLambdaWrapper(functor), nstripes);
}
/////////////////////////////// forEach method of cv::Mat ////////////////////////////
template<typename _Tp, typename Functor> inline
void Mat::forEach_impl(const Functor& operation) {
@@ -7,13 +7,11 @@
#include "./allocator_stats.hpp"
#ifdef CV_CXX11
#include <atomic>
#endif
//#define OPENCV_DISABLE_ALLOCATOR_STATS
namespace cv { namespace utils {
#ifdef CV_CXX11
#include <atomic>
#ifndef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE
#if defined(__GNUC__) && (\
@@ -28,6 +26,16 @@ namespace cv { namespace utils {
#define OPENCV_ALLOCATOR_STATS_COUNTER_TYPE long long
#endif
#else // CV_CXX11
#ifndef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE
#define OPENCV_ALLOCATOR_STATS_COUNTER_TYPE int // CV_XADD supports int only
#endif
#endif // CV_CXX11
namespace cv { namespace utils {
#ifdef CV__ALLOCATOR_STATS_LOG
namespace {
#endif
@@ -0,0 +1,163 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_UTILS_PLUGIN_LOADER_HPP
#define OPENCV_UTILS_PLUGIN_LOADER_HPP
#include "opencv2/core/utils/filesystem.hpp"
#include "opencv2/core/utils/filesystem.private.hpp"
#if OPENCV_HAVE_FILESYSTEM_SUPPORT
#if defined(_WIN32)
#include <windows.h>
#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__)
#include <dlfcn.h>
#endif
namespace cv { namespace plugin { namespace impl {
#if defined(_WIN32)
typedef HMODULE LibHandle_t;
typedef wchar_t FileSystemChar_t;
typedef std::wstring FileSystemPath_t;
// TODO wchar_t <=> UTF-8
static inline
FileSystemPath_t toFileSystemPath(const std::string& p)
{
FileSystemPath_t result;
result.resize(p.size());
for (size_t i = 0; i < p.size(); i++)
result[i] = (wchar_t)p[i];
return result;
}
// TODO wchar_t <=> UTF-8
static inline
std::string toPrintablePath(const FileSystemPath_t& p)
{
std::string result;
result.resize(p.size());
for (size_t i = 0; i < p.size(); i++)
{
wchar_t ch = p[i];
if ((int)ch >= ' ' && (int)ch < 128)
result[i] = (char)ch;
else
result[i] = '?';
}
return result;
}
#else // !_WIN32
typedef void* LibHandle_t;
typedef char FileSystemChar_t;
typedef std::string FileSystemPath_t;
static inline FileSystemPath_t toFileSystemPath(const std::string& p) { return p; }
static inline std::string toPrintablePath(const FileSystemPath_t& p) { return p; }
#endif
static inline
void* getSymbol_(LibHandle_t h, const char* symbolName)
{
#if defined(_WIN32)
return (void*)GetProcAddress(h, symbolName);
#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__)
return dlsym(h, symbolName);
#endif
}
static inline
LibHandle_t libraryLoad_(const FileSystemPath_t& filename)
{
#if defined(_WIN32)
# ifdef WINRT
return LoadPackagedLibrary(filename.c_str(), 0);
# else
return LoadLibraryW(filename.c_str());
#endif
#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__)
return dlopen(filename.c_str(), RTLD_NOW);
#endif
}
static inline
void libraryRelease_(LibHandle_t h)
{
#if defined(_WIN32)
FreeLibrary(h);
#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__)
dlclose(h);
#endif
}
static inline
std::string libraryPrefix()
{
#if defined(_WIN32)
return "";
#else
return "lib";
#endif
}
static inline
std::string librarySuffix()
{
#if defined(_WIN32)
const char* suffix = ""
CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION)
#if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
"_64"
#endif
#if defined(_DEBUG) && defined(DEBUG_POSTFIX)
CVAUX_STR(DEBUG_POSTFIX)
#endif
".dll";
return suffix;
#else
return ".so";
#endif
}
//============================
class CV_EXPORTS DynamicLib
{
private:
LibHandle_t handle;
const FileSystemPath_t fname;
bool disableAutoUnloading_;
public:
DynamicLib(const FileSystemPath_t& filename);
~DynamicLib();
/** Do not automatically unload library in destructor */
inline void disableAutomaticLibraryUnloading()
{
disableAutoUnloading_ = true;
}
inline bool isLoaded() const
{
return handle != NULL;
}
void* getSymbol(const char* symbolName) const;
const std::string getName() const;
private:
void libraryLoad(const FileSystemPath_t& filename);
void libraryRelease();
private:
DynamicLib(const DynamicLib &) = delete;
DynamicLib &operator=(const DynamicLib &) = delete;
};
}}} // namespace
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
#endif // OPENCV_UTILS_PLUGIN_LOADER_HPP
@@ -5,7 +5,9 @@
#ifndef OPENCV_UTILS_TLS_HPP
#define OPENCV_UTILS_TLS_HPP
#include <opencv2/core/utility.hpp>
#ifndef OPENCV_CORE_UTILITY_H
#error "tls.hpp must be included after opencv2/core/utility.hpp or opencv2/core.hpp"
#endif
namespace cv {
@@ -497,13 +497,15 @@ VSX_IMPL_CONV_EVEN_2_4(vec_uint4, vec_double2, vec_ctu, vec_ctuo)
VSX_FINLINE(rt) fnm(const rg& a, int only_truncate) \
{ \
assert(only_truncate == 0); \
CV_UNUSED(only_truncate); \
CV_UNUSED(only_truncate); \
return fn2(a); \
}
VSX_IMPL_CONV_2VARIANT(vec_int4, vec_float4, vec_cts, vec_cts)
VSX_IMPL_CONV_2VARIANT(vec_uint4, vec_float4, vec_ctu, vec_ctu)
VSX_IMPL_CONV_2VARIANT(vec_float4, vec_int4, vec_ctf, vec_ctf)
VSX_IMPL_CONV_2VARIANT(vec_float4, vec_uint4, vec_ctf, vec_ctf)
// define vec_cts for converting double precision to signed doubleword
// which isn't combitable with xlc but its okay since Eigen only use it for gcc
// which isn't compatible with xlc but its okay since Eigen only uses it for gcc
VSX_IMPL_CONV_2VARIANT(vec_dword2, vec_double2, vec_cts, vec_ctsl)
#endif // Eigen