在C++中,vector是一个容器类,用于存储动态数组。
而vector
为什么要这样嵌套写呢?这是因为在计算机视觉中,我们经常需要处理的是二维的数据,例如图像中的像素、特征点、轮廓点等。因此,我们需要使用一个二维的动态数组来存储这些数据。如果直接使用一个一维的动态数组,可能会比较难以处理这些二维数据。因此,使用vector
Point3f是OpenCV库中定义的一个结构体类型,表示一个三维坐标点。在C++中,6.0f表示一个float类型的浮点数,其值为6.0。在C++中,float类型的浮点数通常使用字母"f"来表示,以便于区分double类型的浮点数。如果不加"f",则默认为double类型的浮点数。
#include
#include
using namespace cv;
using namespace std;
int main()
{
// 定义和初始化一个Point3f类型的变量
Point3f pt1(1.0f, 2.0f, 3.0f);
// 或者使用默认构造函数来初始化
Point3f pt2;
// 访问Point3f变量的成员变量x、y、z
float x = pt1.x;
float y = pt1.y;
float z = pt1.z;
// 修改Point3f变量的成员变量
pt2.x = 4.0f;
pt2.y = 5.0f;
pt2.z = 6.0f;
cout << pt1 << endl;
return 0;
}
遍历棋盘格角点坐标:OpenCV 库中使用的是标准库中的容器类 std::vector
。cv::Point3f
是 OpenCV 库中定义的一个结构体类型,表示一个三维坐标点,包含三个 float
类型的成员变量,分别表示 x、y、z 三个坐标轴上的坐标值。在使用 std::vector
容器时,可以将 cv::Point3f
类型的对象作为元素添加到容器中,实现对一组三维坐标点的存储和管理。例如,可以定义一个 std::vector
类型的变量,用于存储多个三维坐标点。
int main() {
// 定义棋盘格大小和个数
Size boardSize(8, 8);
int boardNum = 10;
// 定义棋盘格角点坐标
vector> objPoints;
/*定义了一个二维向量的变量objPoints,其中每个元素都是一个三维点(Point3f)的向量(vector)。*/
/*其中objPoints中的每个元素都是一个由相机观察到的三维物体的点云,可以用于重建三维模型或者计算相机的内外参数等。*/
// 生成棋盘格角点坐标
vector obj;
for (int i = 0; i < boardSize.height; i++)
{
for (int j = 0; j < boardSize.width; j++)
{
obj.push_back(Point3f(j, i, 0));
}
}
for (int i = 0; i < boardNum; i++)
{
objPoints.push_back(obj);
}
cout << objPoints.size() << endl;
cout << objPoints[0].size() << endl;
// 遍历并输出二维vector容器中的元素
for (int i = 0; i < objPoints.size(); i++)
{
for (int j = 0; j < objPoints[i].size(); j++)
{
cout << objPoints[i][j] << " ";
}
cout << endl;
}
}
检测棋盘格角点
int main() {
// 定义棋盘格大小和个数
Size boardSize(8, 8);
Mat image = imread("0.jpg");
resize(image, image, Size(), 0.5, 0.5);
// 转换为灰度图
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
// 检测角点
vector corners;
bool found = findChessboardCorners(gray, boardSize, corners);
// 绘制角点
Mat imgCorners;
cvtColor(gray, imgCorners, COLOR_GRAY2BGR);
drawChessboardCorners(imgCorners, boardSize, corners, found);
// 显示图像
imshow("Corners", imgCorners);
waitKey(0);
}
检测普通角点
int main() {
cv::Mat image = cv::imread("1.jpg");
resize(image, image, Size(), 0.5, 0.5);
cv::Mat grayImage;
cv::cvtColor(image, grayImage, cv::COLOR_BGR2GRAY);
std::vector corners;
cv::goodFeaturesToTrack(grayImage, corners, 100, 0.01, 10);
/*
void cv::goodFeaturesToTrack(
InputArray image, // 输入图像,可以是8位或32位浮点型灰度图像
OutputArray corners, // 输出的角点坐标
int maxCorners, // 最多检测的角点数目
double qualityLevel, // 质量水平阈值,取值范围为[0,1],越大表示检测到的角点越准确
double minDistance, // 角点间最小距离,小于该距离的角点会被忽略
InputArray mask = noArray(), // 可选的掩膜图像,检测角点的区域
int blockSize = 3, // 计算角点响应函数时使用的窗口大小
bool useHarrisDetector = false, // 是否使用Harris角点检测算法,如果为false则使用Shi-Tomasi角点检测算法
double k = 0.04 // Harris角点检测算法的k值,取值范围为[0,04,0.06]
*/
for (size_t i = 0; i < corners.size(); i++)
{
cv::circle(image, corners[i], 3, cv::Scalar(0, 0, 255), -1);
}
cv::imshow("Corners", image);
cv::waitKey();
return 0;
}
push_back()
是向容器尾部添加元素的成员函数。
// 存储角点
imgPoints.push_back(corners);
cornerSubPix()
函数在 C++ 中的返回值类型是 void
,也就是说,该函数没有返回值。在函数调用后,可以直接使用修改后的 corners
向量中的元素来获取亚像素级别的角点坐标。
Mat
是OpenCV中的一个类,用于表示矩阵,可以不指定尺寸,此时会创建一个空的矩阵。
// 标定相机
Mat cameraMatrix, distCoeffs;
std::cout << "rows: " << cameraMatrix.rows << std::endl;
std::cout << "cols: " << cameraMatrix.cols << std::endl;
std::cout << "rows: " << distCoeffs.rows << std::endl;
std::cout << "cols: " << distCoeffs.cols << std::endl;
输出: rows: 3
cols: 3
rows: 1
cols: 5
其中相机内参
其中畸变参数
在C++中,vector
和vector
是相机标定过程中的输出参数,用于表示每幅图像的旋转向量和平移向量。其中
rvecs[0]:
[0.1765137348598873;
-0.004509234502410684;
-0.116059886448816]
tvecs[0]:
[-5.096144519206531;
-2.976894855117076;
22.2569114926337]
rvecs[1]:
[-0.2814441570484566;
0.09422450690486907;
-1.516149181978618]
tvecs[1]:
[-2.640683097822767;
4.033523428337181;
25.01756476495153]
......
通常使用罗德里格斯公式将旋转向量转换为旋转矩阵。罗德里格斯公式可以将一个3维向量转化为一个3x3的旋转矩阵。在OpenCV中,可以使用cv::Rodrigues
函数将旋转向量转换为旋转矩阵。
Mat R;
for (int i = 0; i < 10; i++)
{
Rodrigues(rvecs[i], R);
cout << "rvecs[" << i << "]:\n" << R << endl;// 查看 rvecs 中第 i 幅图像的旋转向量
cout << "tvecs[" << i << "]:\n" << tvecs[i] << endl;// 查看 tvecs 中第 i 幅图像的平移向量
}
rvecs[0]:
[0.9932799434099183, 0.1148016925916202, -0.01468078327912038;
-0.1155946774290525, 0.9777693984665894, -0.174942487613379;
-0.005729273048360591, 0.1754638846041632, 0.9844691974002814]
tvecs[0]:
[-5.096144519206531;
-2.976894855117076;
22.2569114926337]
#include
#include
using namespace cv;
using namespace std;
int main()
{
// 定义棋盘格大小和个数
Size boardSize(8, 8);
int boardNum = 10;
// 定义棋盘格角点坐标
vector> objPoints;
/*定义了一个二维向量的变量objPoints,其中每个元素都是一个三维点(Point3f)的向量(vector)。*/
/*其中objPoints中的每个元素都是一个由相机观察到的三维物体的点云,可以用于重建三维模型或者计算相机的内外参数等。*/
vector> imgPoints;
/*定义了一个二维向量的变量,每个元素都是一个二维点(Point2f)的向量(vector)*/
/*用来存储棋盘格图案的角点坐标,用于计算相机的内外参数。*/
// 生成棋盘格角点坐标
vector obj;
for (int i = 0; i < boardSize.height; i++)
{
for (int j = 0; j < boardSize.width; j++)
{
obj.push_back(Point3f(j, i, 0));
}
}
for (int i = 0; i < boardNum; i++)
{
objPoints.push_back(obj);
}
// 读取多个图片并提取角点
for (int i = 1; i <= boardNum; i++)
{
// 读取图片
string filename = "images/" + to_string(i) + ".jpg";
Mat image = imread(filename);
resize(image, image, Size(), 0.5, 0.5);
// 转换为灰度图
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
// 提取角点
vector corners;
bool found = findChessboardCorners(gray, boardSize, corners);
if (found)
{
// 亚像素精细化
cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
// 存储角点
imgPoints.push_back(corners);
// 可视化角点
drawChessboardCorners(image, boardSize, corners, found);
imshow("corners", image);
waitKey(0);
}
}
// 标定相机
Mat cameraMatrix, distCoeffs;
vector rvecs, tvecs;
calibrateCamera(objPoints, imgPoints, Size(640, 480), cameraMatrix, distCoeffs, rvecs, tvecs);
/*
calibrateCamera函数的参数包括:
objectPoints:已知的3D空间点的坐标,类型为vector>,其中Point3f是一个三维点的数据结构。
imagePoints:对应的2D图像点的坐标,类型为vector>,其中Point2f是一个二维点的数据结构。
imageSize:图像的大小,类型为Size。
cameraMatrix:相机的内部参数矩阵,类型为Mat。
distCoeffs:相机的畸变系数,类型为Mat。
rvecs:每个图像的旋转矢量,类型为vector。
tvecs:每个图像的平移矢量,类型为vector。
*/
// 打印标定结果
//cout << "camera matrix:\n" << cameraMatrix << endl;
//cout << "distortion coefficients:\n" << distCoeffs << endl;
Mat R;
for (int i = 0; i < 10; i++)
{
Rodrigues(rvecs[i], R);
cout << "rvecs[" << i << "]:\n" << R << endl;// 查看 rvecs 中第 i 幅图像的旋转向量
cout << "tvecs[" << i << "]:\n" << tvecs[i] << endl;// 查看 tvecs 中第 i 幅图像的平移向量
}
return 0;
}