在做单目标定使用vc2013+opencv2.4.9环境写代码时,遇到Mat类型访问矩阵元素出错的bug,现在问题解决了,所以想在这里简单记一下,
Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 摄像机内参数矩阵 */
vector tvecsMat; /* 每幅图像的旋转向量 */
vector rvecsMat; /* 每幅图像的平移向量 */
Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */
Mat M1 = Mat(3, 4, CV_32FC1, Scalar::all(0));
vector M2;
vector M; /* 投影矩阵M,由矩阵M1、M2相乘得 */
在用以下函数标定完得到内外参之后,
calibrateCamera(object_points, image_points_seq, image_size, cameraMatrix, distCoeffs, rvecsMat, tvecsMat, 0);
我再存入M1、M2矩阵中,最后得到投影矩阵M
在存入M1、M2的过程中,我遇到了Mat类型访问矩阵元素出错,以下语句:
//由内参得到M1
M1.at<float>(0, 0) = cameraMatrix.at<float>(0, 0);
M1.at<float>(0, 1) = cameraMatrix.at<float>(0, 1);
M1.at<float>(0, 2) = cameraMatrix.at<float>(0, 2);
M1.at<float>(0, 3) = 0;
M1.at<float>(1, 0) = cameraMatrix.at<float>(1, 0);
M1.at<float>(1, 1) = cameraMatrix.at<float>(1, 1);
M1.at<float>(1, 2) = cameraMatrix.at<float>(1, 2);
M1.at<float>(1, 3) = 0;
M1.at<float>(2, 0) = cameraMatrix.at<float>(2, 0);
M1.at<float>(2, 1) = cameraMatrix.at<float>(2, 1);
M1.at<float>(2, 2) = cameraMatrix.at<float>(2, 2);
M1.at<float>(2, 3) = 0;
fout << "摄像机的M1矩阵:" << endl;
fout << M1 << endl;
之前at<>内为double时,也有这样的错误,后来发现上面定义是CV_32FC1,所以改成了float问题就解决了,于是M2我也用了一样的方法,出错了,最后正确的代码如下:
for (int i = 0; i"第" << i + 1 << "幅图像的旋转向量:" << endl;
fout << rvecsMat[i] << endl;
/* 将旋转向量转换为相对应的旋转矩阵 */
Rodrigues(rvecsMat[i], rotation_matrix);
fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
fout << rotation_matrix << endl;
cout << rotation_matrix.at<double>(0, 0) << endl;
fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
fout << tvecsMat[i] << endl << endl;
/* 将旋转矩阵存入M2中 */
Mat TempM2 = Mat(4, 4, CV_32FC1, Scalar::all(0));
//cout << sizeof(CV_8UC1) << endl;
//cout << sizeof(CV_32FC1) << endl;
//cout << sizeof(int) << endl;
//cout << sizeof(short) << endl;
//cout << sizeof(long) << endl;
//cout << sizeof(float) << endl;
//cout << sizeof(double) << endl;
TempM2.at<float>(0, 0) = rotation_matrix.at<double>(0, 0);
TempM2.at<float>(0, 1) = rotation_matrix.at<double>(0, 1);
TempM2.at<float>(0, 2) = rotation_matrix.at<double>(0, 2);
TempM2.at<float>(0, 3) = tvecsMat[i].at<double>(0);
TempM2.at<float>(1, 0) = rotation_matrix.at<double>(1, 0);
TempM2.at<float>(1, 1) = rotation_matrix.at<double>(1, 1);
TempM2.at<float>(1, 2) = rotation_matrix.at<double>(1, 2);
TempM2.at<float>(1, 3) = tvecsMat[i].at<double>(1);
TempM2.at<float>(2, 0) = rotation_matrix.at<double>(2, 0);
TempM2.at<float>(2, 1) = rotation_matrix.at<double>(2, 1);
TempM2.at<float>(2, 2) = rotation_matrix.at<double>(2, 2);
TempM2.at<float>(2, 3) = tvecsMat[i].at<double>(2);
TempM2.at<float>(2, 0) = 0;
TempM2.at<float>(2, 1) = 0;
TempM2.at<float>(2, 2) = 0;
TempM2.at<float>(2, 3) = 1;
cout << TempM2 << endl;
M2.push_back(TempM2);
fout << "摄像机的M2矩阵:" << endl;
fout << M2[i] << endl;
}
之前我用的所有矩阵对应元素访问语句如下:
TempM2.at<float>(0, 0) = rotation_matrix.at<float>(0, 0);
我的想法是M1、cameraMatrix、TempM2、rotation_matrix都是CV_32FC1型,所以所有at<>都用的float,后来出错后,单步调试找原因,最后发现
Rodrigues(rvecsMat[i], rotation_matrix);
是这个函数这里的问题,在调用这个函数之前
cout << rotation_matrix.at<float>(0, 0) << endl;
是对的,这个函数作用之后,就要用double访问了,后面好不容易找到了Rodrigues函数的源码,在calibration.cpp中,看了仍然没搞明白,时间原因就没有细究了,有时间再回来看看~
所以要注意Rodrigues函数会改变mat的数值类型。