上一篇 opencv2.0 DataType 我们看了DataType的组成,这一篇就来研究一下他们的成员函数。
Point_(在operations.hpp里)
//7个构造函数
template<typename _Tp> inline Point_<_Tp>::Point_() : x(0), y(0) {}
template<typename _Tp> inline Point_<_Tp>::Point_(_Tp _x, _Tp _y) : x(_x), y(_y) {}
template<typename _Tp> inline Point_<_Tp>::Point_(const Point_& pt) : x(pt.x), y(pt.y) {}
template<typename _Tp> inline Point_<_Tp>::Point_(const CvPoint& pt) : x((_Tp)pt.x), y((_Tp)pt.y) {}
template<typename _Tp> inline Point_<_Tp>::Point_(const CvPoint2D32f& pt)
: x(saturate_cast<_Tp>(pt.x)), y(saturate_cast<_Tp>(pt.y)) {}
template<typename _Tp> inline Point_<_Tp>::Point_(const Size_<_Tp>& sz) : x(sz.width), y(sz.height) {}
template<typename _Tp> inline Point_<_Tp>::Point_(const Vec<_Tp,2>& v) : x(v[0]), y(v[1]) {}
其中两个为了兼容1.0版本,这个就不考虑了。我们主要来看看剩余的5个
#include<iostream>
#include<opencv2/core/core.hpp>
using namespace std;
using namespace cv;
int main()
{
Point p1;
Point2f p2(1.1,2.2);
Point2f p3(p2);
Point2d p4(Size_<double>(0.5,0.6));
Point2i p5(Vec<int,2>(0,0));
return 0;
}
接下来推荐一篇博客 saturate_cast 研究 ,专门讨论saturate_cast模板类,因为以后到处要用到...看过之后,千万不要再使用强制类型转换了,否则出问题后果自负...
template<typename _Tp> inline Point_<_Tp>& Point_<_Tp>::operator = (const Point_& pt)
{ x = pt.x; y = pt.y; return *this; }
template<typename _Tp> template<typename _Tp2> inline Point_<_Tp>::operator Point_<_Tp2>() const
{ return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); }
template<typename _Tp> inline Point_<_Tp>::operator CvPoint() const
{ return cvPoint(saturate_cast<int>(x), saturate_cast<int>(y)); }
template<typename _Tp> inline Point_<_Tp>::operator CvPoint2D32f() const
{ return cvPoint2D32f((float)x, (float)y); }
template<typename _Tp> inline Point_<_Tp>::operator Vec<_Tp, 2>() const
{ return Vec<_Tp, 2>(x, y); }
复制构造函数,就是分别给x,y分量赋值,强制类型转换有转成Point_<_Tp>和Vec<_Tp,2>型的,对于转成Point_<_Tp>其实就是x,y分量分别通过saturate_cast一下。剩余两个是兼容1.0版本,不讲了。
Point p1(1,2);
Point2i p2 = p1;
Point2d p3(1.2,2.3);
Point_<int> p4 = p3; //此处x,y会强转为int
Point_<int> p5(-1,256);
Point_<char> p6 = Point_<char>(p5); //2.3.1编译报错
Point_<char> p6 = static_cast<Point_<char> >(p5); //2.3.1编译报错
Vec2i vec = (Vec2i)p5;
郁闷啊,找了很久的错误,最后一行一直编译通不过,最后发现可能是低版本的一个bug,高版本已修复可以编译通过了,至于编译错误的原因,可能是编译器将(Point_<char>)p5看做Point_<char>(p5),然后尝试调用p5的隐式转换,可以从上面看出有CvPoint,CvPoint2D32f,Point_<_Tp>这三种隐式转换,那么这3个都可以作为Point_的拷贝构造函数的参数,因此编译器就不清楚了,然后报错了。从侧面体现了强制类型转换实际上是被编译器认为调用构造函数,尝试从多个重载过的强制转换函数做隐式转换,所以当重载了多个强制转换函数和这些强转后的类型都有匹配的构造函数时,需要注意了,此时就会出现冲突。
一个问题折射了强制转换函数真正的运行原理,看来这么多时间花得是值得的,既然这样,那么尝试修改源码,注释掉那两个早期版本的构造函数或者在前面加关键字explicit,限制隐式调用,或者直接注释掉那两个早版本的强制转换函数,理论上可以得到解决,但是考虑到整个库是一个整体,关联紧密,可能这些东西在别处会被引用(实际上修改后确实在别处报错了),因此建议使用高版本。
两个点积函数,(x1,y1)与(x2,y2)的点积为x1*x2+y1*y2
template<typename _Tp> inline _Tp Point_<_Tp>::dot(const Point_& pt) const
{ return saturate_cast<_Tp>(x*pt.x + y*pt.y); }
template<typename _Tp> inline double Point_<_Tp>::ddot(const Point_& pt) const
{ return (double)x*pt.x + (double)y*pt.y; }
Point_<char> p1(1,2);
Point p2(-129,0);
p1.dot(p2); //ASCII:127
Point_<schar> p3(1,2);
Point p4(-129,0);
p3.dot(p4); //ASCII:-128
Point p5(-129,0),p6(12,12);
p5.ddot(p6); //1548
我们这里用得非常规一下,主要是要注意以后这样用要小心,对于dot如果调用对象的模板类型与形参对象的模板类型不一致,则形参对象的模板类型会调用强制转换函数转成调用对象的模板类型,然后在尝试进行点积,这里就有一个疑问了,上面部分我说低版本2.3.1对于强制转换会报错,但是这个竟然编译通过了,原因解释如下:经过debug,发现实参强制转换后并没有调用形参的拷贝构造函数,至于为什么不调用,我也解释不清,因为如果传入的形参不需要强制转换,则是会调用拷贝构造函数的,难道这里编译器做了什么 ...不清楚了...
Point p1(1,2),p2(2,1);
p1 += p2; // +=
p1 -= p2; // -=
p1 *= 1; // * int
p1 *= (float)1.0; // * float
p1 *= 1.0; // * double
norm(p1); //sqrt((double)p1.x*p1.x + (double)p1.y*p1.y)
p1 == p2; // ==
p1 != p2; // !=
p1 + p2; // +
p1 - p2; // -
- p1; // 取反
1 * p1; // int *
p1 * 1; // * int
(float)1.0 * p1; // float *
p1 * (float)1.0; // * float
1.0 * p1; // double *
p1 * 1.0; // * double
template<typename _Tp> inline bool Point_<_Tp>::inside( const Rect_<_Tp>& r ) const
{ return r.contains(*this);}
Point(1,1).inside(Rect(1,1,1,1));
//6个构造函数
template<typename _Tp> inline Point3_<_Tp>::Point3_() : x(0), y(0), z(0) {}
template<typename _Tp> inline Point3_<_Tp>::Point3_(_Tp _x, _Tp _y, _Tp _z) : x(_x), y(_y), z(_z) {}
template<typename _Tp> inline Point3_<_Tp>::Point3_(const Point3_& pt) : x(pt.x), y(pt.y), z(pt.z) {}
template<typename _Tp> inline Point3_<_Tp>::Point3_(const Point_<_Tp>& pt) : x(pt.x), y(pt.y), z(_Tp()) {}
template<typename _Tp> inline Point3_<_Tp>::Point3_(const CvPoint3D32f& pt) :
x(saturate_cast<_Tp>(pt.x)), y(saturate_cast<_Tp>(pt.y)), z(saturate_cast<_Tp>(pt.z)) {}
template<typename _Tp> inline Point3_<_Tp>::Point3_(const Vec<_Tp, 3>& v) : x(v[0]), y(v[1]), z(v[2]) {}
#include<iostream>
#include<opencv2/core/core.hpp>
using namespace std;
using namespace cv;
int main()
{
Point3i p1;
Point3i p2(1,1,1);
Point3i p3(p2);
Point3f p4;
Point3i p5(p4); //2.3.1编译通不过
Vec<double,3> vec;
Point3d p6(vec);
return 0;
}
template<typename _Tp> template<typename _Tp2> inline Point3_<_Tp>::operator Point3_<_Tp2>() const
{ return Point3_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(z)); }
template<typename _Tp> inline Point3_<_Tp>::operator CvPoint3D32f() const
{ return cvPoint3D32f((float)x, (float)y, (float)z); }
template<typename _Tp> inline Point3_<_Tp>::operator Vec<_Tp, 3>() const
{ return Vec<_Tp, 3>(x, y, z); }
Point3i p1;
Point3_<short> p2 = (Point3_<short>)p1; //2.3.1编译通不过
Vec3i vec = (Vec3i)p1;
template<typename _Tp> inline Point3_<_Tp>& Point3_<_Tp>::operator = (const Point3_& pt)
{ x = pt.x; y = pt.y; z = pt.z; return *this; }
template<typename _Tp> inline _Tp Point3_<_Tp>::dot(const Point3_& pt) const
{ return saturate_cast<_Tp>(x*pt.x + y*pt.y + z*pt.z); }
template<typename _Tp> inline double Point3_<_Tp>::ddot(const Point3_& pt) const
{ return (double)x*pt.x + (double)y*pt.y + (double)z*pt.z; }
template<typename _Tp> inline Point3_<_Tp> Point3_<_Tp>::cross(const Point3_<_Tp>& pt) const
{ return Point3_<_Tp>(y*pt.z - z*pt.y, z*pt.x - x*pt.z, x*pt.y - y*pt.x); }
//6个构造函数
template<typename _Tp> inline Size_<_Tp>::Size_()
: width(0), height(0) {}
template<typename _Tp> inline Size_<_Tp>::Size_(_Tp _width, _Tp _height)
: width(_width), height(_height) {}
template<typename _Tp> inline Size_<_Tp>::Size_(const Size_& sz)
: width(sz.width), height(sz.height) {}
template<typename _Tp> inline Size_<_Tp>::Size_(const CvSize& sz)
: width(saturate_cast<_Tp>(sz.width)), height(saturate_cast<_Tp>(sz.height)) {}
template<typename _Tp> inline Size_<_Tp>::Size_(const CvSize2D32f& sz)
: width(saturate_cast<_Tp>(sz.width)), height(saturate_cast<_Tp>(sz.height)) {}
template<typename _Tp> inline Size_<_Tp>::Size_(const Point_<_Tp>& pt) : width(pt.x), height(pt.y) {}
#include<iostream>
#include<opencv2/core/core.hpp>
using namespace std;
using namespace cv;
int main()
{
Size s1;
Size2f s2(1,2);
Size2f s3(s2);
Size2i s4(Point(1,1));
Size2i s5(Vec<int,2> vec);
Vec2i vec;
Size2i s6(vec);
return 0;
}
template<typename _Tp> template<typename _Tp2> inline Size_<_Tp>::operator Size_<_Tp2>() const
{ return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); }
template<typename _Tp> inline Size_<_Tp>::operator CvSize() const
{ return cvSize(saturate_cast<int>(width), saturate_cast<int>(height)); }
template<typename _Tp> inline Size_<_Tp>::operator CvSize2D32f() const
{ return cvSize2D32f((float)width, (float)height); }
这里还是低版本会报错,因为拷贝构造函数冲突了
Size2i s1(1,1);
Size s2 = s1 * 1; // * _Tp
s2 = s1; // =
s1 + s2; // +
s1 - s2; // -
s1 += s2; // +=
s1 -= s2; // -=
s1 == s2; // ==
s1 != s2; // !=
s1.area(); // s1.width * s1.height
//6个构造函数
template<typename _Tp> inline Rect_<_Tp>::Rect_() : x(0), y(0), width(0), height(0) {}
template<typename _Tp> inline Rect_<_Tp>::Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height) : x(_x), y(_y), width(_width), height(_height) {}
template<typename _Tp> inline Rect_<_Tp>::Rect_(const Rect_<_Tp>& r) : x(r.x), y(r.y), width(r.width), height(r.height) {}
template<typename _Tp> inline Rect_<_Tp>::Rect_(const CvRect& r) : x((_Tp)r.x), y((_Tp)r.y), width((_Tp)r.width), height((_Tp)r.height) {}
template<typename _Tp> inline Rect_<_Tp>::Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz) :
x(org.x), y(org.y), width(sz.width), height(sz.height) {}
template<typename _Tp> inline Rect_<_Tp>::Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2)
{
x = std::min(pt1.x, pt2.x); y = std::min(pt1.y, pt2.y);
width = std::max(pt1.x, pt2.x) - x; height = std::max(pt1.y, pt2.y) - y;
}
#include<iostream>
#include<opencv2/core/core.hpp>
using namespace std;
using namespace cv;
int main()
{
Rect r1;
Rect r2(1,1,2,2);
Rect r3(r1);
Rect r4(Point(1,1),Size(2,2));
Rect r5(Point(2,2),Point(1,3));
Rect r6(Point(2,2),Point(2,3));
return 0;
}
//! the top-left corner
Point_<_Tp> tl() const;
//! the bottom-right corner
Point_<_Tp> br() const;
//! size (width, height) of the rectangle
Size_<_Tp> size() const;
//! area (width*height) of the rectangle
_Tp area() const;
Rect r1(1,1,2,2);
r1.tl(); // 左上角(1,1)
r1.br(); // 右下角(3,3)
Size s = r1.size();
r1.area(); // r1.width * r1.height
template<typename _Tp> template<typename _Tp2> inline Rect_<_Tp>::operator Rect_<_Tp2>() const
{ return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y),
saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); }
template<typename _Tp> inline Rect_<_Tp>::operator CvRect() const
{ return cvRect(saturate_cast<int>(x), saturate_cast<int>(y),
saturate_cast<int>(width), saturate_cast<int>(height)); }
template<typename _Tp> inline bool Rect_<_Tp>::contains(const Point_<_Tp>& pt) const
{ return x <= pt.x && pt.x < x + width && y <= pt.y && pt.y < y + height; }
Rect r1(1,1,1,1);
r1.contains(Point(1,1)); // true
r1.contains(Point(1,2)); // false
r1.contains(Point(2,1)); // false
r1.contains(Point(2,2)); //false
注意矩形的右边界和下边界不算在矩形里,对于浮点型的要注意,因为浮点误差,右边界与下边界判断可能出现误差...
Rect r1(1,1,1,1);
r1 += Point(1,1); //平移
r1 -= Point(1,1); //平移
r1 = r1 + Point(1,1); //平移
r1 = r1 - Point(1,1); //平移
r1 += Size(1,1); //扩张
r1 -= Size(1,1); //缩小
r1 = r1 + Size(1,1); //扩张
r1 = r1 - Size(1,1); //缩小
r1 == r1;
r1 != r1;
template<typename _Tp> static inline Rect_<_Tp>& operator &= ( Rect_<_Tp>& a, const Rect_<_Tp>& b )
{
_Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y);
a.width = std::min(a.x + a.width, b.x + b.width) - x1;
a.height = std::min(a.y + a.height, b.y + b.height) - y1;
a.x = x1; a.y = y1;
if( a.width <= 0 || a.height <= 0 )
a = Rect();
return a;
}
template<typename _Tp> static inline Rect_<_Tp>& operator |= ( Rect_<_Tp>& a, const Rect_<_Tp>& b )
{
_Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y);
a.width = std::max(a.x + a.width, b.x + b.width) - x1;
a.height = std::max(a.y + a.height, b.y + b.height) - y1;
a.x = x1; a.y = y1;
return a;
}
来参观一下代码,比较复杂,大致说说思想。&表示矩形求交集,可以肯定结果必然是一个矩形或者不存在。我们考虑矩形a和矩形b的左上角,如果两者有交集,那么交集矩形的左上角必然是 ( max(a.x,b.x),max(a.y,b.y) ),因为矩形a和b都是以左上角往右边和下边延伸的,因此例如a.x<b.x,那么在区间[a.x,b.x]之间必然不存在交集,因为b是往右延伸的,y方向也是这样。这样我们便得到了相交矩形的左上角顶点,那么width和height怎么定,显然我们知道a的右边界坐标a.x+a.width和b的右边界坐标b.x+b.width,显然要取最小值min(a.x+a.width,b.x+b.width),因为大于这个最小值部分是不会有交集的,然后我们知道左上角坐标,也就是左边界坐标,然后将这个最小值减去左边界,我们就得到了交集矩形的width,同理计算height...然而我们会发现当交集不存在的情况下,按照我们这种做法,左上角坐标还是存在的,但是会发现width和height小于等于0的情况,其实可以通过枚举法,把所有a和b可能的位置枚举一遍,可以发现上面这种做法均是正确的...
Rect r1(1,1,1,1);
Rect r2(2,2,1,1);
r1 & r2;
r1 | r2;
r1 &= r2;
r1 |= r2;
当然如果要判断矩形a是否包含于矩形b,则只要判断a & b是否等于 b即可...
//3个构造函数
inline RotatedRect::RotatedRect() { angle = 0; }
inline RotatedRect::RotatedRect(const Point2f& _center, const Size2f& _size, float _angle)
: center(_center), size(_size), angle(_angle) {}
inline RotatedRect::RotatedRect(const CvBox2D& box)
: center(box.center), size(box.size), angle(box.angle) {}
#include<iostream>
#include<opencv2/core/core.hpp>
using namespace std;
using namespace cv;
int main()
{
RotatedRect rr1;
RotatedRect rr2(Point2f(),Size2f(1,2),0);
return 0;
}
强制转换
inline RotatedRect::operator CvBox2D() const
{
CvBox2D box; box.center = center; box.size = size; box.angle = angle;
return box;
}
CvBox2D是1.0版本的,这里不做讨论了...
//! returns 4 vertices of the rectangle
void points(Point2f pts[]) const;
//! returns the minimal up-right rectangle containing the rotated rectangle
Rect boundingRect() const;
void RotatedRect::points(Point2f pt[]) const
{
double _angle = angle*CV_PI/180.;
float b = (float)cos(_angle)*0.5f;
float a = (float)sin(_angle)*0.5f;
pt[0].x = center.x - a*size.height - b*size.width;
pt[0].y = center.y + b*size.height - a*size.width;
pt[1].x = center.x + a*size.height - b*size.width;
pt[1].y = center.y - b*size.height - a*size.width;
pt[2].x = 2*center.x - pt[0].x;
pt[2].y = 2*center.y - pt[0].y;
pt[3].x = 2*center.x - pt[1].x;
pt[3].y = 2*center.y - pt[1].y;
}
Rect RotatedRect::boundingRect() const
{
Point2f pt[4];
points(pt);
Rect r(cvFloor(min(min(min(pt[0].x, pt[1].x), pt[2].x), pt[3].x)),
cvFloor(min(min(min(pt[0].y, pt[1].y), pt[2].y), pt[3].y)),
cvCeil(max(max(max(pt[0].x, pt[1].x), pt[2].x), pt[3].x)),
cvCeil(max(max(max(pt[0].y, pt[1].y), pt[2].y), pt[3].y)));
r.width -= r.x - 1;
r.height -= r.y - 1;
return r;
}
接下来,睁大眼睛看我的深入分析,首先我们来谈一谈这个angle参数的内涵,首先angle是角度制的,并且没有范围限制,也就是不需要【0,360),但是由于三角函数的周期性,超出这个范围也可以映射到这范围里的...
Point2f p[4];
RotatedRect rr(Point2f(),Size2f(1,1.8),1);
rr.points(p);
Rect r = rr.boundingRect();
对于boundingRect这个函数,很无语啊,r.width -= r.x - 1;r.height -= r.y - 1; 这里为什么要减1呢?但从数学角度来说,这样的矩形并不是最小的,但是呢?写库者可能考虑图像处理是按像素点计算的,而矩形的定义不算下边界和右边界,所以width和height多了1,可能就是考虑图像多了一排像素和一列像素...有点坑,那让单纯为了几何计算的情何以堪...
Range(在operations.hpp里)
//3个构造函数
inline Range::Range() : start(0), end(0) {}
inline Range::Range(int _start, int _end) : start(_start), end(_end) {}
inline Range::Range(const CvSlice& slice) : start(slice.start_index), end(slice.end_index)
{
if( start == 0 && end == CV_WHOLE_SEQ_END_INDEX )
*this = Range::all();
}
#include<iostream>
#include<opencv2/core/core.hpp>
using namespace std;
using namespace cv;
int main()
{
Range r1;
Range r2(1,2);
return 0;
}
强制转换
inline Range::operator CvSlice() const
{ return *this != Range::all() ? cvSlice(start, end) : CV_WHOLE_SEQ; }
常用函数
inline int Range::size() const { return end - start; }
inline bool Range::empty() const { return start == end; }
inline Range Range::all() { return Range(INT_MIN, INT_MAX); }
Range r1(1,2);
r1.size();
r1.empty();
r1 = r1.all();
注意:all()返回的范围是【-2147483648,2147483647),显然如果取size(),那么会爆int...
一些运算符
Range r1(1,2),r2;
r1 == r2;
r1 != r2;
!r2; //true
r1 & r2; //交集
r1 &= r2;
r1 + 1; //r1.start + 1,r1.end + 1
1 + r1;
r1 - 1;
Matx();
Matx(_Tp v0); //!< 1x1 matrix
Matx(_Tp v0, _Tp v1); //!< 1x2 or 2x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2); //!< 1x3 or 3x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 1x4, 2x2 or 4x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 1x5 or 5x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 1x6, 2x3, 3x2 or 6x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 1x7 or 7x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 1x8, 2x4, 4x2 or 8x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 1x9, 3x3 or 9x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 1x10, 2x5 or 5x2 or 10x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3,
_Tp v4, _Tp v5, _Tp v6, _Tp v7,
_Tp v8, _Tp v9, _Tp v10, _Tp v11); //!< 1x12, 2x6, 3x4, 4x3, 6x2 or 12x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3,
_Tp v4, _Tp v5, _Tp v6, _Tp v7,
_Tp v8, _Tp v9, _Tp v10, _Tp v11,
_Tp v12, _Tp v13, _Tp v14, _Tp v15); //!< 1x16, 4x4 or 16x1 matrix
explicit Matx(const _Tp* vals); //!< initialize from a plain array
Matx<int,1,1> m1;
Matx<int,1,1> m2(1);
Matx12d m3(1,1);
Matx13d m4(1,1,1);
//...
double val[12];
Matx66d m5(val);
强制转换
template<typename _Tp, int m, int n> template<typename T2>
inline Matx<_Tp, m, n>::operator Matx<T2, m, n>() const
{
Matx<T2, m, n> M;
for( int i = 0; i < m*n; i++ ) M.val[i] = saturate_cast<T2>(val[i]);
return M;
}
Matx<int,1,1> m1;
m1(0,0); // val[0*n+0]
m1(0); //val[0]
static Matx all(_Tp alpha);
static Matx zeros();
static Matx ones();
static Matx eye();
static Matx diag(const diag_type& d);
static Matx randu(_Tp a, _Tp b);
static Matx randn(_Tp a, _Tp b);
_Tp dot(const Matx<_Tp, m, n>& v) const;
double ddot(const Matx<_Tp, m, n>& v) const;
Matx<int,1,2> m;
m = m.all(4); //返回一个元素全部为4的矩阵
m = m.zeros(); //返回一个元素全部为1的矩阵
m = m.ones(); //返回一个元素全部为0的矩阵
m = m.eye(); //返回一个对角线为1其余为0的矩阵
Matx<int,1,1> p(5);
m = m.diag(p); //返回一个对角线为p其余为0的矩阵,p的行为min(rows,cols),列为1
Matx<int,1,2> m1(1,1);
Matx<int,1,2> m2(1,2);
m1.dot(m2);
m1.ddot(m2);
template<int m1, int n1> Matx<_Tp, m1, n1> reshape() const;
template<int m1, int n1> Matx<_Tp, m1, n1> get_minor(int i, int j) const;
Matx<_Tp, 1, n> row(int i) const;
Matx<_Tp, m, 1> col(int i) const;
Matx<_Tp, MIN(m,n), 1> diag() const;
reshape和get_minor是模板函数,由于这个本身就是模板类,所以模板函数的参数不可以省略了,必须显示的写在函数名后,看例子。
Matx<int,1,2> m;
Matx<int,2,1> n;
n = m.reshape<2,1>(); //改变形状,必须保证元素个数相同
Matx<int,3,3> m1(1,2,3,4,5,6,7,8,9);
Matx<int,2,2> m2;
m2 = m1.get_minor<2,2>(1,1); //提取以m1(1,1)为左上角的2*2子矩阵
Matx<int,1,3> m3;
m3 = m1.row(0); //提取第0行
Matx<int,3,1> m4;
m4 = m1.col(0); //提取第0列
m4 = m1.diag(); //提取对角线,行为min(rows,cols),列为1
还有很多很多函数...
Matx<int,1,2> m1(1,2),m2(2,3);
m1 += m2;
m1 -= m2;
m1 + m2;
m1 - m2;
m1 *= 1; //int/float/double
m1 * 1; //int/float/double
m1 * Matx<int,2,1>(2,3); //矩阵乘法
- m1; //取反
Matx<int,1,2> m3(m1,m2,Matx_AddOp()); //对应元素相加
Matx<int,1,2> m4(m1,m2,Matx_SubOp()); //对应元素相减
Matx<int,1,2> m5(m1,5,Matx_ScaleOp()); //对应元素乘5
Matx<int,1,2> m6(m1,m2,Matx_MulOp()); //对应元素相乘
Matx<int,1,1> m7(m1,Matx<int,2,1>(2,3),Matx_MatMulOp()); //矩阵乘法
Matx<int,1,2> m8(Matx<int,2,1>(2,1),Matx_TOp()); //矩阵转置
Matx<int,2,2>() * Point();
Matx<int,3,3>() * Point(); //Point添加一维为1
Matx<int,3,3>() * Point3i();
Matx<int,4,4>() * Point3i(); //Point3i添加一维为1
m1.mul(m2); //对应元素相乘
Matx<int,2,2> m1(1,2,3,4);
Matx<int,2,2> m2;
m2 = m1.t(); //转置
trace(m1); //矩阵的迹,对角线之和
还有一些有关于矩阵分解的LU,CHOLESKY...涉及到算法了...以后有空补...
//! default constructor
Vec();
Vec(_Tp v0); //!< 1-element vector constructor
Vec(_Tp v0, _Tp v1); //!< 2-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2); //!< 3-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 4-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 5-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 6-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 7-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 8-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 9-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 10-element vector constructor
explicit Vec(const _Tp* values); //数组
Vec(const Vec<_Tp, cn>& v); //Vec
这里的注意Vec是继承Matx的,所以上述所有的构造方法都是调用了Matx的构造方法
#include<iostream>
#include<opencv2/core/core.hpp>
using namespace std;
using namespace cv;
int main()
{
Vec2i v1;
Vec3i v2(1,2,3);
Vec3i v3(v2);
Vec4i v4(new int[4]{4,3,2,1});
return 0;
}
//! convertion to another data type
template<typename T2> operator Vec<T2, cn>() const;
//! conversion to 4-element CvScalar.
operator CvScalar() const;
/*! element access */
const _Tp& operator [](int i) const;
_Tp& operator[](int i);
const _Tp& operator ()(int i) const;
_Tp& operator ()(int i);
static Vec all(_Tp alpha); //全部置为alpha
//! per-element multiplication
Vec mul(const Vec<_Tp, cn>& v) const; //对应分量相乘
/*!
cross product of the two 3D vectors.
For other dimensionalities the exception is raised
*/
Vec cross(const Vec& v) const; //这个貌似已废弃,直接抛异常了,但是特化版本是有的,见下面
Vec3i v1(1,2,3);
Vec3i v2 = v1.all(-1); //全部元素置为-1
v2 = v1.mul(v2); //对应分量相乘
v2.cross(v1);
Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_AddOp);
Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_SubOp);
template<typename _T2> Vec(const Matx<_Tp, cn, 1>& a, _T2 alpha, Matx_ScaleOp);
调用父类的方法
Vec3i v1(1,2,3),v2(1,2,3);
v1 += v2; // +=
v1 -= v2; // -=
v1 + v2; // +
v1 - v2; // -
v1 *= 1; // *= int
v1 *= (float)1.0; // *= float
v1 *= 1.0; // *= double
v1 * 1; // * int
1 * v1; // int *
v1 * (float)1.0; // * float
(float)1.0 * v1; // float *
v1 * 1.0; // * double
1.0 * v1; // double *
- v1; //取反
Vec3f v3(1,2,3);
v3.cross(v3); //叉积,float型的特化版本
Vec3f v4(1,2,3);
v4.cross(v4); //叉积,double型的特化版本
//特化版本,不同类型的向量+=,结果通过saturate_cast转换成第一种类型
Vec2i v5;
v5 += Vec2d(1,2); // 长度为2
Vec3i v6;
v6 += Vec3d(1,2,3); // 长度为3
Vec4i v7;
v7 += Vec4d(1,2,3,4); // 长度为4
//! various constructors
Scalar_();
Scalar_(_Tp v0, _Tp v1, _Tp v2=0, _Tp v3=0);
Scalar_(const CvScalar& s);
Scalar_(_Tp v0);
#include<iostream>
#include<opencv2/core/core.hpp>
using namespace std;
using namespace cv;
int main()
{
Scalar_<int> s1;
Scalar_<int> s2(1);
Scalar_<int> s3(1,2);
Scalar_<int> s4(1,2,3);
Scalar_<int> s5(1,2,3,4);
return 0;
}
因为Scalar_继承自Vec,所以Vec的函数都可以使用了...
//! conversion to the old-style CvScalar
operator CvScalar() const;
//! conversion to another data type
template<typename T2> operator Scalar_<T2>() const;
//! returns a scalar with all elements set to v0
static Scalar_<_Tp> all(_Tp v0); //全部置为v0
//! per-element product
Scalar_<_Tp> mul(const Scalar_<_Tp>& t, double scale=1 ) const; //对应分量相乘再乘上scale
// returns (v0, -v1, -v2, -v3)
Scalar_<_Tp> conj() const;
// returns true iff v1 == v2 == v3 == 0
bool isReal() const;
Scalar_<int> s1 = Scalar_<int>::all(3);
Scalar_<int> s2(1,2,3,4);
s1 = s1.mul(s2,2);
s1 = s1.conj();
s1.isReal();
Scalar s1,s2;
s1 += s2;
s1 -= s2;
s1 *= 1; // *_Tp
s1 + s2;
s1 - s2;
s1 * 1; // *_Tp
1 * s1; // *_Tp
- s1; //取反
s1 == s2;
s1 != s2;
s1 /= 1.0;
s1 / 1.0;
1.0 / s1; //s1.conj()*1.0/||s1||
s1 *= s2;
s1 * s2;
s1 /= s2;
s1 / s2;
后面4个定义很奇葩,不知道有没有什么意义...
template<typename _Tp> static inline Scalar_<_Tp>
operator * (const Scalar_<_Tp>& a, const Scalar_<_Tp>& b)
{
return Scalar_<_Tp>(saturate_cast<_Tp>(a[0]*b[0] - a[1]*b[1] - a[2]*b[2] - a[3]*b[3]),
saturate_cast<_Tp>(a[0]*b[1] + a[1]*b[0] + a[2]*b[3] - a[3]*b[2]),
saturate_cast<_Tp>(a[0]*b[2] - a[1]*b[3] + a[2]*b[0] - a[3]*b[1]),
saturate_cast<_Tp>(a[0]*b[3] + a[1]*b[2] - a[2]*b[1] - a[3]*b[0]));
}
template<typename _Tp> static inline Scalar_<_Tp>&
operator *= (Scalar_<_Tp>& a, const Scalar_<_Tp>& b)
{
a = a*b;
return a;
}
template<typename _Tp> static inline
Scalar_<_Tp> operator / (const Scalar_<_Tp>& a, const Scalar_<_Tp>& b)
{
return a*((_Tp)1/b);
}
template<typename _Tp> static inline
Scalar_<_Tp>& operator /= (Scalar_<_Tp>& a, const Scalar_<_Tp>& b)
{
a = a/b;
return a;
}