目录
- Mat 类
- Point2d/Point3d 类
- Vector2d/Vector3d 类
- Sophus::SE3d/SO3d 类
Mat类
Mat类是opencv中图像存储矩阵,常常与cv::imread()函数一起使用,注意的是,Mat矩阵不能与Eigen库中的矩阵进行任何数学运算,需要时必须进行转换。Mat类也存放一些固定的参数,如相机内参等等,对Mat类一个最重要操作便是访问矩阵内的元素。
1.利用Mat.ptr访问
cv::Mat image = cv::Mat(400, 600, CV_8UC1);
//创建一个Mat类的image矩阵
double d=image.ptr<unsigned short>(int(y))[int(x)];
//访问(x,y)处的元素
2.利用Mat.at访问
cv::Mat image = cv::Mat(400, 600, CV_8UC1);
//创建一个Mat类的image矩阵
double d=image.at<double>(y, x);
//访问(x,y)处的元素
注意:(x,y)是图像的像素坐标系,与一般的坐标系原点不同,在图像的左上角。对于矩阵便是:第x行,第y列的元素。
3.Mat矩阵的手动输入元素
cv::Mat y=(Mat_<double>(1,3)<<3,2,1);
//定义一个1×3的矩阵,并且输入数据
Point2d/Point3d 类
cv::Point2d; cv::Point3d是opencv中的一种存储二维/三维点的一种数据结构,常常用与容器配合使用,用于存储图像的特征点等等。
1.Keypoint转换为Point2d类
for(Dmatch m:matches){
vector<Point2d> pts_2=
(keypoints[matches[i].queryIdx].pt)
}
keypoints[i].pt返回的是一个point类
2.Point类访问元素
vector<Point2d> pts_2=
(keypoints[matches[i].queryIdx].pt)
double x= pts_2.x;
double y= pts_2.y;
3.Point类的数学运算
Point类可之间进行加减运算,乘除运算转换为cv::Vec3d类。
//求解特征点的质心
Point3f p1, p2; //质心坐标
int N = pts1.size();
//pts1为point3f类型
for (int i = 0; i < N; i++) {
p1 += pts1[i]; //加法运算
p2 += pts2[i];
}
p1 = Point3f(Vec3f(p1) / N);
p2 = Point3f(Vec3f(p2) / N);
//向量的乘法运算要转换为Vec3f类型
Vector2d/Vector3d 类
Vector2d/Vector3d是Eigen库中的向量,也常常用于图像相关的运算,其灵活性比cv中的point类要高,更加"数学化"。
1.运算性质
Vector2d/3本质是Eigen库的矩阵,实际运算过程严格按照矩阵运算即可。常常也用于存储图像的特征向量,特征点等,一般与容器配合使用。
2.赋值与遍历(手写输入数据)
Eigen::Vector3d xyz;
xyz <<
1 ,
2 ,
3;
Eigen::Vector3d t(1,2,3);
//创建一个向量,两种方式都可以,第一种不能之间赋值
double x =xyz(0 ,0);
double y =xyz(1 ,0);
double z =xyz(2 ,0);
//访问相应的元素
注意:手写赋值与Mat类不同,遍历是必须严格按照矩阵的行与列进行遍历。
3.Eigen与Point类的互相转换
//Point to eigen
//若pts为定义好的 vector<Point3d> pts_3d l类型并且已经赋值
vector<Eigen::Vector3d> pts3_eigen;
for (int i = 0; i < pts_3d.size(); i++)
{
pts3_eigen.push_back(
Eigen::Vector3d(pts_3d[i].x, pts_3d[i].y, pts_3d[i].z)
);
}
//eigen to Point
vector<cv::Point3d> point3;
for (int i = 0; i < pts3_eigen.size(); i++)
{
point3.push_back(
cv::Point3d(pts3_eigen[i](0, 0), pts3_eigen[i](1, 0), pts3_eigen[i](2, 0)));
}
Sophus::SE3d/SO3d类
李群李代数最直接的用法就是表达为位姿,如何对特征点进行变换,值得注意的是,此时的特征点必须是Eigen的Vector类型。
1.变换
Eigen::Matrix3d R = Eigen::AngleAxisd(M_PI / 2, Eigen::Vector3d(0, 1, 0)).toRotationMatrix();
//沿着y轴旋转90°
Eigen::Vector3d t(1, 0, 0);
//沿着x轴平移一个单位
Sophus::SE3d T(R, t);
Eigen::Vector3d v(0, 1, 0);
Eigen::Vector3d v_after = T * v;
cout << "变换前的向量:\n" << v << endl;
cout << "变换后的向量:\n" << v_after<< endl;
注:
1.以李群表示的位姿对某个Vector点变换后的数据类型还是Vector。
2.凡是在图像层次的运算都用cv里面的结构,凡是涉及其他的数学运算都用Eigen里面的结构。