//////////////////////////////////////////////////////////////////// // Types.inl // // Copyright 2007 cDc@seacave // Distributed under the Boost Software License, Version 1.0 // (See http://www.boost.org/LICENSE_1_0.txt) // D E F I N E S /////////////////////////////////////////////////// // S T R U C T S /////////////////////////////////////////////////// namespace std { //namespace tr1 { // Specializations for unordered containers template <> struct hash { typedef SEACAVE::ImageRef argument_type; typedef size_t result_type; result_type operator()(const argument_type& v) const { return std::hash()((const uint64_t&)v); } }; //} // namespace tr1 } // namespace std #if CV_MAJOR_VERSION > 3 template INT_TYPE cvRANSACUpdateNumIters(REAL_TYPE p, REAL_TYPE ep, INT_TYPE modelPoints, INT_TYPE maxIters) { ASSERT(p>=0 && p<=1); ASSERT(ep>=0 && ep<=1); // avoid inf's & nan's REAL_TYPE num = MAXF(REAL_TYPE(1)-p, SEACAVE::EPSILONTOLERANCE()); REAL_TYPE denom = REAL_TYPE(1)-POWI(REAL_TYPE(1)-ep, modelPoints); if (denom < SEACAVE::EPSILONTOLERANCE()) return 0; num = SEACAVE::LOGN(num); denom = SEACAVE::LOGN(denom); return (denom >= 0 || -num >= (-denom)*maxIters ? maxIters : ROUND2INT(num/denom)); } #endif namespace cv { #if CV_MAJOR_VERSION > 2 template<> class DataType { public: typedef unsigned value_type; typedef value_type work_type; typedef value_type channel_type; typedef value_type vec_type; enum { generic_type = 0, depth = CV_32S, channels = 1, fmt = (int)'i', type = CV_MAKETYPE(depth, channels) }; }; #else #if CV_MINOR_VERSION < 4 template static inline _AccTp normL2Sqr(const _Tp* a, int n) { _AccTp s = 0; int i=0; #if CV_ENABLE_UNROLLED for (; i <= n - 4; i += 4) { _AccTp v0 = a[i], v1 = a[i+1], v2 = a[i+2], v3 = a[i+3]; s += v0*v0 + v1*v1 + v2*v2 + v3*v3; } #endif for (; i < n; i++) { _AccTp v = a[i]; s += v*v; } return s; } #endif #if CV_MINOR_VERSION < 4 || CV_SUBMINOR_VERSION < 11 // Convenience creation functions. In the far future, there may be variadic templates here. template Ptr makePtr() { return Ptr(new T()); } template Ptr makePtr(const A1& a1) { return Ptr(new T(a1)); } template Ptr makePtr(const A1& a1, const A2& a2) { return Ptr(new T(a1, a2)); } template Ptr makePtr(const A1& a1, const A2& a2, const A3& a3) { return Ptr(new T(a1, a2, a3)); } template Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4) { return Ptr(new T(a1, a2, a3, a4)); } template Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { return Ptr(new T(a1, a2, a3, a4, a5)); } template Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) { return Ptr(new T(a1, a2, a3, a4, a5, a6)); } template Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) { return Ptr(new T(a1, a2, a3, a4, a5, a6, a7)); } template Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) { return Ptr(new T(a1, a2, a3, a4, a5, a6, a7, a8)); } template Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) { return Ptr(new T(a1, a2, a3, a4, a5, a6, a7, a8, a9)); } template Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) { return Ptr(new T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)); } #endif // property implementation macros #define CV_IMPL_PROPERTY_RO(type, name, member) \ inline type get##name() const { return member; } #define CV_HELP_IMPL_PROPERTY(r_type, w_type, name, member) \ CV_IMPL_PROPERTY_RO(r_type, name, member) \ inline void set##name(w_type val) { member = val; } #define CV_HELP_WRAP_PROPERTY(r_type, w_type, name, internal_name, internal_obj) \ r_type get##name() const { return internal_obj.get##internal_name(); } \ void set##name(w_type val) { internal_obj.set##internal_name(val); } #define CV_IMPL_PROPERTY(type, name, member) CV_HELP_IMPL_PROPERTY(type, type, name, member) #define CV_IMPL_PROPERTY_S(type, name, member) CV_HELP_IMPL_PROPERTY(type, const type &, name, member) #define CV_WRAP_PROPERTY(type, name, internal_name, internal_obj) CV_HELP_WRAP_PROPERTY(type, type, name, internal_name, internal_obj) #define CV_WRAP_PROPERTY_S(type, name, internal_name, internal_obj) CV_HELP_WRAP_PROPERTY(type, const type &, name, internal_name, internal_obj) #define CV_WRAP_SAME_PROPERTY(type, name, internal_obj) CV_WRAP_PROPERTY(type, name, name, internal_obj) #define CV_WRAP_SAME_PROPERTY_S(type, name, internal_obj) CV_WRAP_PROPERTY_S(type, name, name, internal_obj) #endif //! copy every second source image element to the destination image inline void downsample2x(InputArray _src, OutputArray _dst) { Mat src(_src.getMat()); #if 1 _dst.create((src.rows+1)/2, (src.cols+1)/2, src.type()); #else if (_dst.empty()) { // create a new matrix _dst.create(src.rows/2, src.cols/2, src.type()); } else { // overwrite elements in the existing matrix ASSERT(src.rows > 0 && (unsigned)(src.rows-_dst.size().height*2) <= 1); ASSERT(src.cols > 0 && (unsigned)(src.cols-_dst.size().width*2) <= 1); ASSERT(src.type() == _dst.type()); } #endif Mat dst(_dst.getMat()); ASSERT(src.elemSize() == dst.elemSize()); switch (src.elemSize()) { case 1: for (int i=0; i(i,j) = src.at(2*i,2*j); break; case 2: for (int i=0; i(i,j) = src.at(2*i,2*j); break; case 4: for (int i=0; i(i,j) = src.at(2*i,2*j); break; case 8: for (int i=0; i(i,j) = src.at(2*i,2*j); break; default: for (int i=0; i 0 && src.rows*2-1 <= _dst.size().height); ASSERT(src.cols > 0 && src.cols*2-1 <= _dst.size().width); ASSERT(src.type() == _dst.type()); } Mat dst(_dst.getMat()); ASSERT(src.elemSize() == dst.elemSize()); switch (src.elemSize()) { case 1: for (int i=0; i(2*i,2*j) = src.at(i,j); break; case 2: for (int i=0; i(2*i,2*j) = src.at(i,j); break; case 4: for (int i=0; i(2*i,2*j) = src.at(i,j); break; case 8: for (int i=0; i(2*i,2*j) = src.at(i,j); break; default: for (int i=0; i const typename ColorType::value_type ColorType::ONE(1); template const typename ColorType::alt_type ColorType::ALTONE(1); template const TPixel TPixel::BLACK (0, 0, 0); template const TPixel TPixel::WHITE (ColorType::ONE, ColorType::ONE, ColorType::ONE); template const TPixel TPixel::GRAY (0.8f*ColorType::ONE, 0.8f*ColorType::ONE, 0.8f*ColorType::ONE); template const TPixel TPixel::RED (ColorType::ONE, 0, 0); template const TPixel TPixel::GREEN (0, ColorType::ONE, 0); template const TPixel TPixel::BLUE (0, 0, ColorType::ONE); template const TPixel TPixel::YELLOW (ColorType::ONE, ColorType::ONE, 0); template const TPixel TPixel::MAGENTA (ColorType::ONE, 0, ColorType::ONE); template const TPixel TPixel::CYAN (0, ColorType::ONE, ColorType::ONE); template const TColor TColor::BLACK (0, 0, 0, ColorType::ONE); template const TColor TColor::WHITE (ColorType::ONE, ColorType::ONE, ColorType::ONE, ColorType::ONE); template const TColor TColor::GRAY (0.8f*ColorType::ONE, 0.8f*ColorType::ONE, 0.8f*ColorType::ONE, ColorType::ONE); template const TColor TColor::RED (ColorType::ONE, 0, 0, ColorType::ONE); template const TColor TColor::GREEN (0, ColorType::ONE, 0, ColorType::ONE); template const TColor TColor::BLUE (0, 0, ColorType::ONE, ColorType::ONE); template const TColor TColor::YELLOW (ColorType::ONE, ColorType::ONE, 0, ColorType::ONE); template const TColor TColor::MAGENTA (ColorType::ONE, 0, ColorType::ONE, ColorType::ONE); template const TColor TColor::CYAN (0, ColorType::ONE, ColorType::ONE, ColorType::ONE); #ifdef _SUPPORT_CPP11 template inline typename std::enable_if::value, size_t>::type SizeOfArray(const A&) { return std::extent::value; } #else template inline size_t SizeOfArray(const T(&)[N]) { return N; } #endif // C L A S S ////////////////////////////////////////////////////// // square template FORCEINLINE SEACAVE::TPoint2 SQUARE(const SEACAVE::TPoint2& v) { return SEACAVE::TPoint2(SQUARE(v.x), SQUARE(v.y)); } template FORCEINLINE SEACAVE::TPoint3 SQUARE(const SEACAVE::TPoint3& v) { return SEACAVE::TPoint3(SQUARE(v.x), SQUARE(v.y), SQUARE(v.z)); } template FORCEINLINE SEACAVE::TMatrix SQUARE(const SEACAVE::TMatrix& v) { SEACAVE::TMatrix nv; for (int i=0; i FORCEINLINE SEACAVE::TPoint2 SQUARE(const cv::Point_& v) { return SEACAVE::TPoint2(SQUARE(v.x), SQUARE(v.y)); } template FORCEINLINE SEACAVE::TPoint3 SQUARE(const cv::Point3_& v) { return SEACAVE::TPoint3(SQUARE(v.x), SQUARE(v.y), SQUARE(v.z)); } template FORCEINLINE SEACAVE::TMatrix SQUARE(const cv::Matx& v) { SEACAVE::TMatrix nv; for (int i=0; i FORCEINLINE SEACAVE::TPixel SQUARE(const SEACAVE::TPixel& v) { return SEACAVE::TPixel(SQUARE(v.r), SQUARE(v.g), SQUARE(v.b)); } template FORCEINLINE SEACAVE::TColor SQUARE(const SEACAVE::TColor& v) { return SEACAVE::TColor(SQUARE(v.r), SQUARE(v.g), SQUARE(v.b), SQUARE(v.a)); } // sqrt template FORCEINLINE SEACAVE::TPoint2 SQRT(const SEACAVE::TPoint2& v) { return SEACAVE::TPoint2(SQRT(v.x), SQRT(v.y)); } template FORCEINLINE SEACAVE::TPoint3 SQRT(const SEACAVE::TPoint3& v) { return SEACAVE::TPoint3(SQRT(v.x), SQRT(v.y), SQRT(v.z)); } template FORCEINLINE SEACAVE::TMatrix SQRT(const SEACAVE::TMatrix& v) { SEACAVE::TMatrix nv; for (int i=0; i FORCEINLINE SEACAVE::TPoint2 SQRT(const cv::Point_& v) { return SEACAVE::TPoint2(SQRT(v.x), SQRT(v.y)); } template FORCEINLINE SEACAVE::TPoint3 SQRT(const cv::Point3_& v) { return SEACAVE::TPoint3(SQRT(v.x), SQRT(v.y), SQRT(v.z)); } template FORCEINLINE SEACAVE::TMatrix SQRT(const cv::Matx& v) { SEACAVE::TMatrix nv; for (int i=0; i FORCEINLINE SEACAVE::TPixel SQRT(const SEACAVE::TPixel& v) { return SEACAVE::TPixel(SQRT(v.r), SQRT(v.g), SQRT(v.b)); } template FORCEINLINE SEACAVE::TColor SQRT(const SEACAVE::TColor& v) { return SEACAVE::TColor(SQRT(v.r), SQRT(v.g), SQRT(v.b), SQRT(v.a)); } // exp template FORCEINLINE SEACAVE::TPoint2 EXP(const SEACAVE::TPoint2& v) { return SEACAVE::TPoint2(EXP(v.x), EXP(v.y)); } template FORCEINLINE SEACAVE::TPoint3 EXP(const SEACAVE::TPoint3& v) { return SEACAVE::TPoint3(EXP(v.x), EXP(v.y), EXP(v.z)); } template FORCEINLINE SEACAVE::TMatrix EXP(const SEACAVE::TMatrix& v) { SEACAVE::TMatrix nv; for (int i=0; i FORCEINLINE SEACAVE::TPoint2 EXP(const cv::Point_& v) { return SEACAVE::TPoint2(EXP(v.x), EXP(v.y)); } template FORCEINLINE SEACAVE::TPoint3 EXP(const cv::Point3_& v) { return SEACAVE::TPoint3(EXP(v.x), EXP(v.y), EXP(v.z)); } template FORCEINLINE SEACAVE::TMatrix EXP(const cv::Matx& v) { SEACAVE::TMatrix nv; for (int i=0; i FORCEINLINE SEACAVE::TPixel EXP(const SEACAVE::TPixel& v) { return SEACAVE::TPixel(EXP(v.r), EXP(v.g), EXP(v.b)); } template FORCEINLINE SEACAVE::TColor EXP(const SEACAVE::TColor& v) { return SEACAVE::TColor(EXP(v.r), EXP(v.g), EXP(v.b), EXP(v.a)); } // loge template FORCEINLINE SEACAVE::TPoint2 LOGN(const SEACAVE::TPoint2& v) { return SEACAVE::TPoint2(LOGN(v.x), LOGN(v.y)); } template FORCEINLINE SEACAVE::TPoint3 LOGN(const SEACAVE::TPoint3& v) { return SEACAVE::TPoint3(LOGN(v.x), LOGN(v.y), LOGN(v.z)); } template FORCEINLINE SEACAVE::TMatrix LOGN(const SEACAVE::TMatrix& v) { SEACAVE::TMatrix nv; for (int i=0; i FORCEINLINE SEACAVE::TPoint2 LOGN(const cv::Point_& v) { return SEACAVE::TPoint2(LOGN(v.x), LOGN(v.y)); } template FORCEINLINE SEACAVE::TPoint3 LOGN(const cv::Point3_& v) { return SEACAVE::TPoint3(LOGN(v.x), LOGN(v.y), LOGN(v.z)); } template FORCEINLINE SEACAVE::TMatrix LOGN(const cv::Matx& v) { SEACAVE::TMatrix nv; for (int i=0; i FORCEINLINE SEACAVE::TPixel LOGN(const SEACAVE::TPixel& v) { return SEACAVE::TPixel(LOGN(v.r), LOGN(v.g), LOGN(v.b)); } template FORCEINLINE SEACAVE::TColor LOGN(const SEACAVE::TColor& v) { return SEACAVE::TColor(LOGN(v.r), LOGN(v.g), LOGN(v.b), LOGN(v.a)); } // abs template FORCEINLINE SEACAVE::TPoint2 ABS(const SEACAVE::TPoint2& v) { return SEACAVE::TPoint2(ABS(v.x), ABS(v.y)); } template FORCEINLINE SEACAVE::TPoint3 ABS(const SEACAVE::TPoint3& v) { return SEACAVE::TPoint3(ABS(v.x), ABS(v.y), ABS(v.z)); } template FORCEINLINE SEACAVE::TMatrix ABS(const SEACAVE::TMatrix& v) { SEACAVE::TMatrix nv; for (int i=0; i FORCEINLINE SEACAVE::TPoint2 ABS(const cv::Point_& v) { return SEACAVE::TPoint2(ABS(v.x), ABS(v.y)); } template FORCEINLINE SEACAVE::TPoint3 ABS(const cv::Point3_& v) { return SEACAVE::TPoint3(ABS(v.x), ABS(v.y), ABS(v.z)); } template FORCEINLINE SEACAVE::TMatrix ABS(const cv::Matx& v) { SEACAVE::TMatrix nv; for (int i=0; i FORCEINLINE bool ISZERO(const cv::Point_& v) { return (ISZERO(v.x) && ISZERO(v.y)); } template FORCEINLINE bool ISZERO(const cv::Point3_& v) { return (ISZERO(v.x) && ISZERO(v.y) && ISZERO(v.z)); } template FORCEINLINE bool ISZERO(const cv::Matx& v) { for (int i=0; i FORCEINLINE bool ISEQUAL(const cv::Point_& v1, const cv::Point_& v2) { return (ISEQUAL(v1.x,v2.x) && ISEQUAL(v1.y,v2.y)); } template FORCEINLINE bool ISEQUAL(const cv::Point3_& v1, const cv::Point3_& v2) { return (ISEQUAL(v1.x,v2.x) && ISEQUAL(v1.y,v2.y) && ISEQUAL(v1.z,v2.z)); } template FORCEINLINE bool ISEQUAL(const cv::Matx& v1, const cv::Matx& v2) { for (int i=0; i FORCEINLINE SEACAVE::TPoint2 Floor2Int(const cv::Point_& v) { return SEACAVE::TPoint2(FLOOR2INT(v.x), FLOOR2INT(v.y)); } template FORCEINLINE SEACAVE::TPoint2 Ceil2Int(const cv::Point_& v) { return SEACAVE::TPoint2(CEIL2INT(v.x), CEIL2INT(v.y)); } template FORCEINLINE SEACAVE::TPoint2 Round2Int(const cv::Point_& v) { return SEACAVE::TPoint2(ROUND2INT(v.x), ROUND2INT(v.y)); } template FORCEINLINE SEACAVE::TPoint3 Floor2Int(const cv::Point3_& v) { return SEACAVE::TPoint3(FLOOR2INT(v.x), FLOOR2INT(v.y), FLOOR2INT(v.z)); } template FORCEINLINE SEACAVE::TPoint3 Ceil2Int(const cv::Point3_& v) { return SEACAVE::TPoint3(CEIL2INT(v.x), CEIL2INT(v.y), CEIL2INT(v.z)); } template FORCEINLINE SEACAVE::TPoint3 Round2Int(const cv::Point3_& v) { return SEACAVE::TPoint3(ROUND2INT(v.x), ROUND2INT(v.y), ROUND2INT(v.z)); } template FORCEINLINE SEACAVE::TMatrix Floor2Int(const cv::Matx& v) { SEACAVE::TMatrix nv; for (int i=0; i(v.val[i]); return nv; } template FORCEINLINE SEACAVE::TMatrix Ceil2Int(const cv::Matx& v) { SEACAVE::TMatrix nv; for (int i=0; i(v.val[i]); return nv; } template FORCEINLINE SEACAVE::TMatrix Round2Int(const cv::Matx& v) { SEACAVE::TMatrix nv; for (int i=0; i(v.val[i]); return nv; } // ISFINITE template FORCEINLINE bool ISFINITE(const SEACAVE::TPoint2& v) { return (ISFINITE(v.x) && ISFINITE(v.y)); } template FORCEINLINE bool ISFINITE(const SEACAVE::TPoint3& v) { return (ISFINITE(v.x) && ISFINITE(v.y) && ISFINITE(v.z)); } template FORCEINLINE bool ISFINITE(const SEACAVE::TDMatrix& v) { ASSERT(v.isContinuous()); return ISFINITE(v.val, v.area()); } template FORCEINLINE bool ISFINITE(const cv::Point_& v) { return (ISFINITE(v.x) && ISFINITE(v.y)); } template FORCEINLINE bool ISFINITE(const cv::Point3_& v) { return (ISFINITE(v.x) && ISFINITE(v.y) && ISFINITE(v.z)); } template FORCEINLINE bool ISFINITE(const cv::Matx& v) { ASSERT(v.isContinuous()); return ISFINITE(v.val, m*n); } template FORCEINLINE bool ISFINITE(const Eigen::Matrix& m) { return ISFINITE(m.data(), m.size()); } // initializing both scalar and matrix variables template FORCEINLINE Scalar INITTO(const Scalar*, Value v) { return static_cast(v); } template FORCEINLINE TPoint2 INITTO(const TPoint2*, Value v) { return TPoint2(static_cast(v)); } template FORCEINLINE TPoint3 INITTO(const TPoint3*, Value v) { return TPoint3(static_cast(v)); } template FORCEINLINE Eigen::Matrix INITTO(const Eigen::Matrix*, Value v) { return Eigen::Matrix::Constant(static_cast(v)); } /*----------------------------------------------------------------*/ template inline IDX MinIndex(const TYPE* data, IDX size) { ASSERT(size>0); IDX idx = 0; for (IDX i=1; i data[i]) idx = i; return idx; } template inline IDX MaxIndex(const TYPE* data, IDX size) { ASSERT(size>0); IDX idx = 0; for (IDX i=1; i inline ACCTYPE dot(const TYPE* a, const TYPE* b, size_t n) { ACCTYPE s(0); const TYPE* const last = a+n; #if 1 // unrolled const TYPE* const lastgroup = last-3; while (a < lastgroup) { s += ACCTYPE(a[0])*ACCTYPE(b[0]) + ACCTYPE(a[1])*ACCTYPE(b[1]) + ACCTYPE(a[2])*ACCTYPE(b[2]) + ACCTYPE(a[3])*ACCTYPE(b[3]); a += 4; b += 4; } #endif while (a < last) s += ACCTYPE(*a++) * ACCTYPE(*b++); return s; } template inline ACCTYPE dot(const TYPE* a, const TYPE* b) { ACCTYPE s(0); const TYPE* const last = a+N; #if 1 // unrolled const TYPE* const lastgroup = last-3; while (a < lastgroup) { s += ACCTYPE(a[0])*ACCTYPE(b[0]) + ACCTYPE(a[1])*ACCTYPE(b[1]) + ACCTYPE(a[2])*ACCTYPE(b[2]) + ACCTYPE(a[3])*ACCTYPE(b[3]); a += 4; b += 4; } #endif while (a < last) s += ACCTYPE(*a++) * ACCTYPE(*b++); return s; } #ifdef _USE_SSE template <> inline float dot(const float* l, const float* r, size_t size) { return sse_f_t::dot(l, r, size); } template <> inline double dot(const double* l, const double* r, size_t size) { return sse_d_t::dot(l, r, size); } #endif template inline TYPE dot(const TMatrix& l, const TMatrix& r) { return ((const cv::Vec&)l).dot((const cv::Vec&)r); } template inline TYPE dot(const cv::Matx& l, const cv::Matx& r) { return ((const cv::Vec&)l).dot((const cv::Vec&)r); } inline float dot(float v1, float v2) { return v1 * v2; } inline double dot(double v1, double v2) { return v1 * v2; } template inline TYPE dot(const cv::Point_* v1, const cv::Point_* v2, size_t size) { return dot((const TYPE*)v1, (const TYPE*)v2, size*2); } template inline TYPE dot(const cv::Point3_* v1, const cv::Point3_* v2, size_t size) { return dot((const TYPE*)v1, (const TYPE*)v2, size*3); } template inline TYPE dot(const cv::Vec* v1, const cv::Vec* v2, size_t size) { return dot((const TYPE*)v1, (const TYPE*)v2, size*m); } template inline TMatrix cross(const TMatrix& l, const TMatrix& r) { return ((const typename TMatrix::Vec&)l).cross((const typename TMatrix::Vec&)r); } template inline TMatrix cross(const cv::Matx& l, const cv::Matx& r) { return ((const typename TMatrix::Vec&)l).cross((const typename TMatrix::Vec&)r); } template inline typename RealType::type normSq(const cv::Point_& v) { typedef typename RealType::type real; return SQUARE((real)v.x)+SQUARE((real)v.y); } template inline typename RealType::type normSq(const cv::Point3_& v) { typedef typename RealType::type real; return SQUARE((real)v.x)+SQUARE((real)v.y)+SQUARE((real)v.z); } template inline typename RealType::type normSq(const TMatrix& v) { typedef typename RealType::type real; return cv::normL2Sqr(v.val, m*n); } template inline typename RealType::type normSq(const cv::Matx& v) { typedef typename RealType::type real; return cv::normL2Sqr(v.val, m*n); } template inline typename RealType::type normSq(const TDMatrix& v) { typedef typename RealType::type real; return cv::normL2Sqr(v.cv::Mat::template ptr(), v.area()); } template inline typename RealType::type normSq(const cv::Mat_& v) { typedef typename RealType::type real; return cv::normL2Sqr(v.cv::Mat::template ptr(), v.cols*v.rows); } inline REAL normSq(int v) { return SQUARE((REAL)v); } inline REAL normSq(unsigned v) { return SQUARE((REAL)v); } inline float normSq(float v) { return SQUARE(v); } inline double normSq(double v) { return SQUARE(v); } template inline typename RealType::type normSq(const cv::Point_* v, size_t size) { typedef typename RealType::type real; return cv::normL2Sqr((const TYPE*)v, size*2); } template inline typename RealType::type normSq(const cv::Point3_* v, size_t size) { typedef typename RealType::type real; return cv::normL2Sqr((const TYPE*)v, size*3); } template inline typename RealType::type normSq(const cv::Vec* v, size_t size) { typedef typename RealType::type real; return cv::normL2Sqr((const TYPE*)v, size*m); } template inline ACCTYPE normSq(const TYPE* a, size_t n) { ACCTYPE s(0); const TYPE* const last = a+n; #if 1 // unrolled const TYPE* const lastgroup = last-3; while (a < lastgroup) { s += SQUARE(ACCTYPE(a[0])) + SQUARE(ACCTYPE(a[1])) + SQUARE(ACCTYPE(a[2])) + SQUARE(ACCTYPE(a[3])); a += 4; } #endif while (a < last) s += SQUARE(ACCTYPE(*a++)); return s; } template inline ACCTYPE normSq(const TYPE* a) { ACCTYPE s(0); const TYPE* const last = a+N; #if 1 // unrolled const TYPE* const lastgroup = last-3; while (a < lastgroup) { s += SQUARE(ACCTYPE(a[0])) + SQUARE(ACCTYPE(a[1])) + SQUARE(ACCTYPE(a[2])) + SQUARE(ACCTYPE(a[3])); a += 4; } #endif while (a < last) s += SQUARE(ACCTYPE(*a++)); return s; } template inline ACCTYPE normSq(const TYPE* a, const TYPE* b, size_t n) { ACCTYPE s(0); const TYPE* const last = a+n; #if 1 // unrolled const TYPE* const lastgroup = last-3; while (a < lastgroup) { const INTTYPE v0(a[0] - b[0]), v1(a[1] - b[1]), v2(a[2] - b[2]), v3(a[3] - b[3]); s += ACCTYPE(v0*v0 + v1*v1 + v2*v2 + v3*v3); a += 4; b += 4; } #endif while (a < last) { const INTTYPE v(*a++ - *b++); s += ACCTYPE(v*v); } return s; } template inline ACCTYPE normSq(const TYPE* a, const TYPE* b) { ACCTYPE s(0); const TYPE* const last = a+N; #if 1 // unrolled const TYPE* const lastgroup = last-3; while (a < lastgroup) { const INTTYPE v0(a[0] - b[0]), v1(a[1] - b[1]), v2(a[2] - b[2]), v3(a[3] - b[3]); s += ACCTYPE(v0*v0 + v1*v1 + v2*v2 + v3*v3); a += 4; b += 4; } #endif while (a < last) { const INTTYPE v(*a++ - *b++); s += ACCTYPE(v*v); } return s; } template inline ACCTYPE normSqDelta(TYPE* a, size_t n, const ACCTYPE avg) { ACCTYPE s(0); const TYPE* const last = a+n; #if 1 // unrolled const TYPE* const lastgroup = last-3; while (a < lastgroup) { const ACCTYPE v0(a[0]-=avg), v1(a[1]-=avg), v2(a[2]-=avg), v3(a[3]-=avg); s += v0*v0 + v1*v1 + v2*v2 + v3*v3; a += 4; } #endif while (a < last) { const ACCTYPE v(*a++ -= avg); s += v*v; } return s; } template inline ACCTYPE normSqDelta(TYPE* a, const ACCTYPE avg) { ACCTYPE s(0); const TYPE* const last = a+N; #if 1 // unrolled const TYPE* const lastgroup = last-3; while (a < lastgroup) { const ACCTYPE v0(a[0]-=avg), v1(a[1]-=avg), v2(a[2]-=avg), v3(a[3]-=avg); s += v0*v0 + v1*v1 + v2*v2 + v3*v3; a += 4; } #endif while (a < last) { const ACCTYPE v(*a++ -= avg); s += v*v; } return s; } template inline ACCTYPE normSqZeroMean(TYPE* ptr, size_t n) { TYPE* a = ptr; ACCTYPE avg(0); const TYPE* const last = a+n; #if 1 // unrolled const TYPE* const lastgroup = last-3; while (a < lastgroup) { avg += ACCTYPE(a[0]) + ACCTYPE(a[1]) + ACCTYPE(a[2]) + ACCTYPE(a[3]); a += 4; } #endif while (a < last) avg += ACCTYPE(*a++); avg /= (ACCTYPE)n; a = ptr; ACCTYPE s(0); #if 1 // unrolled while (a < lastgroup) { const ACCTYPE v0(a[0]-=avg), v1(a[1]-=avg), v2(a[2]-=avg), v3(a[3]-=avg); s += v0*v0 + v1*v1 + v2*v2 + v3*v3; a += 4; } #endif while (a < last) { const ACCTYPE v(*a++ -= avg); s += v*v; } return s; } template inline ACCTYPE normSqZeroMean(TYPE* ptr) { TYPE* a = ptr; ACCTYPE avg(0); const TYPE* const last = a+N; #if 1 // unrolled const TYPE* const lastgroup = last-3; while (a < lastgroup) { avg += ACCTYPE(a[0]) + ACCTYPE(a[1]) + ACCTYPE(a[2]) + ACCTYPE(a[3]); a += 4; } #endif while (a < last) avg += ACCTYPE(*a++); avg /= (ACCTYPE)N; a = ptr; ACCTYPE s(0); #if 1 // unrolled while (a < lastgroup) { const ACCTYPE v0(a[0]-=avg), v1(a[1]-=avg), v2(a[2]-=avg), v3(a[3]-=avg); s += v0*v0 + v1*v1 + v2*v2 + v3*v3; a += 4; } #endif while (a < last) { const ACCTYPE v(*a++ -= avg); s += v*v; } return s; } template inline typename RealType::type norm(const TPoint2& v) { return SQRT(normSq(v)); } template inline typename RealType::type norm(const TPoint3& v) { return SQRT(normSq(v)); } template inline typename RealType::type norm(const TMatrix& v) { typedef typename RealType::type real; return SQRT(cv::normL2Sqr(v.val, m*n)); } template inline typename RealType::type norm(const TDMatrix& v) { typedef typename RealType::type real; return SQRT(cv::normL2Sqr(v.cv::Mat::template ptr(), v.area())); } template inline TPoint2 normalized(const TPoint2& v) { return cv::normalize((const typename TPoint2::cvVec&)v); } template inline TPoint2 normalized(const cv::Point_& v) { return cv::normalize((const typename TPoint2::cvVec&)v); } template inline TPoint3 normalized(const TPoint3& v) { return cv::normalize((const typename TPoint3::cvVec&)v); } template inline TPoint3 normalized(const cv::Point3_& v) { return cv::normalize((const typename TPoint3::cvVec&)v); } template inline TMatrix normalized(const TMatrix& v) { return cv::normalize((const typename TMatrix::Vec&)v); } template inline TMatrix normalized(const cv::Matx& v) { return cv::normalize((const typename TMatrix::Vec&)v); } template inline void normalize(TPoint2& v) { (typename TPoint2::cvVec&)v = cv::normalize((const typename TPoint2::cvVec&)v); } template inline void normalize(cv::Point_& v) { (typename TPoint2::cvVec&)v = cv::normalize((const typename TPoint2::cvVec&)v); } template inline void normalize(TPoint3& v) { (typename TPoint3::cvVec&)v = cv::normalize((const typename TPoint3::cvVec&)v); } template inline void normalize(cv::Point3_& v) { (typename TPoint3::cvVec&)v = cv::normalize((const typename TPoint3::cvVec&)v); } template inline void normalize(TMatrix& v) { (typename TMatrix::Vec&)v = cv::normalize((const typename TMatrix::Vec&)v); } template inline void normalize(cv::Matx& v) { (typename TMatrix::Vec&)v = cv::normalize((const typename TMatrix::Vec&)v); } template inline TYPE area(const TPoint2& v1, const TPoint2& v2) { return ABS(v1.x * v2.y - v1.y * v2.x); } template inline TYPE area(const cv::Point_& v1, const cv::Point_& v2) { return ABS(v1.x * v2.y - v1.y * v2.x); } template inline TYPE area(const TPoint3& v1, const TPoint3& v2) { return norm(cross(v1,v2)); } template inline TYPE area(const cv::Point3_& v1, const cv::Point3_& v2) { return norm(cross(v1,v2)); } /*----------------------------------------------------------------*/ /** @brief comparison function for floating point values See http://www.boost.org/libs/test/doc/components/test_tools/floating_point_comparison.html */ template // left == right inline bool equal(const _Tp& left, const _Tp& right, const _Tp& = std::numeric_limits<_Tp>::epsilon()) { return (left==right); } template<> inline bool equal(const double& left, const double& right, const double& eps) { // the code below does not work when one value is zero if (left==0. || right==0.) return (ABS(left-right) <= eps); // compare two non-zero values return (ABS(left-right) <= eps*MAXF(ABS(right),ABS(left))); } template<> inline bool equal(const float& left, const float& right, const float& eps) { // the code below does not work when one value is zero if (left==0. || right==0.) return (ABS(left-right) <= eps); // compare two non-zero values return (ABS(left-right) <= eps*MAXF(ABS(right),ABS(left))); } /** @brief comparison function for floating point values */ template // left < right inline bool less(const _Tp& left, const _Tp& right, const _Tp& eps = std::numeric_limits<_Tp>::epsilon()) { if (left==0. || right==0.) return (right-left) > eps; return ((right-left) > eps * MINF(right,left)); } /** @brief comparison function for floating point values */ template // left <= right inline bool lessEqual(const _Tp& left, const _Tp& right, const _Tp& eps = std::numeric_limits<_Tp>::epsilon()) { return (less(left, right, eps) || equal(left, right, eps)); } /** @brief comparison function for floating point values */ template // left > right inline bool greater(const _Tp& left, const _Tp& right, const _Tp& eps = std::numeric_limits<_Tp>::epsilon()) { if (left==0. || right==0.) return (left-right) > eps; return ((left-right) > eps * MINF(right,left)); } /** @brief comparison function for floating point values */ template // left >= right inline bool greaterEqual(const _Tp& left, const _Tp& right, const _Tp& eps = std::numeric_limits<_Tp>::epsilon()) { return (greater(left,right) || equal(left, right, eps)); } /*----------------------------------------------------------------*/ /** @brief determine the number of decimals to store, w.g. to file @returns the number of decimals between lower bound guaranteed precision (digits10) and the upper bound max. precision (nr. of binary digits) */ #ifdef WIN32 # pragma warning(push, 2) #endif // WIN32 template inline unsigned decimalsToStore() { if (std::numeric_limits<_Tp>::is_integer){ // integer types can display exactly one decimal more than their guaranteed precision digits return std::numeric_limits<_Tp>::digits10+1; } else { //return std::numeric_limits<_Tp>::digits10; // lower bound return std::numeric_limits<_Tp>::digits; // upper bound } } #ifdef WIN32 # pragma warning(pop) #endif // WIN32 /*----------------------------------------------------------------*/ // operators // TPoint2 operators #if CV_MAJOR_VERSION > 2 template inline TPoint2 operator/(const TPoint2& pt, TYPEM m) { return TPoint2(pt.x/m, pt.y/m); } template inline TPoint2 operator/(const TPoint2& pt, TYPEM m) { const float invm(INVERT(float(m))); return TPoint2(invm*pt.x, invm*pt.y); } template inline TPoint2 operator/(const TPoint2& pt, TYPEM m) { const double invm(INVERT(double(m))); return TPoint2(invm*pt.x, invm*pt.y); } template inline TPoint2& operator/=(TPoint2& pt, TYPEM m) { pt.x /= m; pt.y /= m; return pt; } template inline TPoint2& operator/=(TPoint2& pt, TYPEM m) { const float invm(INVERT(float(m))); pt.x *= invm; pt.y *= invm; return pt; } template inline TPoint2& operator/=(TPoint2& pt, TYPEM m) { const double invm(INVERT(double(m))); pt.x *= invm; pt.y *= invm; return pt; } #else template inline TPoint2 operator/(const cv::Point_& pt, TYPEM m) { return TPoint2(pt.x/m, pt.y/m); } template inline TPoint2 operator/(const cv::Point_& pt, TYPEM m) { const float invm(INVERT(float(m))); return TPoint2(invm*pt.x, invm*pt.y); } template inline TPoint2 operator/(const cv::Point_& pt, TYPEM m) { const double invm(INVERT(double(m))); return TPoint2(invm*pt.x, invm*pt.y); } template inline TPoint2& operator/=(cv::Point_& pt, TYPEM m) { pt.x /= m; pt.y /= m; return (TPoint2&)pt; } template inline TPoint2& operator/=(cv::Point_& pt, TYPEM m) { const float invm(INVERT(float(m))); pt.x *= invm; pt.y *= invm; return (TPoint2&)pt; } template inline TPoint2& operator/=(cv::Point_& pt, TYPEM m) { const double invm(INVERT(double(m))); pt.x *= invm; pt.y *= invm; return (TPoint2&)pt; } #endif template inline TPoint2 operator/(const cv::Point_& pt0, const cv::Point_& pt1) { return TPoint2(pt0.x/pt1.x, pt0.y/pt1.y); } template inline TPoint2& operator/=(cv::Point_& pt0, const cv::Point_& pt1) { pt0.x/=pt1.x; pt0.y/=pt1.y; return (TPoint2&)pt0; } template inline TPoint2 operator*(const cv::Point_& pt0, const cv::Point_& pt1) { return TPoint2(pt0.x*pt1.x, pt0.y*pt1.y); } template inline TPoint2& operator*=(cv::Point_& pt0, const cv::Point_& pt1) { pt0.x*=pt1.x; pt0.y*=pt1.y; return (TPoint2&)pt0; } template inline TPoint2 cvtPoint2(const TPoint2& p) { return TPoint2(TTO(p.x), TTO(p.y)); } // TPoint3 operators #if CV_MAJOR_VERSION > 2 template inline TPoint3 operator/(const TPoint3& pt, TYPEM m) { return TPoint3(pt.x/m, pt.y/m, pt.z/m); } template inline TPoint3 operator/(const TPoint3& pt, TYPEM m) { const float invm(INVERT(float(m))); return TPoint3(invm*pt.x, invm*pt.y, invm*pt.z); } template inline TPoint3 operator/(const TPoint3& pt, TYPEM m) { const double invm(INVERT(double(m))); return TPoint3(invm*pt.x, invm*pt.y, invm*pt.z); } template inline TPoint3& operator/=(TPoint3& pt, TYPEM m) { pt.x /= m; pt.y /= m; pt.z /= m; return pt; } template inline TPoint3& operator/=(TPoint3& pt, TYPEM m) { const float invm(INVERT(float(m))); pt.x *= invm; pt.y *= invm; pt.z *= invm; return pt; } template inline TPoint3& operator/=(TPoint3& pt, TYPEM m) { const double invm(INVERT(double(m))); pt.x *= invm; pt.y *= invm; pt.z *= invm; return pt; } #else template inline TPoint3 operator/(const cv::Point3_& pt, TYPEM m) { return TPoint3(pt.x/m, pt.y/m, pt.z/m); } template inline TPoint3 operator/(const cv::Point3_& pt, TYPEM m) { const float invm(INVERT(float(m))); return TPoint3(invm*pt.x, invm*pt.y, invm*pt.z); } template inline TPoint3 operator/(const cv::Point3_& pt, TYPEM m) { const double invm(INVERT(double(m))); return TPoint3(invm*pt.x, invm*pt.y, invm*pt.z); } template inline TPoint3& operator/=(cv::Point3_& pt, TYPEM m) { pt.x /= m; pt.y /= m; pt.z /= m; return (TPoint3&)pt; } template inline TPoint3& operator/=(cv::Point3_& pt, TYPEM m) { const float invm(INVERT(float(m))); pt.x *= invm; pt.y *= invm; pt.z *= invm; return (TPoint3&)pt; } template inline TPoint3& operator/=(cv::Point3_& pt, TYPEM m) { const double invm(INVERT(double(m))); pt.x *= invm; pt.y *= invm; pt.z *= invm; return (TPoint3&)pt; } #endif template inline TPoint3 operator/(const cv::Point3_& pt0, const cv::Point3_& pt1) { return TPoint3(pt0.x/pt1.x, pt0.y/pt1.y, pt0.z/pt1.z); } template inline TPoint3& operator/=(cv::Point3_& pt0, const cv::Point3_& pt1) { pt0.x/=pt1.x; pt0.y/=pt1.y; pt0.z/=pt1.z; return (TPoint3&)pt0; } template inline TPoint3 operator*(const cv::Point3_& pt0, const cv::Point3_& pt1) { return TPoint3(pt0.x*pt1.x, pt0.y*pt1.y, pt0.z*pt1.z); } template inline TPoint3& operator*=(cv::Point3_& pt0, const cv::Point3_& pt1) { pt0.x*=pt1.x; pt0.y*=pt1.y; pt0.z*=pt1.z; return (TPoint3&)pt0; } template inline TPoint3 cvtPoint3(const TPoint3& p) { return TPoint3(TTO(p.x), TTO(p.y), TTO(p.z)); } // TPixel operators template inline TPixel operator/(const TPixel& pt, TYPEM m) { const TYPEM invm(INVERT(m)); return TPixel(invm*pt.r, invm*pt.g, invm*pt.b); } template inline TPixel& operator/=(TPixel& pt, TYPEM m) { const TYPEM invm(INVERT(m)); pt.r *= invm; pt.g *= invm; pt.b *= invm; return pt; } template inline TPixel operator/(const TPixel& pt0, const TPixel& pt1) { return TPixel(pt0.r/pt1.r, pt0.g/pt1.g, pt0.b/pt1.b); } template inline TPixel& operator/=(TPixel& pt0, const TPixel& pt1) { pt0.r/=pt1.r; pt0.g/=pt1.g; pt0.b/=pt1.b; return pt0; } template inline TPixel operator*(const TPixel& pt0, const TPixel& pt1) { return TPixel(pt0.r*pt1.r, pt0.g*pt1.g, pt0.b*pt1.b); } template inline TPixel& operator*=(TPixel& pt0, const TPixel& pt1) { pt0.r*=pt1.r; pt0.g*=pt1.g; pt0.b*=pt1.b; return pt0; } // TColor operators template inline TColor operator/(const TColor& pt, TYPEM m) { const TYPEM invm(INVERT(m)); return TColor(invm*pt.r, invm*pt.g, invm*pt.b, invm*pt.a); } template inline TColor& operator/=(TColor& pt, TYPEM m) { const TYPEM invm(INVERT(m)); pt.r *= invm; pt.g *= invm; pt.b *= invm; pt.a *= invm; return pt; } template inline TColor operator/(const TColor& pt0, const TColor& pt1) { return TColor(pt0.r/pt1.r, pt0.g/pt1.g, pt0.b/pt1.b, pt0.a/pt1.a); } template inline TColor& operator/=(TColor& pt0, const TColor& pt1) { pt0.r/=pt1.r; pt0.g/=pt1.g; pt0.b/=pt1.b; pt0.a/=pt1.a; return pt0; } template inline TColor operator*(const TColor& pt0, const TColor& pt1) { return TColor(pt0.r*pt1.r, pt0.g*pt1.g, pt0.b*pt1.b, pt0.a*pt1.a); } template inline TColor& operator*=(TColor& pt0, const TColor& pt1) { pt0.r*=pt1.r; pt0.g*=pt1.g; pt0.b*=pt1.b; pt0.a*=pt1.a; return pt0; } // TMatrix operators template inline TMatrix operator + (const TMatrix& m1, const TMatrix& m2) { return TMatrix(m1, m2, cv::Matx_AddOp()); } template inline TMatrix operator + (const TMatrix& m1, const cv::Matx& m2) { return cv::Matx(m1, m2, cv::Matx_AddOp()); } template inline TMatrix operator + (const cv::Matx& m1, const TMatrix& m2) { return TMatrix(m1, m2, cv::Matx_AddOp()); } template inline TMatrix operator - (const TMatrix& m1, const TMatrix& m2) { return TMatrix(m1, m2, cv::Matx_SubOp()); } template inline TMatrix operator - (const TMatrix& m1, const cv::Matx& m2) { return TMatrix(m1, m2, cv::Matx_SubOp()); } template inline TMatrix operator - (const cv::Matx& m1, const TMatrix& m2) { return TMatrix(m1, m2, cv::Matx_SubOp()); } template inline TMatrix operator - (const TMatrix& M) { return TMatrix(M, TYPE(-1), cv::Matx_ScaleOp()); } template inline TMatrix operator * (const TMatrix& m1, const TMatrix& m2) { return TMatrix(m1, m2, cv::Matx_MatMulOp()); } template inline TMatrix operator / (const TMatrix& mat, TYPE2 v) { typedef typename std::conditional::value,TYPE2,REAL>::type real_t; return TMatrix(mat, real_t(1)/v, cv::Matx_ScaleOp()); } template inline TMatrix& operator /= (TMatrix& mat, TYPE2 v) { return mat = mat/v; } // TImage operators template inline TImage cvtImage(const TImage& image) { TImage img(image.size()); for (int r=0; r FORCEINLINE SEACAVE::TPoint2 operator/(TYPEM n, const cv::Point_& d) { return SEACAVE::TPoint2(n/d.x, n/d.y); } template FORCEINLINE SEACAVE::TPoint3 operator/(TYPEM n, const cv::Point3_& d) { return SEACAVE::TPoint3(n/d.x, n/d.y, n/d.z); } template FORCEINLINE SEACAVE::TPixel operator/(TYPEM n, const SEACAVE::TPixel& d) { return SEACAVE::TPixel(n/d.r, n/d.g, n/d.b); } template FORCEINLINE SEACAVE::TColor operator/(TYPEM n, const SEACAVE::TColor& d) { return SEACAVE::TColor(n/d.r, n/d.g, n/d.b, n/d.a); } /*----------------------------------------------------------------*/ } // namespace SEACAVE // Informative template class for OpenCV "scalars" #define DEFINE_GENERIC_CVDATATYPE(tp,ctp) namespace cv { \ template<> class DataType< tp > { \ public: \ typedef tp value_type; \ typedef value_type work_type; \ typedef ctp channel_type; \ typedef value_type vec_type; \ enum { \ generic_type = 0, \ depth = DataDepth::value, \ channels = sizeof(value_type)/sizeof(channel_type), \ fmt = DataDepth::fmt, \ type = CV_MAKETYPE(depth, channels) \ }; \ }; } #define DEFINE_CVDATATYPE(tp) DEFINE_GENERIC_CVDATATYPE(tp,tp::Type) #define DEFINE_GENERIC_CVDATADEPTH(tp,ctp) namespace cv { \ template<> class DataDepth< tp > { \ public: \ enum { \ value = DataDepth< ctp >::value, \ fmt = DataDepth< ctp >::fmt \ }; \ }; } #define DEFINE_CVDATADEPTH(tp) DEFINE_GENERIC_CVDATADEPTH(tp,tp::Type) // define specialized cv:DataType<> DEFINE_CVDATADEPTH(SEACAVE::hfloat) DEFINE_CVDATADEPTH(SEACAVE::cuint32_t) // define specialized cv:DataType<> DEFINE_CVDATATYPE(SEACAVE::hfloat) DEFINE_CVDATATYPE(SEACAVE::cuint32_t) DEFINE_GENERIC_CVDATATYPE(uint64_t,double) /*----------------------------------------------------------------*/ DEFINE_CVDATATYPE(SEACAVE::Point2i) DEFINE_CVDATATYPE(SEACAVE::Point2hf) DEFINE_CVDATATYPE(SEACAVE::Point2f) DEFINE_CVDATATYPE(SEACAVE::Point2d) /*----------------------------------------------------------------*/ DEFINE_CVDATATYPE(SEACAVE::Point3i) DEFINE_CVDATATYPE(SEACAVE::Point3hf) DEFINE_CVDATATYPE(SEACAVE::Point3f) DEFINE_CVDATATYPE(SEACAVE::Point3d) /*----------------------------------------------------------------*/ DEFINE_CVDATATYPE(SEACAVE::Pixel8U) DEFINE_CVDATATYPE(SEACAVE::Pixel32F) DEFINE_CVDATATYPE(SEACAVE::Pixel64F) /*----------------------------------------------------------------*/ DEFINE_CVDATATYPE(SEACAVE::Color8U) DEFINE_CVDATATYPE(SEACAVE::Color32F) DEFINE_CVDATATYPE(SEACAVE::Color64F) /*----------------------------------------------------------------*/ DEFINE_GENERIC_CVDATATYPE(SEACAVE::DMatrix8S, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::DMatrix8U, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::DMatrix32S, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::DMatrix32U, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::DMatrix32F, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::DMatrix64F, uint8_t) /*----------------------------------------------------------------*/ DEFINE_GENERIC_CVDATATYPE(SEACAVE::DVector8S, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::DVector8U, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::DVector32S, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::DVector32U, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::DVector32F, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::DVector64F, uint8_t) /*----------------------------------------------------------------*/ DEFINE_GENERIC_CVDATATYPE(SEACAVE::Image8U, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::Image16F, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::Image32F, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::Image64F, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::Image8U3, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::Image8U4, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::Image32F3, uint8_t) DEFINE_GENERIC_CVDATATYPE(SEACAVE::Image32F4, uint8_t) /*----------------------------------------------------------------*/ namespace SEACAVE { namespace CONVERT { // convert sRGB to/from linear value // (see http://en.wikipedia.org/wiki/SRGB) template constexpr T sRGB2RGB(T x) { return x <= T(0.04045) ? x * (T(1)/T(12.92)) : POW((x + T(0.055)) * (T(1)/T(1.055)), T(2.4)); } template constexpr T RGB2sRGB(T x) { return x <= T(0.0031308) ? T(12.92) * x : T(1.055) * POW(x, T(1)/T(2.4)) - T(0.055); } static const CAutoPtrArr g_ptrsRGB82RGBf([]() { float* const buffer = new float[256]; for (int i=0; i<256; ++i) buffer[i] = sRGB2RGB(float(i)/255.f); return buffer; }()); // color conversion helper structures template struct NormRGB_t { const TO v; inline NormRGB_t(TI _v) : v(TO(_v)*(TO(1)/TO(255))) {} inline operator TO () const { return v; } }; template struct RGBUnNorm_t { const TO v; inline RGBUnNorm_t(TI _v) : v(TO(_v)*TO(255)) {} inline operator TO () const { return v; } }; template struct RoundF2U_t { const TO v; inline RoundF2U_t(TI _v) : v(ROUND2INT(_v)) {} inline operator TO () const { return v; } }; template struct sRGB2RGB_t { const TO v; inline sRGB2RGB_t(TI _v) : v(sRGB2RGB(TO(_v))) {} inline operator TO () const { return v; } }; template struct NormsRGB2RGB_t { const TO v; inline NormsRGB2RGB_t(TI _v) : v(sRGB2RGB(TO(_v)*(TO(1)/TO(255)))) {} inline operator TO () const { return v; } }; template <> struct NormsRGB2RGB_t { const float v; inline NormsRGB2RGB_t(uint8_t _v) : v(g_ptrsRGB82RGBf[_v]) {} inline operator float () const { return v; } }; template struct NormsRGB2RGBUnNorm_t { const TO v; inline NormsRGB2RGBUnNorm_t(TI _v) : v(sRGB2RGB(TO(_v)*(TO(1)/TO(255)))*TO(255)) {} inline operator TO () const { return v; } }; template <> struct NormsRGB2RGBUnNorm_t { const float v; inline NormsRGB2RGBUnNorm_t(uint8_t _v) : v(g_ptrsRGB82RGBf[_v]*255.f) {} inline operator float () const { return v; } }; } // namespace CONVERT /*----------------------------------------------------------------*/ // C L A S S ////////////////////////////////////////////////////// template struct OppositeType { typedef FLT Type; }; template <> struct OppositeType { typedef double Type; }; template <> struct OppositeType { typedef float Type; }; // Point2 template inline cv::Point_ Cast(const cv::Point_& pt) { return pt; } template inline TPoint2 Cast(const TPoint2& pt) { return pt; } // Point3 template inline cv::Point3_ Cast(const cv::Point3_& pt) { return pt; } template inline TPoint3 Cast(const TPoint3& pt) { return pt; } // Pixel template inline TPixel Cast(const TPixel& pt) { return pt; } // Color template inline TColor Cast(const TColor& pt) { return pt; } // Matrix template inline TMatrix Cast(const TMatrix& v) { return v; } /*----------------------------------------------------------------*/ // C L A S S ////////////////////////////////////////////////////// template TPoint3 TPoint3::RotateAngleAxis(const TPoint3& pt, const TPoint3& angle_axis) { TPoint3 result; const TYPE theta2(normSq(angle_axis)); if (theta2 > TYPE(1e-12)) { // Away from zero, use the Rodriguez formula // // result = pt costheta + // (w x pt) * sintheta + // w (w . pt) (1 - costheta) // // We want to be careful to only evaluate the square root if the // norm of the angle_axis vector is greater than zero. Otherwise // we get a division by zero. // const TYPE theta(SQRT(theta2)); const TPoint3 w(angle_axis*(TYPE(1)/theta)); const TYPE costheta(COS(theta)); const TYPE sintheta(SIN(theta)); const TPoint3 w_cross_pt(w.cross(pt)); const TYPE w_dot_pt(w.dot(pt)); result = pt*costheta + w_cross_pt*sintheta + w*(TYPE(1.0)-costheta)*w_dot_pt; } else { // Near zero, the first order Taylor approximation of the rotation // matrix R corresponding to a vector w and angle w is // // R = I + hat(w) * sin(theta) // // But sintheta ~ theta and theta * w = angle_axis, which gives us // // R = I + hat(w) // // and actually performing multiplication with the point pt, gives us // R * pt = pt + w x pt. // // Switching to the Taylor expansion at zero helps avoid all sorts // of numerical nastiness. const TPoint3 w_cross_pt(angle_axis.cross(pt)); result = pt + w_cross_pt; } return result; } /*----------------------------------------------------------------*/ // C L A S S ////////////////////////////////////////////////////// template inline TMatrix::TMatrix(TYPE v0) { STATIC_ASSERT(channels >= 1); val[0] = v0; for (int i = 1; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1) { STATIC_ASSERT(channels >= 2); val[0] = v0; val[1] = v1; for (int i = 2; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2) { STATIC_ASSERT(channels >= 3); val[0] = v0; val[1] = v1; val[2] = v2; for (int i = 3; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3) { STATIC_ASSERT(channels >= 4); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; for (int i = 4; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4) { STATIC_ASSERT(channels >= 5); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; for (int i = 5; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5) { STATIC_ASSERT(channels >= 6); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; for (int i = 6; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6) { STATIC_ASSERT(channels >= 7); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; for (int i = 7; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6, TYPE v7) { STATIC_ASSERT(channels >= 8); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; for (int i = 8; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6, TYPE v7, TYPE v8) { STATIC_ASSERT(channels >= 9); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; val[8] = v8; for (int i = 9; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6, TYPE v7, TYPE v8, TYPE v9) { STATIC_ASSERT(channels >= 10); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; val[8] = v8; val[9] = v9; for (int i = 10; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6, TYPE v7, TYPE v8, TYPE v9, TYPE v10, TYPE v11) { STATIC_ASSERT(channels >= 12); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; for (int i = 12; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6, TYPE v7, TYPE v8, TYPE v9, TYPE v10, TYPE v11, TYPE v12, TYPE v13) { STATIC_ASSERT(channels == 14); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; val[12] = v12; val[13] = v13; for (int i = 14; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6, TYPE v7, TYPE v8, TYPE v9, TYPE v10, TYPE v11, TYPE v12, TYPE v13, TYPE v14, TYPE v15) { STATIC_ASSERT(channels >= 16); val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; val[12] = v12; val[13] = v13; val[14] = v14; val[15] = v15; for (int i = 16; i < channels; i++) val[i] = TYPE(0); } template inline TMatrix::TMatrix(const TYPE* values) { for (int i = 0; i < channels; i++) val[i] = values[i]; } template inline bool TMatrix::IsEqual(const Base& rhs) const { for (int i=0; i inline bool TMatrix::IsEqual(const Base& rhs, TYPE eps) const { for (int i=0; i inline TMatrix TMatrix::RightNullSpace(int flags /*= 0*/) const { STATIC_ASSERT(n > m); const cv::SVD svd(*this, flags|cv::SVD::FULL_UV); // the orthonormal basis of the null space is formed by the columns // of svd.vt such that the corresponding singular values are 0 (n - m or svd.vt.cols - svd.w.rows) ASSERT(svd.vt.rows == n && svd.vt.rows == svd.vt.cols && svd.w.rows == m); // return result (last rows transposed) return svd.vt.rowRange(m,n).t(); } // calculate right null-vector of the matrix ([n,1]) template inline TMatrix TMatrix::RightNullVector(int flags /*= 0*/) const { const cv::SVD svd(*this, (m >= n ? flags : flags|cv::SVD::FULL_UV)); // the singular values could be checked for numerical stability // return result (last row transposed) ASSERT(svd.vt.rows == n); return *svd.vt.ptr< const TMatrix >(n-1); } // calculate left null-vector of the matrix ([m,1]) template inline TMatrix TMatrix::LeftNullVector(int flags /*= 0*/) const { return TMatrix(Base::t()).RightNullVector(flags); } /*----------------------------------------------------------------*/ // C L A S S ////////////////////////////////////////////////////// template inline TYPE TDMatrix::getDetSquare() const { ASSERT(cols == rows); const int dim = rows; const int subdim = dim-1; // end of recursion in 1x1: if (subdim==0) return Base::operator()(0,0); // end of recursion in 2x2: if (subdim==1) return (Base::operator()(0,0)*Base::operator()(1,1)- Base::operator()(1,0)*Base::operator()(0,1)); TYPE d = 0; TDMatrix SubMatrix(subdim, subdim); for (int sub=0; sub inline TDMatrix TDMatrix::getAdjoint() const { ASSERT(rows==cols); TDMatrix Out(cols,rows); TDMatrix SubMatrix(rows-1,cols-1); for (int i=0; i inline void TDMatrix::getSystemMatrix(TDMatrix& dest) const { // resize result to square matrix dest = TDMatrix::zeros(cols, cols); /// Hessian is symmetric! so first diagonal then lower left // diagonal for (int col = 0; col inline void TDMatrix::makeSymmetric() { ASSERT(cols == rows); const int num = cols; for (int r=0; r inline TYPE TDMatrix::getNormL1() const { TYPE result = 0; for (const TYPE* dataP = getData()+Base::total()-1; dataP >= getData(); dataP--) result += ABS(*dataP); return result; } template inline double TDMatrix::getNormL2() const { double result = 0; for (const TYPE* dataP = getData()+Base::total()-1; dataP >= getData(); dataP--) result += (double)((*dataP) * (*dataP)); return SQRT(result); } /** Kronecker-product with matrix B, result in dest */ template void TDMatrix::Kronecker(const TDMatrix& B, TDMatrix& dest) const { const int A_rows = rows; const int A_cols = cols; const int B_rows = B.rows; const int B_cols = B.cols; dest.newsize(A_rows*B_rows,A_cols*B_cols); for (int i=0; i void TDMatrix::SwapRows(int i, int r) { TYPE* const rowi = Base::operator[](i); TYPE* const rowr = Base::operator[](r); for (int c=0; c void TDMatrix::GaussJordan() { //const bool verbose = false; const int numr = rows, numc = cols; const int max = MINF(numr, numc); ///<< offset to right from diagonal, the working column is given by r+offs int offs = 0; for (int r=0; r=0; --r) { // search for leading element int c; for (c=r; c=0; --row) { const TYPE wval=Base::operator()(row,c); for (int col=0; col TDMatrix TDVector::getOuterProduct(const TDVector& v) const { TDMatrix mat(rows,v.rows); TYPE rVal; for (int row=0; row void TDVector::getKroneckerProduct(const TDVector& arg, TDVector& dst) const { const int s1=rows, s2=arg.rows; int l=0; dst.newsize(s1*s2); for (int i=0; i template TPixel TPixel::colorRamp(VT v, VT vmin, VT vmax) { if (v < vmin) v = vmin; if (v > vmax) v = vmax; const TYPE dv((TYPE)(vmax - vmin)); TPixel c(1,1,1); // white if (v < vmin + (VT)(TYPE(0.25) * dv)) { c.r = TYPE(0); c.g = TYPE(4) * (v - vmin) / dv; } else if (v < vmin + (VT)(TYPE(0.5) * dv)) { c.r = TYPE(0); c.b = TYPE(1) + TYPE(4) * (vmin + TYPE(0.25) * dv - v) / dv; } else if (v < vmin + (VT)(TYPE(0.75) * dv)) { c.r = TYPE(4) * (v - vmin - TYPE(0.5) * dv) / dv; c.b = TYPE(0); } else { c.g = TYPE(1) + TYPE(4) * (vmin + TYPE(0.75) * dv - v) / dv; c.b = TYPE(0); } return c; } // Gray values are expected in the range [0, 1] and converted to RGB values. template TPixel TPixel::gray2color(ALT gray) { ASSERT(ALT(0) <= gray && gray <= ALT(1)); // Jet colormap inspired by Matlab. auto const Interpolate = [](ALT val, ALT y0, ALT x0, ALT y1, ALT x1) -> ALT { return (val - x0) * (y1 - y0) / (x1 - x0) + y0; }; auto const Base = [&Interpolate](ALT val) -> ALT { if (val <= ALT(0.125)) { return ALT(0); } else if (val <= ALT(0.375)) { return Interpolate(ALT(2) * val - ALT(1), ALT(0), ALT(-0.75), ALT(1), ALT(-0.25)); } else if (val <= ALT(0.625)) { return ALT(1); } else if (val <= ALT(0.87)) { return Interpolate(ALT(2) * val - ALT(1), ALT(1), ALT(0.25), ALT(0), ALT(0.75)); } else { return ALT(0); } }; return TPixel().set( Base(gray + ALT(0.25)), Base(gray), Base(gray - ALT(0.25)) ); } /*----------------------------------------------------------------*/ // C L A S S ////////////////////////////////////////////////////// // Find a pixel inside the image template inline const TYPE& TImage::getPixel(int y, int x) const { if (x < 0) x = 0; else if (x >= cols) x = cols-1; if (y < 0) y = 0; else if (y >= rows) y = rows-1; return BaseBase::operator()(y,x); } /*----------------------------------------------------------------*/ // sample by bilinear interpolation template template TYPE TImage::sample(const TPoint2& pt) const { const int lx((int)pt.x); const int ly((int)pt.y); const T x(pt.x-lx), x1(T(1)-x); const T y(pt.y-ly), y1(T(1)-y); return (BaseBase::operator()( ly, lx)*x1 + BaseBase::operator()( ly, lx+1)*x)*y1 + (BaseBase::operator()(ly+1,lx)*x1 + BaseBase::operator()(ly+1,lx+1)*x)*y; } template template TYPE TImage::sampleSafe(const TPoint2& pt) const { const int lx((int)pt.x); const int ly((int)pt.y); const T x(pt.x-lx), x1(T(1)-x); const T y(pt.y-ly), y1(T(1)-y); return (getPixel( ly, lx)*x1 + getPixel( ly, lx+1)*x)*y1 + (getPixel(ly+1,lx)*x1 + getPixel(ly+1,lx+1)*x)*y; } /*----------------------------------------------------------------*/ // sample by bilinear interpolation, using only pixels that meet the user condition template template bool TImage::sample(TV& v, const TPoint2& pt, const Functor& functor) const { const int lx((int)pt.x); const int ly((int)pt.y); const T x(pt.x-lx), x1(T(1)-x); const T y(pt.y-ly), y1(T(1)-y); const TYPE& x0y0(BaseBase::operator()(ly , lx )); const bool b00(functor(x0y0)); const TYPE& x1y0(BaseBase::operator()(ly , lx+1)); const bool b10(functor(x1y0)); const TYPE& x0y1(BaseBase::operator()(ly+1, lx )); const bool b01(functor(x0y1)); const TYPE& x1y1(BaseBase::operator()(ly+1, lx+1)); const bool b11(functor(x1y1)); if (!b00 && !b10 && !b01 && !b11) return false; v = TV(y1*(x1*Cast(b00 ? x0y0 : (b10 ? x1y0 : (b01 ? x0y1 : x1y1))) + x*Cast(b10 ? x1y0 : (b00 ? x0y0 : (b11 ? x1y1 : x0y1)))) + y *(x1*Cast(b01 ? x0y1 : (b11 ? x1y1 : (b00 ? x0y0 : x1y0))) + x*Cast(b11 ? x1y1 : (b01 ? x0y1 : (b10 ? x1y0 : x0y0))))); return true; } template template bool TImage::sampleSafe(TV& v, const TPoint2& pt, const Functor& functor) const { const int lx((int)pt.x); const int ly((int)pt.y); const T x(pt.x-lx), x1(T(1)-x); const T y(pt.y-ly), y1(T(1)-y); const TYPE& x0y0(getPixel(ly , lx )); const bool b00(functor(x0y0)); const TYPE& x1y0(getPixel(ly , lx+1)); const bool b10(functor(x1y0)); const TYPE& x0y1(getPixel(ly+1, lx )); const bool b01(functor(x0y1)); const TYPE& x1y1(getPixel(ly+1, lx+1)); const bool b11(functor(x1y1)); if (!b00 && !b10 && !b01 && !b11) return false; v = TV(y1*(x1*Cast(b00 ? x0y0 : (b10 ? x1y0 : (b01 ? x0y1 : x1y1))) + x*Cast(b10 ? x1y0 : (b00 ? x0y0 : (b11 ? x1y1 : x0y1)))) + y *(x1*Cast(b01 ? x0y1 : (b11 ? x1y1 : (b00 ? x0y0 : x1y0))) + x*Cast(b11 ? x1y1 : (b01 ? x0y1 : (b10 ? x1y0 : x0y0))))); return true; } // same as above, but using default value if the condition is not met template template TYPE TImage::sample(const TPoint2& pt, const Functor& functor, const TYPE& dv) const { const int lx((int)pt.x); const int ly((int)pt.y); const T x(pt.x-lx), x1(T(1)-x); const T y(pt.y-ly), y1(T(1)-y); const TYPE& x0y0(BaseBase::operator()(ly , lx )); const bool b00(functor(x0y0)); const TYPE& x1y0(BaseBase::operator()(ly , lx+1)); const bool b10(functor(x1y0)); const TYPE& x0y1(BaseBase::operator()(ly+1, lx )); const bool b01(functor(x0y1)); const TYPE& x1y1(BaseBase::operator()(ly+1, lx+1)); const bool b11(functor(x1y1)); return TYPE(y1*(x1*Cast(b00 ? x0y0 : dv) + x*Cast(b10 ? x1y0 : dv)) + y *(x1*Cast(b01 ? x0y1 : dv) + x*Cast(b11 ? x1y1 : dv))); } template template TYPE TImage::sampleSafe(const TPoint2& pt, const Functor& functor, const TYPE& dv) const { const int lx((int)pt.x); const int ly((int)pt.y); const T x(pt.x-lx), x1(T(1)-x); const T y(pt.y-ly), y1(T(1)-y); const TYPE& x0y0(getPixel(ly , lx )); const bool b00(functor(x0y0)); const TYPE& x1y0(getPixel(ly , lx+1)); const bool b10(functor(x1y0)); const TYPE& x0y1(getPixel(ly+1, lx )); const bool b01(functor(x0y1)); const TYPE& x1y1(getPixel(ly+1, lx+1)); const bool b11(functor(x1y1)); return TYPE(y1*(x1*Cast(b00 ? x0y0 : dv) + x*Cast(b10 ? x1y0 : dv)) + y *(x1*Cast(b01 ? x0y1 : dv) + x*Cast(b11 ? x1y1 : dv))); } // same as above, sample image at a specified position, but using the given sampler #include "Sampler.inl" template template INTERTYPE TImage::sample(const SAMPLER& sampler, const TPoint2& pt) const { return Sampler::Sample< TImage, SAMPLER, TPoint2, INTERTYPE >(*this, sampler, pt); } // convert color image to gray template template void TImage::toGray(TImage& out, int code, bool bNormalize, bool bSRGB) const { #if 1 typedef typename RealType::type Real; ASSERT(code==cv::COLOR_RGB2GRAY || code==cv::COLOR_RGBA2GRAY || code==cv::COLOR_BGR2GRAY || code==cv::COLOR_BGRA2GRAY); static const Real coeffsRGB[] = {Real(0.299), Real(0.587), Real(0.114)}; static const Real coeffsBGR[] = {Real(0.114), Real(0.587), Real(0.299)}; const Real* coeffs; switch (code) { case cv::COLOR_BGR2GRAY: case cv::COLOR_BGRA2GRAY: coeffs = coeffsBGR; break; case cv::COLOR_RGB2GRAY: case cv::COLOR_RGBA2GRAY: coeffs = coeffsRGB; break; default: ASSERT("Unsupported image format" == NULL); } const Real &cb(coeffs[0]), &cg(coeffs[1]), &cr(coeffs[2]); if (out.rows!=rows || out.cols!=cols) out.create(rows, cols); ASSERT(cv::Mat::isContinuous()); ASSERT(out.cv::Mat::isContinuous()); const int scn(this->cv::Mat::channels()); T* dst = out.cv::Mat::template ptr(); T* const dstEnd = dst + out.area(); typedef typename cv::DataType::channel_type ST; if (bSRGB) { if (bNormalize) { typedef typename CONVERT::NormsRGB2RGB_t ColConv; for (const ST* src=cv::Mat::template ptr(); dst!=dstEnd; src+=scn) *dst++ = T(cb*ColConv(src[0]) + cg*ColConv(src[1]) + cr*ColConv(src[2])); } else { typedef typename CONVERT::NormsRGB2RGBUnNorm_t ColConv; for (const ST* src=cv::Mat::template ptr(); dst!=dstEnd; src+=scn) *dst++ = T(cb*ColConv(src[0]) + cg*ColConv(src[1]) + cr*ColConv(src[2])); } } else { if (bNormalize) { typedef typename CONVERT::NormRGB_t ColConv; for (const ST* src=cv::Mat::template ptr(); dst!=dstEnd; src+=scn) *dst++ = T(cb*ColConv(src[0]) + cg*ColConv(src[1]) + cr*ColConv(src[2])); } else { for (const ST* src=cv::Mat::template ptr(); dst!=dstEnd; src+=scn) *dst++ = T(cb*src[0] + cg*src[1] + cr*src[2]); } } #else cv::Mat cimg; convertTo(cimg, cv::DataType::type); cv::cvtColor(cimg, out, code); if (bNormalize) out *= T(1)/T(255); #endif } /*----------------------------------------------------------------*/ // compute scaled size such that the biggest dimension is scaled as desired // and the smaller one maintains the aspect ratio as best as it can template cv::Size TImage::computeResize(const cv::Size& size, REAL scale) { return cv::Size( cv::saturate_cast((REAL)size.width*scale), cv::saturate_cast((REAL)size.height*scale)); } // compute the final scaled size by performing successive resizes // with the given scale value template cv::Size TImage::computeResize(const cv::Size& size, REAL scale, unsigned resizes) { cv::Size scaledSize(size); while (resizes-- > 0) scaledSize = computeResize(scaledSize, scale); return scaledSize; } // compute image scale for a given max and min resolution template unsigned TImage::computeMaxResolution(unsigned width, unsigned height, unsigned& level, unsigned minImageSize, unsigned maxImageSize) { // consider the native resolution the max(width,height) const unsigned imageSize = MAXF(width, height); // if the max level it's used, return original image size if (level == 0) return MINF(imageSize, maxImageSize); // compute the resolution corresponding to the desired level unsigned size = (imageSize >> level); // if the image is too small if (size < minImageSize) { // start from the max level level = 0; while ((imageSize>>(level+1)) >= minImageSize) ++level; size = (imageSize>>level); } return MINF(size, maxImageSize); } template unsigned TImage::computeMaxResolution(unsigned& level, unsigned minImageSize, unsigned maxImageSize) const { return computeMaxResolution((unsigned)width(), (unsigned)height(), level, minImageSize, maxImageSize); } /*----------------------------------------------------------------*/ // Raster the given triangle and output the position of each pixel of the triangle; // based on "Advanced Rasterization" by Nick (Nicolas Capens) // http://devmaster.net/forums/topic/1145-advanced-rasterization template template void TImage::RasterizeTriangle(const TPoint2& v1, const TPoint2& v2, const TPoint2& v3, PARSER& parser) { // 28.4 fixed-point coordinates const int_t Y1 = ROUND2INT(T(16) * v1.y); const int_t Y2 = ROUND2INT(T(16) * v2.y); const int_t Y3 = ROUND2INT(T(16) * v3.y); const int_t X1 = ROUND2INT(T(16) * v1.x); const int_t X2 = ROUND2INT(T(16) * v2.x); const int_t X3 = ROUND2INT(T(16) * v3.x); // Deltas const int_t DX12 = X1 - X2; const int_t DX23 = X2 - X3; const int_t DX31 = X3 - X1; const int_t DY12 = Y1 - Y2; const int_t DY23 = Y2 - Y3; const int_t DY31 = Y3 - Y1; // Fixed-point deltas const int_t FDX12 = DX12 << 4; const int_t FDX23 = DX23 << 4; const int_t FDX31 = DX31 << 4; const int_t FDY12 = DY12 << 4; const int_t FDY23 = DY23 << 4; const int_t FDY31 = DY31 << 4; // Bounding rectangle int minx = (int)((MINF3(X1, X2, X3) + 0xF) >> 4); int maxx = (int)((MAXF3(X1, X2, X3) + 0xF) >> 4); int miny = (int)((MINF3(Y1, Y2, Y3) + 0xF) >> 4); int maxy = (int)((MAXF3(Y1, Y2, Y3) + 0xF) >> 4); // Block size, standard 8x8 (must be power of two) const int q = 8; // Start in corner of 8x8 block minx &= ~(q - 1); miny &= ~(q - 1); // Half-edge constants int_t C1 = DY12 * X1 - DX12 * Y1; int_t C2 = DY23 * X2 - DX23 * Y2; int_t C3 = DY31 * X3 - DX31 * Y3; // Correct for fill convention if (DY12 < 0 || (DY12 == 0 && DX12 > 0)) C1++; if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++; if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++; // Loop through blocks int pixy = miny; for (int y = miny; y < maxy; y += q) { for (int x = minx; x < maxx; x += q) { // Corners of block const int_t x0 = int_t(x) << 4; const int_t x1 = int_t(x + q - 1) << 4; const int_t y0 = int_t(y) << 4; const int_t y1 = int_t(y + q - 1) << 4; // Evaluate half-space functions const bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0; const bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0; const bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0; const bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0; const int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3); const bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0; const bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0; const bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0; const bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0; const int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3); const bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0; const bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0; const bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0; const bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0; const int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3); // Skip block when outside an edge if (a == 0x0 || b == 0x0 || c == 0x0) continue; int nowpixy = pixy; // Accept whole block when totally covered if (a == 0xF && b == 0xF && c == 0xF) { for (int iy = 0; iy < q; iy++) { for (int ix = x; ix < x + q; ix++) parser(ImageRef(ix,nowpixy)); ++nowpixy; } } else // Partially covered block { int_t CY1 = C1 + DX12 * y0 - DY12 * x0; int_t CY2 = C2 + DX23 * y0 - DY23 * x0; int_t CY3 = C3 + DX31 * y0 - DY31 * x0; for (int iy = y; iy < y + q; iy++) { int_t CX1 = CY1; int_t CX2 = CY2; int_t CX3 = CY3; for (int ix = x; ix < x + q; ix++) { if (CX1 > 0 && CX2 > 0 && CX3 > 0) parser(ImageRef(ix,nowpixy)); CX1 -= FDY12; CX2 -= FDY23; CX3 -= FDY31; } CY1 += FDX12; CY2 += FDX23; CY3 += FDX31; ++nowpixy; } } } pixy += q; } } // same as above, but raster a triangle using barycentric coordinates: // https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation template template void TImage::RasterizeTriangleBary(const TPoint2& v1, const TPoint2& v2, const TPoint2& v3, PARSER& parser) { // compute bounding-box fully containing the triangle const TPoint2 boxMin(MINF3(v1.x, v2.x, v3.x), MINF3(v1.y, v2.y, v3.y)); const TPoint2 boxMax(MAXF3(v1.x, v2.x, v3.x), MAXF3(v1.y, v2.y, v3.y)); // check the bounding-box intersects the image const cv::Size size(parser.Size()); if (boxMax.x < T(0) || boxMin.x > T(size.width - 1) || boxMax.y < T(0) || boxMin.y > T(size.height - 1)) return; // clip bounding-box to be fully contained by the image ImageRef boxMinI(FLOOR2INT(boxMin)); ImageRef boxMaxI(CEIL2INT(boxMax)); Base::clip(boxMinI, boxMaxI, size); // ignore back oriented triangles (negative area) const T area(EdgeFunction(v1, v2, v3)); if (CULL && area <= 0) return; // parse all pixels inside the bounding-box const T invArea(T(1) / area); for (int y = boxMinI.y; y <= boxMaxI.y; ++y) { for (int x = boxMinI.x; x <= boxMaxI.x; ++x) { const ImageRef pt(x, y); const TPoint2 p(Cast(pt)); // discard point if not in triangle; // testing only for negative barycentric coordinates // guarantees all will be in [0,1] at the end of all checks const T b1(EdgeFunction(v2, v3, p) * invArea); if (b1 < 0) continue; const T b2(EdgeFunction(v3, v1, p) * invArea); if (b2 < 0) continue; const T b3(EdgeFunction(v1, v2, p) * invArea); if (b3 < 0) continue; // output pixel parser(pt, TPoint3(b1, b2, b3)); } } } // drawing line between 2 points from left to right // papb -> pcpd // pa, pb, pc, pd must then be sorted before template inline void _ProcessScanLine(int y, const TPoint3& pa, const TPoint3& pb, const TPoint3& pc, const TPoint3& pd, PARSER& parser) { // Thanks to current Y, we can compute the gradient to compute others values like // the starting X (sx) and ending X (ex) to draw between // if pa.y == pb.y or pc.y == pd.y, gradient is forced to 1 const T gradient1 = CLAMP(pa.y != pb.y ? (T(y) - pa.y) / (pb.y - pa.y) : T(1), T(0), T(1)); const T gradient2 = CLAMP(pc.y != pd.y ? (T(y) - pc.y) / (pd.y - pc.y) : T(1), T(0), T(1)); const int sx = FLOOR2INT(lerp(pa.x, pb.x, gradient1)); const int ex = FLOOR2INT(lerp(pc.x, pd.x, gradient2)); // starting Z & ending Z const T z1 = lerp(pa.z, pb.z, gradient1); const T z2 = lerp(pc.z, pd.z, gradient2); // drawing a line from left (sx) to right (ex) const T invd = T(1) / (T)(ex - sx); for (int x = sx; x < ex; ++x) { const T gradient = T(x - sx) * invd; ASSERT(gradient >= T(0) && gradient <= T(1)); const T z = lerp(z1, z2, gradient); parser(ImageRef(x,y), z); } } // Raster the given triangle and output the position and depth of each pixel of the triangle; // based on "Learning how to write a 3D software engine � Rasterization & Z-Buffering" by Nick (David Rousset) // http://blogs.msdn.com/b/davrous/archive/2013/06/21/tutorial-part-4-learning-how-to-write-a-3d-software-engine-in-c-ts-or-js-rasterization-amp-z-buffering.aspx template template void TImage::RasterizeTriangleDepth(TPoint3 p1, TPoint3 p2, TPoint3 p3, PARSER& parser) { // sorting the points in order to always have this order on screen p1, p2 & p3 // with p1 always up (thus having the Y the lowest possible to be near the top screen) // then p2 between p1 & p3 if (p1.y > p2.y) std::swap(p1, p2); if (p2.y > p3.y) std::swap(p2, p3); if (p1.y > p2.y) std::swap(p1, p2); // computing lines' directions (slopes) // http://en.wikipedia.org/wiki/Slope const T dP1P2 = (p2.y - p1.y > 0 ? (p2.x - p1.x) / (p2.y - p1.y) : T(0)); const T dP1P3 = (p3.y - p1.y > 0 ? (p3.x - p1.x) / (p3.y - p1.y) : T(0)); // first case where triangles are like that: // P1 // - // -- // - - // - - // - - P2 // - - // - - // - // P3 if (dP1P2 > dP1P3) { for (int y = (int)p1.y; y <= (int)p3.y; ++y) { if (y < p2.y) _ProcessScanLine(y, p1, p3, p1, p2, parser); else _ProcessScanLine(y, p1, p3, p2, p3, parser); } } // second case where triangles are like that: // P1 // - // -- // - - // - - // P2 - - // - - // - - // - // P3 else { for (int y = (int)p1.y; y <= (int)p3.y; ++y) { if (y < p2.y) _ProcessScanLine(y, p1, p2, p1, p3, parser); else _ProcessScanLine(y, p2, p3, p1, p3, parser); } } } template template void TImage::DrawLine(const TPoint2& p1, const TPoint2& p2, PARSER& parser) { #if 0 const TPoint2 d(ABS(p2 - p1)); const int sx(p1.xd.y ? d.x : -d.y)/2), e2; const ImageRef x2(p2); ImageRef p(p1); while (true) { parser(p); if (p == x2) break; e2 = err; if (e2 >-d.x) { err -= d.y; p.x += sx; } if (e2 < d.y) { err += d.x; p.y += sy; } } #else // Bresenham's line algorithm // https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm T x1(p1.x), y1(p1.y), x2(p2.x), y2(p2.y); const bool steep(ABS(y2 - y1) > ABS(x2 - x1)); if (steep) { std::swap(x1, y1); std::swap(x2, y2); } if (x1 > x2) { std::swap(x1, x2); std::swap(y1, y2); } const T dx(x2 - x1); const T dy(ABS(y2 - y1)); T error(dx / 2.f); int y(ROUND2INT(y1)); const int ystep((y1 < y2) ? 1 : -1); const int maxX(ROUND2INT(x2)); for (int x=ROUND2INT(x1); x bool TImage::DrawLineAntialias(Point2f x1, Point2f x2, FncDrawPointAntialias fncDrawPoint, void* pData) { bool revert = false; const Point2f dx = x2 - x1; if (ABS(dx.x) > ABS(dx.y)) { const ImageRef delta(0,1); if (x2.x < x1.x) { std::swap(x1, x2); revert = true; } const float gradient = dx.y / dx.x; int xpxl1 = round_(x1.x); float yend = x1.y + gradient*(float(xpxl1) - x1.x); int ypxl1 = ipart_(yend); float xgap = rfpart_(x1.x + 0.5); float tmp = fpart_(yend)*xgap; fncDrawPoint(ImageRef(xpxl1, ypxl1), delta, xgap-tmp, tmp, pData); float intery = yend + gradient; int xpxl2 = round_(x2.x); yend = x2.y + gradient*(float(xpxl2) - x2.x); int ypxl2 = ipart_(yend); for (int x=xpxl1+1; x bool TImage::DrawLineAntialias(const ImageRef& x1, const ImageRef& x2, FncDrawPointAntialias fncDrawPoint, void* pData) { const ImageRef dx = x2 - x1; if (ABS(dx.x) > ABS(dx.y)) { const ImageRef delta(0,1); const float gradient = (float)dx.y / dx.x; float intery = float(x1.y) + gradient; if (x2.x < x1.x) { for (int x=x1.x-1; x>x2.x; --x) { const float tmp = fpart_(intery); fncDrawPoint(ImageRef(x, ipart_(intery)), delta, 1.f-tmp, tmp, pData); intery += gradient; } return true; } else { for (int x=x1.x+1; xx2.y; --y) { const float tmp = fpart_(interx); fncDrawPoint(ImageRef(ipart_(interx), y), delta, 1.f-tmp, tmp, pData); interx += gradient; } return true; } else { for (int y=x1.y+1; y template void TImage::DilateMean(TImage& dst, const TYPE& invalid) const { TImage out; Base::copyTo(out); const int RowsEnd(rows-HalfSize); const int ColsEnd(cols-HalfSize); for (int r=HalfSize; r 0) out(r,c) = (n > 1 ? vo/n : vo); } } dst = out; } /*----------------------------------------------------------------*/ template bool TImage::Load(const String& fileName) { if (Util::getFileExt(fileName).ToLower() == ".pfm") { if (Base::depth() != CV_32F) return false; File fImage(fileName, File::READ, File::OPEN); if (!fImage.isOpen()) return false; ASSERT(sizeof(float) == 4); int i; char buffer[128]; // check header for (i=0; i<4; ++i) { if (fImage.read(buffer+i, 1) != 1) return false; if (buffer[i] == '\n') break; } if (buffer[0] != 'P' || buffer[1] != 'f' || buffer[i] != '\n') return false; // read resolution int w, h; for (i=0; i<127; ++i) { if (fImage.read(buffer+i, 1) != 1) return false; if (buffer[i] == '\n') break; } buffer[i] = 0; if (sscanf(buffer, "%d %d", &w, &h) != 2) return false; // read number of channels double sc; for (i=0; i<127; ++i) { if (fImage.read(buffer+i, 1) != 1) return false; if (buffer[i] == '\n') break; } buffer[i] = 0; if (sscanf(buffer, "%lf", &sc) != 1) return false; const bool bLittleEndian(sc < 0); #if __BYTE_ORDER == __LITTLE_ENDIAN ASSERT(bLittleEndian); #else ASSERT(!bLittleEndian); #endif const int nChannels(bLittleEndian ? -((int)sc) : (int)sc); if (nChannels != Base::channels()) return false; Base::create(h, w); ASSERT(sizeof(float)*Base::channels() == Base::step.p[1]); const size_t rowbytes((size_t)Base::size.p[1]*Base::step.p[1]); for (int i=rows; i>0; ) if (fImage.read(cv::Mat::template ptr(--i), rowbytes) != rowbytes) return false; return true; } cv::Mat img(cv::imread(fileName, cv::IMREAD_UNCHANGED)); if (img.empty()) { VERBOSE("error: loading image '%s'", fileName.c_str()); return false; } if (img.channels() != Base::channels()) { if (img.channels() == 3 && Base::channels() == 1) cv::cvtColor(img, img, cv::COLOR_BGR2GRAY); else if (img.channels() == 1 && Base::channels() == 3) cv::cvtColor(img, img, cv::COLOR_GRAY2BGR); else if (img.channels() == 4 && Base::channels() == 1) cv::cvtColor(img, img, cv::COLOR_BGRA2GRAY); else if (img.channels() == 1 && Base::channels() == 4) cv::cvtColor(img, img, cv::COLOR_GRAY2BGRA); else if (img.channels() == 4 && Base::channels() == 3) cv::cvtColor(img, img, cv::COLOR_BGRA2BGR); } if (img.type() == Base::type()) cv::swap(img, *this); else img.convertTo(*this, Base::type()); return true; } /*----------------------------------------------------------------*/ template bool TImage::Save(const String& fileName) const { std::vector compression_params; const String ext(Util::getFileExt(fileName).ToLower()); if (ext == ".png") { compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION); compression_params.push_back(6); } else if (ext == ".jpg") { compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); compression_params.push_back(95); } else if (ext == ".pfm") { if (Base::depth() != CV_32F) return false; Util::ensureFolder(fileName); File fImage(fileName, File::WRITE, File::CREATE | File::TRUNCATE); if (!fImage.isOpen()) return false; ASSERT(sizeof(float) == 4); #if __BYTE_ORDER == __LITTLE_ENDIAN static const double scale(-1.0); #else static const double scale(1.0); #endif fImage.print("Pf\n%d %d\n%lf\n", width(), height(), scale*Base::channels()); ASSERT(sizeof(float)*Base::channels() == Base::step.p[1]); const size_t rowbytes = (size_t)Base::size.p[1]*Base::step.p[1]; for (int i=rows; i>0; ) fImage.write(cv::Mat::template ptr(--i), rowbytes); return true; } try { if (!cv::imwrite(fileName, *this, compression_params)) { VERBOSE("error: saving image '%s'", fileName.c_str()); return false; } } catch (std::runtime_error& ex) { VERBOSE("error: saving image '%s' (exception: %s)", fileName.c_str(), ex.what()); return false; } return true; } /*----------------------------------------------------------------*/ #ifndef _RELEASE template void TImage::Show(const String& winname, int delay, bool bDestroy) const { cv::imshow(winname, *this); cv::waitKey(delay); if (bDestroy) cv::destroyWindow(winname); } /*----------------------------------------------------------------*/ #endif // C L A S S ////////////////////////////////////////////////////// // Create a derivative kernel, such that you can take the // derivative of an image by convolving with the kernel horizontally and vertically inline const TMatrix& CreateDerivativeKernel3x3() { static const double kernel[3*3] = { -1.0/8.0, 0.0, 1.0/8.0, -2.0/8.0, 0.0, 2.0/8.0, -1.0/8.0, 0.0, 1.0/8.0 }; return *((const TMatrix*)kernel); } inline const TMatrix& CreateDerivativeKernel3x3xx() { static const double kernel[3*3] = { 1.0/6.0, -2.0/6.0, 1.0/6.0, 4.0/6.0, -8.0/6.0, 4.0/6.0, 1.0/6.0, -2.0/6.0, 1.0/6.0 }; return *((const TMatrix*)kernel); } inline const TMatrix& CreateDerivativeKernel3x3xy() { static const double kernel[3*3] = { 1.0/4.0, 0.0, -1.0/4.0, 0.0, 0.0, 0.0, -1.0/4.0, 0.0, 1.0/4.0 }; return *((const TMatrix*)kernel); } // same as above, but using central differences like approach: Noise Robust Gradient Operators // (see: http://www.holoborodko.com/pavel/image-processing/edge-detection) inline const TMatrix& CreateDerivativeKernel3x5() { static const double kernel[3*5] = { -1.0/32.0, -2.0/32.0, 0.0, 2.0/32.0, 1.0/32.0, -2.0/32.0, -4.0/32.0, 0.0, 4.0/32.0, 2.0/32.0, -1.0/32.0, -2.0/32.0, 0.0, 2.0/32.0, 1.0/32.0 }; return *((const TMatrix*)kernel); } inline const TMatrix& CreateDerivativeKernel5x7() { static const double kernel[5*7] = { -1.0/512.0, -4.0/512.0, -5.0/512.0, 0.0, 5.0/512.0, 4.0/512.0, 1.0/512.0, -4.0/512.0, -16.0/512.0, 20.0/512.0, 0.0, 20.0/512.0, 16.0/512.0, 4.0/512.0, -6.0/512.0, -24.0/512.0, 30.0/512.0, 0.0, 30.0/512.0, 24.0/512.0, 6.0/512.0, -4.0/512.0, -16.0/512.0, 20.0/512.0, 0.0, 20.0/512.0, 16.0/512.0, 4.0/512.0, -1.0/512.0, -4.0/512.0, -5.0/512.0, 0.0, 5.0/512.0, 4.0/512.0, 1.0/512.0 }; return *((const TMatrix*)kernel); } // Zero mean Gaussian. inline double Gaussian(double x, double sigma) { return 1/sqrt(2*M_PI*sigma*sigma) * exp(-(x*x/2.0/sigma/sigma)); } // 2D gaussian (zero mean) // (see: (9) in http://mathworld.wolfram.com/GaussianFunction.html) inline double Gaussian2D(double x, double y, double sigma) { return 1.0/(2.0*M_PI*sigma*sigma) * exp( -(x*x+y*y)/(2.0*sigma*sigma)); } inline double GaussianDerivative(double x, double sigma) { return -x / sigma / sigma * Gaussian(x, sigma); } // Solve the inverse of the Gaussian for positive x. inline double GaussianInversePositive(double y, double sigma) { return sqrt(-2.0 * sigma * sigma * log(y * sigma * sqrt(2.0*M_PI))); } // Compute the Gaussian kernel width corresponding to the given sigma. inline int ComputeGaussianKernelWidth(double sigma) { ASSERT(sigma >= 0.0); // 0.004 implies a 3 pixel kernel with 1 pixel sigma. const double truncation_factor(0.004); // Calculate the kernel size based on sigma such that it is odd. const double precisehalfwidth(GaussianInversePositive(truncation_factor, sigma)); int width = ROUND2INT(2*precisehalfwidth); if (width % 2 == 0) width++; return width; } // Compute a Gaussian kernel, such that you can compute the blurred image // by convolving with the kernel horizontally then vertically. inline void ComputeGaussianKernel(double sigma, DVector64F& kernel) { const int width(ComputeGaussianKernelWidth(sigma)); // Calculate the gaussian kernel and its derivative. kernel.create(width); kernel.memset(0); const int halfwidth(width / 2); for (int i = -halfwidth; i <= halfwidth; ++i) kernel(i + halfwidth) = Gaussian(i, sigma); // Since images should not get brighter or darker, normalize. cv::normalize(kernel, kernel, 1.0, 0.0, cv::NORM_L1); } // Compute a Gaussian kernel and derivative, such that you can take the // derivative of an image by convolving with the kernel horizontally then the // derivative vertically to get (eg) the y derivative. inline void ComputeGaussianKernel(double sigma, DVector64F& kernel, DVector64F& derivative) { const int width(ComputeGaussianKernelWidth(sigma)); // Calculate the gaussian kernel and its derivative. kernel.create(width); derivative.create(width); kernel.memset(0); derivative.memset(0); const int halfwidth(width / 2); for (int i = -halfwidth; i <= halfwidth; ++i) { kernel(i + halfwidth) = Gaussian(i, sigma); derivative(i + halfwidth) = GaussianDerivative(i, sigma); } // Since images should not get brighter or darker, normalize. cv::normalize(kernel, kernel, 1.0, 0.0, cv::NORM_L1); // Normalize the derivative differently. See // www.cs.duke.edu/courses/spring03/cps296.1/handouts/Image%20Processing.pdf double factor(0); for (int i = -halfwidth; i <= halfwidth; ++i) { factor -= derivative(i+halfwidth)*i; } derivative /= factor; } template void FastConvolve(const DVector64F& kernel, int width, int height, const Type* src, int src_stride, int src_line_stride, Type* dst, int dst_stride) { double coefficients[2 * size + 1]; for (int k = 0; k < 2 * size + 1; ++k) { coefficients[k] = kernel(2 * size - k); } // Fast path: if the kernel has a certain size, use the constant sized loops. for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { double sum(0); for (int k = -size; k <= size; ++k) { if (vertical) { if (y + k >= 0 && y + k < height) { sum += double(src[k * src_line_stride]) * coefficients[k + size]; } } else { if (x + k >= 0 && x + k < width) { sum += double(src[k * src_stride]) * coefficients[k + size]; } } } dst[0] = static_cast(sum); src += src_stride; dst += dst_stride; } } } template void Convolve(const TImage& in, const DVector64F& kernel, TImage& out) { ASSERT(kernel.rows % 2 == 1); ASSERT(&in != &out); const int width = in.width(); const int height = in.height(); out.create(in.size()); const int src_line_stride = in.step1(0); const int src_stride = in.step1(1); const int dst_stride = out.step1(1); const Type* src = in.cv::Mat::template ptr(); Type* dst = out.cv::Mat::template ptr(); // Use a dispatch table to make most convolutions used in practice use the // fast path. const int half_width(kernel.rows / 2); switch (half_width) { #define static_convolution(size) case size: \ FastConvolve(kernel, width, height, src, src_stride, \ src_line_stride, dst, dst_stride); break; static_convolution(1) static_convolution(2) static_convolution(3) static_convolution(4) static_convolution(5) static_convolution(6) static_convolution(7) #undef static_convolution default: for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { double sum = 0; // Slow path: this loop cannot be unrolled. for (int k = -half_width; k <= half_width; ++k) { if (vertical) { if (y + k >= 0 && y + k < height) { sum += double(src[k * src_line_stride]) * kernel(2 * half_width - (k + half_width)); } } else { if (x + k >= 0 && x + k < width) { sum += double(src[k * src_stride]) * kernel(2 * half_width - (k + half_width)); } } } dst[0] = static_cast(sum); src += src_stride; dst += dst_stride; } } } } template inline void ConvolveHorizontal(const TImage& in, const DVector64F& kernel, TImage& out) { Convolve(in, kernel, out); } template inline void ConvolveVertical(const TImage& in, const DVector64F& kernel, TImage& out) { Convolve(in, kernel, out); } // Compute the gaussian blur of an image, and store the results in one channel. template void BlurredImage(const TImage& in, TImage& blurred, double sigma=0.32) { ASSERT(in.channels() == 1); DVector64F kernel; ComputeGaussianKernel(sigma, kernel); TImage tmp; // Compute convolved image. blurred.create(in.size()); ConvolveVertical(in, kernel, tmp); ConvolveHorizontal(tmp, kernel, blurred); } // Compute the gaussian blur of an image and the derivatives of the blurred // image, and store the results in three channels. template void BlurredImageAndDerivatives(const TImage& in, TImage& blurred, TImage grad[2], double sigma=0.32) { ASSERT(in.channels() == 1); DVector64F kernel, derivative; ComputeGaussianKernel(sigma, kernel, derivative); TImage tmp, dir[2]; // Compute convolved image. blurred.create(in.size()); ConvolveVertical(in, kernel, tmp); ConvolveHorizontal(tmp, kernel, blurred); // Compute first derivative in x. ConvolveHorizontal(tmp, derivative, grad[0]); // Compute first derivative in y. ConvolveHorizontal(in, kernel, tmp); ConvolveVertical(tmp, derivative, grad[1]); } template void BlurredImageAndDerivatives(const TImage& in, TImage& blurred, TImage< TPoint2 >& grad, double sigma=0.32) { TImage dir[2]; BlurredImageAndDerivatives(in, blurred, grad, sigma); cv::merge(dir, 2, grad); } /*----------------------------------------------------------------*/ // C L A S S ////////////////////////////////////////////////////// // returns determinant, note that if it's zero no inversion done; // use Mi == M to store result into M template TYPE InvertMatrix3x3(const TYPE* m, TYPE* mi) { const TYPE d(m[0]*(m[4]*m[8]-m[5]*m[7])+m[1]*(m[5]*m[6]-m[3]*m[8])+m[2]*(m[3]*m[7]-m[4]*m[6])); if (d == TYPE(0)) return TYPE(0); const TYPE invd = TYPE(1)/d; TYPE mc[9]; const TYPE* mm = m; if (mi == m) { memcpy(mc, m, sizeof(TYPE)*9); mm = mc; } mi[0] = (mm[4]*mm[8]-mm[5]*mm[7])*invd; mi[1] = (mm[2]*mm[7]-mm[1]*mm[8])*invd; mi[2] = (mm[1]*mm[5]-mm[2]*mm[4])*invd; mi[3] = (mm[5]*mm[6]-mm[3]*mm[8])*invd; mi[4] = (mm[0]*mm[8]-mm[2]*mm[6])*invd; mi[5] = (mm[2]*mm[3]-mm[0]*mm[5])*invd; mi[6] = (mm[3]*mm[7]-mm[4]*mm[6])*invd; mi[7] = (mm[1]*mm[6]-mm[0]*mm[7])*invd; mi[8] = (mm[0]*mm[4]-mm[1]*mm[3])*invd; return d; } /*----------------------------------------------------------------*/ } // namespace SEACAVE // C L A S S ////////////////////////////////////////////////////// #ifdef _USE_EIGEN ///Compute a rotation exponential using the Rodrigues Formula. ///The rotation axis is given by \f$\vec{w}\f$, and the rotation angle must ///be computed using \f$ \theta = |\vec{w}|\f$. This is provided as a separate ///function primarily to allow fast and rough matrix exponentials using fast ///and rough approximations to \e A and \e B. /// ///@param w Vector about which to rotate. ///@param A \f$\frac{\sin \theta}{\theta}\f$ ///@param B \f$\frac{1 - \cos \theta}{\theta^2}\f$ ///@param R Matrix to hold the return value. ///@relates SO3 template inline void eigen_SO3_exp(const typename Eigen::SO3::Vec3& w, typename Eigen::SO3::Mat3& R) { static const Precision one_6th(1.0/6.0); static const Precision one_20th(1.0/20.0); //Use a Taylor series expansion near zero. This is required for //accuracy, since sin t / t and (1-cos t)/t^2 are both 0/0. Precision A, B; const Precision theta_sq(w.squaredNorm()); if (theta_sq < Precision(1e-8)) { A = Precision(1) - one_6th * theta_sq; B = Precision(0.5); } else { if (theta_sq < Precision(1e-6)) { B = Precision(0.5) - Precision(0.25) * one_6th * theta_sq; A = Precision(1) - theta_sq * one_6th*(Precision(1) - one_20th * theta_sq); } else { const Precision theta(sqrt(theta_sq)); const Precision inv_theta(Precision(1)/theta); A = sin(theta) * inv_theta; B = (Precision(1) - cos(theta)) * (inv_theta * inv_theta); } } { const Precision wx2(w(0)*w(0)); const Precision wy2(w(1)*w(1)); const Precision wz2(w(2)*w(2)); R(0,0) = Precision(1) - B*(wy2 + wz2); R(1,1) = Precision(1) - B*(wx2 + wz2); R(2,2) = Precision(1) - B*(wx2 + wy2); } { const Precision a(A*w[2]); const Precision b(B*(w[0]*w[1])); R(0,1) = b - a; R(1,0) = b + a; } { const Precision a(A*w[1]); const Precision b(B*(w[0]*w[2])); R(0,2) = b + a; R(2,0) = b - a; } { const Precision a(A*w[0]); const Precision b(B*(w[1]*w[2])); R(1,2) = b - a; R(2,1) = b + a; } } template inline typename Eigen::SO3::Mat3 Eigen::SO3::exp(const Vec3& w) const { Mat3 result; eigen_SO3_exp(w, result); return result; } /// Take the logarithm of the matrix, generating the corresponding vector in the Lie Algebra. /// See the Detailed Description for details of this vector. template inline void eigen_SO3_ln(const typename Eigen::SO3::Mat3& R, typename Eigen::SO3::Vec3& w) { const Precision cos_angle((R(0,0) + R(1,1) + R(2,2) - Precision(1)) * Precision(0.5)); w(0) = (R(2,1)-R(1,2))*Precision(0.5); w(1) = (R(0,2)-R(2,0))*Precision(0.5); w(2) = (R(1,0)-R(0,1))*Precision(0.5); const Precision sin_angle_abs(sqrt(w.squaredNorm())); if (cos_angle > Precision(M_SQRT1_2)) { // [0 - Pi/4] use asin if (sin_angle_abs > Precision(0)) w *= asin(sin_angle_abs) / sin_angle_abs; } else if (cos_angle > Precision(-M_SQRT1_2)) { // [Pi/4 - 3Pi/4] use acos, but antisymmetric part if (sin_angle_abs > Precision(0)) w *= acos(cos_angle) / sin_angle_abs; } else { // rest use symmetric part // antisymmetric part vanishes, but still large rotation, need information from symmetric part const Precision angle(Precision(M_PI) - asin(sin_angle_abs)); const Precision d0(R(0,0) - cos_angle); const Precision d1(R(1,1) - cos_angle); const Precision d2(R(2,2) - cos_angle); typename Eigen::SO3::Vec3 r2; if (d0*d0 > d1*d1 && d0*d0 > d2*d2) { // first is largest, fill with first column r2(0) = d0; r2(1) = (R(1,0)+R(0,1))*Precision(0.5); r2(2) = (R(0,2)+R(2,0))*Precision(0.5); } else if (d1*d1 > d2*d2) { // second is largest, fill with second column r2(0) = (R(1,0)+R(0,1))*Precision(0.5); r2(1) = d1; r2(2) = (R(2,1)+R(1,2))*Precision(0.5); } else { // third is largest, fill with third column r2(0) = (R(0,2)+R(2,0))*Precision(0.5); r2(1) = (R(2,1)+R(1,2))*Precision(0.5); r2(2) = d2; } // flip, if we point in the wrong direction! if (r2.dot(w) < Precision(0)) r2 *= Precision(-1); w = r2 * (angle/r2.norm()); } } template inline typename Eigen::SO3::Vec3 Eigen::SO3::ln() const { Vec3 result; eigen_SO3_ln(mat, result); return result; } /// Write an SO3 to a stream /// @relates SO3 template inline std::ostream& operator<<(std::ostream& os, const Eigen::SO3& rhs) { return os << rhs.get_matrix(); } /// Read from SO3 to a stream /// @relates SO3 template inline std::istream& operator>>(std::istream& is, Eigen::SO3& rhs) { is >> rhs.mat; rhs.coerce(); return is; } /// Right-multiply by a Vector /// @relates SO3 template inline Eigen::Matrix operator*(const Eigen::SO3

& lhs, const Eigen::Matrix& rhs) { return lhs.get_matrix() * rhs; } /// Left-multiply by a Vector /// @relates SO3 template inline Eigen::Matrix operator*(const Eigen::Matrix& lhs, const Eigen::SO3

& rhs) { return lhs * rhs.get_matrix(); } /// Right-multiply by a matrix /// @relates SO3 template inline Eigen::Matrix operator*(const Eigen::SO3

& lhs, const Eigen::Matrix& rhs) { return lhs.get_matrix() * rhs; } /// Left-multiply by a matrix /// @relates SO3 template inline Eigen::Matrix operator*(const Eigen::Matrix& lhs, const Eigen::SO3

& rhs) { return lhs * rhs.get_matrix(); } /*----------------------------------------------------------------*/ /// Exponentiate an angle in the Lie algebra to generate a new SO2. template inline void eigen_SO2_exp(const Precision& d, typename Eigen::SO2::Mat2& R) { R(0,0) = R(1,1) = cos(d); R(1,0) = sin(d); R(0,1) = -R(1,0); } template inline typename Eigen::SO2::Mat2 Eigen::SO2::exp(const Precision& d) const { Mat2 result; eigen_SO2_exp(d, result); return result; } /// Extracts the rotation angle from the SO2 template inline void eigen_SO2_ln(const typename Eigen::SO2::Mat2& R, Precision& d) { d = atan2(R(1,0), R(0,0)); } template inline Precision Eigen::SO2::ln() const { Precision d; eigen_SO2_ln(mat, d); return d; } /// Write an SO2 to a stream /// @relates SO2 template inline std::ostream& operator<<(std::ostream& os, const Eigen::SO2 & rhs) { return os << rhs.get_matrix(); } /// Read from SO2 to a stream /// @relates SO2 template inline std::istream& operator>>(std::istream& is, Eigen::SO2& rhs) { is >> rhs.mat; rhs.coerce(); return is; } /// Right-multiply by a Vector /// @relates SO2 template inline Eigen::Matrix operator*(const Eigen::SO2

& lhs, const Eigen::Matrix& rhs) { return lhs.get_matrix() * rhs; } /// Left-multiply by a Vector /// @relates SO2 template inline Eigen::Matrix operator*(const Eigen::Matrix& lhs, const Eigen::SO2

& rhs) { return lhs * rhs.get_matrix(); } /// Right-multiply by a Matrix /// @relates SO2 template inline Eigen::Matrix operator*(const Eigen::SO2

& lhs, const Eigen::Matrix& rhs) { return lhs.get_matrix() * rhs; } /// Left-multiply by a Matrix /// @relates SO2 template inline Eigen::Matrix operator*(const Eigen::Matrix& lhs, const Eigen::SO2

& rhs) { return lhs * rhs.get_matrix(); } /*----------------------------------------------------------------*/ namespace Eigen { template std::istream& operator >> (std::istream& st, MatrixBase& m) { for (int i = 0; i < m.rows(); ++i) for (int j = 0; j < m.cols(); ++j) st >> m(i, j); return st; } } // namespace Eigen /*----------------------------------------------------------------*/ #endif // _USE_EIGEN // C L A S S ////////////////////////////////////////////////////// #ifdef _USE_BOOST namespace boost { namespace serialization { // Serialization support for cv::Mat template void save(Archive& ar, const cv::Mat& m, const unsigned int /*version*/) { const int elem_type = m.type(); const size_t elem_size = m.elemSize(); ar & m.cols; ar & m.rows; ar & elem_type; ar & elem_size; const size_t data_size = elem_size * m.cols * m.rows; if (m.isContinuous()) { ar & boost::serialization::make_array(m.ptr(), data_size); } else { cv::Mat m_cont; m.copyTo(m_cont); ar & boost::serialization::make_array(m_cont.ptr(), data_size); } } template void load(Archive& ar, cv::Mat& m, const unsigned int /*version*/) { int cols, rows, elem_type; size_t elem_size; ar & cols; ar & rows; ar & elem_type; ar & elem_size; m.create(rows, cols, elem_type); const size_t data_size = elem_size * m.cols * m.rows; ar & boost::serialization::make_array(m.ptr(), data_size); } template inline void serialize(Archive& ar, cv::Mat& m, const unsigned int version) { split_free(ar, m, version); } // Serialization support for cv::Mat_ template void save(Archive& ar, const cv::Mat_<_Tp>& m, const unsigned int /*version*/) { ar & m.cols; ar & m.rows; const size_t data_size = m.cols * m.rows; if (m.isContinuous()) { ar & boost::serialization::make_array((const _Tp*)m.ptr(), data_size); } else { cv::Mat_<_Tp> m_cont; m.copyTo(m_cont); ar & boost::serialization::make_array((const _Tp*)m_cont.ptr(), data_size); } } template void load(Archive& ar, cv::Mat_<_Tp>& m, const unsigned int /*version*/) { int cols, rows; ar & cols; ar & rows; m.create(rows, cols); const size_t data_size = m.cols * m.rows; for (size_t n=0; n inline void serialize(Archive& ar, cv::Mat_<_Tp>& m, const unsigned int version) { split_free(ar, m, version); } // Serialization support for cv::Matx template void serialize(Archive& ar, cv::Matx<_Tp, m, n>& _m, const unsigned int /*version*/) { ar & _m.val; } // Serialization support for cv::Vec template void serialize(Archive& ar, cv::Vec<_Tp, cn>& v, const unsigned int /*version*/) { ar & boost::serialization::base_object >(v); } // Serialization support for cv::Point_ template void serialize(Archive& ar, cv::Point_<_Tp>& pt, const unsigned int /*version*/) { ar & pt.x & pt.y; } // Serialization support for cv::Point3_ template void serialize(Archive& ar, cv::Point3_<_Tp>& pt, const unsigned int /*version*/) { ar & pt.x & pt.y & pt.z; } // Serialization support for cv::Size_ template void serialize(Archive& ar, cv::Size_<_Tp>& sz, const unsigned int /*version*/) { ar & sz.width & sz.height; } // Serialization support for cv::Rect_ template void serialize(Archive& ar, cv::Rect_<_Tp>& rc, const unsigned int /*version*/) { ar & rc.x & rc.y & rc.width & rc.height; } // Serialization support for cv::KeyPoint template void serialize(Archive& ar, cv::KeyPoint& k, const unsigned int /*version*/) { ar & k.pt; ar & k.size; ar & k.angle; ar & k.response; ar & k.octave; ar & k.class_id; } // Serialization support for cv::DMatch template void serialize(Archive& ar, cv::DMatch& m, const unsigned int /*version*/) { ar & m.queryIdx; ar & m.trainIdx; ar & m.imgIdx; ar & m.distance; } #ifdef _USE_EIGEN // Serialization support for Eigen::Matrix // specialization handling fixed sized matrices template inline void save(Archive& ar, const Eigen::Matrix& M, const unsigned int /*version*/) { ar << make_nvp("data", make_array(M.data(), _Rows*_Cols)); } template inline void load(Archive& ar, Eigen::Matrix& M, const unsigned int /*version*/) { ar >> make_nvp("data", make_array(M.data(), _Rows*_Cols)); } // The function that causes boost::serialization to look for separate // save() and load() functions when serializing and Eigen matrix. template inline void serialize(Archive& ar, Eigen::Matrix& M, const unsigned int version) { split_free(ar, M, version); } #endif // _USE_EIGEN } // namespace serialization } // namespace boost /*----------------------------------------------------------------*/ // include headers that implement a archive in simple text and binary format or XML format #if defined(_MSC_VER) #pragma warning (push) #pragma warning (disable : 4275) // non dll-interface class #pragma warning (disable : 4715) // not all control paths return a value #endif #include #include #include #include //#include //#include // include headers that implement compressed serialization support #include #include #if BOOST_VERSION >= 106900 #include #endif #if defined(_MSC_VER) #pragma warning (pop) #endif enum ARCHIVE_TYPE { ARCHIVE_MVS = -1, ARCHIVE_TEXT = 0, ARCHIVE_BINARY, ARCHIVE_BINARY_ZIP, ARCHIVE_BINARY_ZSTD, ARCHIVE_LAST, #if BOOST_VERSION >= 106900 ARCHIVE_DEFAULT = ARCHIVE_BINARY_ZSTD #else ARCHIVE_DEFAULT = ARCHIVE_BINARY_ZIP #endif }; // export the current state of the given reconstruction object template bool SerializeSave(const TYPE& obj, std::ofstream& fs, ARCHIVE_TYPE type, unsigned flags=boost::archive::no_header) { // serialize out the current state switch (type) { case ARCHIVE_TEXT: { boost::archive::text_oarchive ar(fs, flags); ar << obj; break; } case ARCHIVE_BINARY: { boost::archive::binary_oarchive ar(fs, flags); ar << obj; break; } case ARCHIVE_BINARY_ZIP: { namespace io = boost::iostreams; io::filtering_streambuf ffs; ffs.push(io::zlib_compressor(io::zlib::best_speed)); ffs.push(fs); boost::archive::binary_oarchive ar(ffs, flags); ar << obj; break; } #if BOOST_VERSION >= 106900 case ARCHIVE_BINARY_ZSTD: { namespace io = boost::iostreams; io::filtering_streambuf ffs; ffs.push(io::zstd_compressor(io::zstd::best_speed)); ffs.push(fs); boost::archive::binary_oarchive ar(ffs, flags); ar << obj; break; } #endif default: VERBOSE("error: Can not save the object, invalid archive type"); return false; } return true; } // SerializeSave template bool SerializeSave(const TYPE& obj, const SEACAVE::String& fileName, ARCHIVE_TYPE type, unsigned flags=boost::archive::no_header) { // open the output stream std::ofstream fs(fileName, std::ios::out | std::ios::binary); if (!fs.is_open()) return false; // serialize out the current state return SerializeSave(obj, fs, type, flags); } // SerializeSave // import the state to the given reconstruction object template bool SerializeLoad(TYPE& obj, std::ifstream& fs, ARCHIVE_TYPE type, unsigned flags=boost::archive::no_header) { try { // serialize in the saved state switch (type) { case ARCHIVE_TEXT: { boost::archive::text_iarchive ar(fs, flags); ar >> obj; break; } case ARCHIVE_BINARY: { boost::archive::binary_iarchive ar(fs, flags); ar >> obj; break; } case ARCHIVE_BINARY_ZIP: { namespace io = boost::iostreams; io::filtering_streambuf ffs; ffs.push(io::zlib_decompressor()); ffs.push(fs); boost::archive::binary_iarchive ar(ffs, flags); ar >> obj; break; } #if BOOST_VERSION >= 106900 case ARCHIVE_BINARY_ZSTD: { namespace io = boost::iostreams; io::filtering_streambuf ffs; ffs.push(io::zstd_decompressor()); ffs.push(fs); boost::archive::binary_iarchive ar(ffs, flags); ar >> obj; break; } #endif default: VERBOSE("error: Can not load the object, invalid archive type"); return false; } } catch (const std::exception& e) { VERBOSE("error: invalid stream (%s)", e.what()); return false; } return true; } // SerializeLoad template bool SerializeLoad(TYPE& obj, const SEACAVE::String& fileName, ARCHIVE_TYPE type, unsigned flags=boost::archive::no_header) { // open the input stream std::ifstream fs(fileName, std::ios::in | std::ios::binary); if (!fs.is_open()) return false; // serialize in the saved state return SerializeLoad(obj, fs, type, flags); } // SerializeLoad /*----------------------------------------------------------------*/ #endif // _USE_BOOST #ifdef _USE_BREAKPAD #include #include #include #include class MiniDumper { public: static inline void Create(const SEACAVE::String& strAppNameANSI, SEACAVE::String strDumpPathANSI, MINIDUMP_TYPE dumpType=MiniDumpNormal, bool bOutOfProcess=true) { static MiniDumper oMiniDumper(strAppNameANSI, strDumpPathANSI, dumpType, bOutOfProcess); } static inline void Create(const SEACAVE::String& strAppNameANSI, SEACAVE::String strDumpPathANSI, int verbosity, bool bOutOfProcess=true) { MINIDUMP_TYPE dumpType; switch (verbosity) { case 1: dumpType = MiniDumpWithDataSegs; break; case 2: dumpType = MiniDumpWithFullMemory; break; default: dumpType = MiniDumpNormal; } Create(strAppNameANSI, strDumpPathANSI, dumpType, bOutOfProcess); } MiniDumper(const SEACAVE::String& strAppNameANSI, SEACAVE::String strDumpPathANSI, MINIDUMP_TYPE dumpType=MiniDumpNormal, bool bOutOfProcess=true) : crash_server(NULL), handler(NULL) { if (strDumpPathANSI.IsEmpty()) strDumpPathANSI = SEACAVE::Util::getCurrentFolder(); const std::wstring strDumpPath(strDumpPathANSI.begin(), strDumpPathANSI.end()); const std::wstring strAppName(strAppNameANSI.begin(), strAppNameANSI.end()); std::wstring strPipeName; if (bOutOfProcess) { // try to create an out-of-process minidumper const SEACAVE::String strUUIDANSI(SEACAVE::Util::getUniqueName(0)); const std::wstring strUUID(strUUIDANSI.begin(), strUUIDANSI.end()); strPipeName = L"\\\\.\\pipe\\BreakpadCrashServices\\"+strAppName+L"-"+strUUID; crash_server = new google_breakpad::CrashGenerationServer( strPipeName, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, &strDumpPath); if (!crash_server->Start()) { VERBOSE("error: unable to start minidump server"); delete crash_server; crash_server = NULL; } } // create the minidumper const int kCustomInfoCount = 2; const google_breakpad::CustomInfoEntry kCustomInfoEntries[] = { google_breakpad::CustomInfoEntry(L"prod", strAppName.c_str()), google_breakpad::CustomInfoEntry(L"ver", L"1.0"), }; google_breakpad::CustomClientInfo custom_info = {kCustomInfoEntries, kCustomInfoCount}; handler = new google_breakpad::ExceptionHandler( strDumpPath, NULL, NULL, NULL, google_breakpad::ExceptionHandler::HANDLER_ALL, dumpType, (crash_server ? strPipeName.c_str() : NULL), &custom_info); } ~MiniDumper() { delete handler; delete crash_server; } google_breakpad::CrashGenerationServer* crash_server; google_breakpad::ExceptionHandler* handler; }; #endif