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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
* - Tait–Bryan 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 Tait–Bryan 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user