我有一个真正令人头疼的时间试图弄清楚为什么我的 OpenCV 矩阵的人口完全按照我在调试模式下的预期工作,但是当我尝试发布项目时,它会截断所有的值给它,并错误地填充矩阵!
我的设置的简短描述:
- 我同时使用 OpenCV 和 ViSP 库来处理 USB Flycapture 相机。
- 我在 Qt-Creator 的 Ubuntu 16.04 上运行所有东西,因为我计划在这个项目中使用 GUI。
- 填充矩阵的参数对于相机的校准很重要,因此截断是绝对不行的!
上代码!
首先,我使用 ViSP 的内置类从文件中加载已保存的参数。出于调试目的(并确保我不会失去理智),我还将这些值保存到全局变量中以供快速参考:
bool load_intrinsics()
{
vpCameraParameters cam;
vpXmlParserCaemra parser;
std::string intrinsicFilePath = "...path to file...";
std::string cameraName = "Camera";
if (parser.parse(cam, intrinsicFilePath, camera_name, vpCameraParameters::perspectiveProjWithDistortion) != vpXmlParserCamera::SEQUENCE_OK)
{
std::cout << "ERROR WITH LOADING INTRINSICS" << std::endl;
return false;
}
else
{ // variables here are <double> variables, defined globally
global_px = cam.get_px();
global_py = cam.get_py();
global_u0 = cam.get_u0();
global_v0 = cam.get_v0();
global_kud = cam.get_kud();
return true;
}
}
`
这一切都按预期工作。该函数正确读取所有值并将这些值(未截断!)存储到全局变量中。
接下来我尝试将这些变量传递给一个cv::Mat
对象,这就是事情开始走下坡路的地方......
void createCvMat()
{
// create camera matrix
cv::Mat tempCamMat = cv::Mat::zeros(3, 3, CV_64F);
tempCamMat.at<double>(0, 0) = global_px;
tempCamMat.at<double>(0, 2) = global_u0;
tempCamMat.at<double>(1, 1) = global_py;
tempCamMat.at<double>(1, 2) = global_v0;
tempCamMat.at<double>(2, 2) = 1.0;
// create distortion matrix
cv::Mat tempDisMat = cv::Mat::zeros(5, 1, CV_64F);
tempDisMat.at<double>(0, 0) = global_kud;
// pass temporary matrices to empty global matrices
tempCamMat.copyTo(cameraMatrix);
tempDisMat.copyTo(distortionMatrix);
}
现在,如第一个代码片段中所述,我已经确保全局变量具有正确的值。然而,当我使用这些矩阵,例如,使用cv::undistort(...)
时,很明显矩阵没有正确加载。
作为完整性检查,我尝试将矩阵写出到控制台,并确保正确加载了值:
void sanityCheck(cv::Mat checkMatrix)
{
std::cout << std::endl << "Matrix holds:" <<std::endl;
for (int r = 0; r < checkMatrix.rows; r++)
{
for (int c = 0; c < checkMatrix.cols; c++)
{
std::cout << checkMatrix.at<double>(r, c) << " | ";
}
std::cout << std::endl;
}
}
在调试模式下调用两个矩阵的完整性检查,我得到以下输出:
`
Camera
Matrix Includes:
606.204 | 0 | 607.664 |
0 | 612.354 | 521.775 |
0 | 0 | 1 |
Distortion
Matrix Includes:
-0.240543 |
0 |
0 |
0 |
0 |
`
请注意,std::cout
控制台输出会截断写入六个有效数字的值,因为从文件中读取的数字有近二十个有效数字。结合使用该iomanip
库std::setprecision(...)
,我已经确认完整的数字已正确结转并插入到矩阵中。
在发布中调用相同的函数,我得到以下输出:
Camera
Matrix Includes:
606 | 0 | 607 |
0 | 612 | 521 |
0 | 0 | 1 |
Distortion
Matrix Includes:
-0 |
0 |
0 |
0 |
0 |
` 请注意,即使将双精度变量传递给能够容纳双精度变量的矩阵,也只有整数会填充矩阵!对于我的生活,我无法弄清楚为什么它在项目的发布版本中这样做,而不是在调试版本中!
作为当前的解决方法,我尝试将数字直接从“*.xml”文件复制粘贴到变量作为常量,然后将它们传递给cv::Mat
对象:
// define each global variable (don't read from file)
global_px = 606.20444013030078;
...
global_kud = -0.24054321189834804;
// populate matrices
createCvMat();
. 这工作得很好......我不知道为什么,但确实如此。
正如任何程序员很可能会告诉你的那样,应该避免这种常量的“硬编码”。如果我出于某种原因更改了相机上的设置并且必须重新校准,或者如果最终用户希望校准他们自己的相机,最好从外部文件中简单地读取这些内在值。