0

我有一个真正令人头疼的时间试图弄清楚为什么我的 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控制台输出会截断写入六个有效数字的值,因为从文件中读取的数字有近二十个有效数字。结合使用该iomanipstd::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();

. 这工作得很好......我不知道为什么,但确实如此。

正如任何程序员很可能会告诉你的那样,应该避免这种常量的“硬编码”。如果我出于某种原因更改了相机上的设置并且必须重新校准,或者如果最终用户希望校准他们自己的相机,最好从外部文件中简单地读取这些内在值。

4

1 回答 1

1

细节:

double将变量加载到cv::Mat<double>对象的问题与已安装的 Ubuntu-16.04 操作系统的本地化问题有关。由于 PC 是在德国配置的,无论安装时所有参数都设置为模仿 EN 标准,PC 仍将其数字、货币、时间等解释设置为 DE 标准。

double这意味着,从外部文件解析变量将导致操作系统将 EN 标准的小数位(即句点 (.))误认为是 DE 标准的千分位分隔符。这会导致double变量的小数部分被截断!

解决方案:

使用 Ubuntu-16.04 操作系统,这可以通过在终端内更改系统区域设置来解决。打开终端并输入locale命令将为用户提供用于系统本地化解释的语言标准列表,如下所示:

LANG=en_US.UTF-8
LANGUAGE=en_US
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=en_US.UTF-8
LC_TIME=de_DE.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=en_US.UTF-8
...

更改LC_CTYPE,LC_NUMERICLC_MEASUREMENT标签以en_US.UTF-8解决我这边的问题。这可以通过终端使用以下命令完成:

sudo update-locale LC_CTYPE=en_US.UTF-8
sudo update-locale LC_NUMERIC=en_US.UTF-8
sudo update-locale LC_MEASUREMENT=en_US.UTF-8

或者在您选择的文本编辑器中,/etc/default/locale使用 root 权限编辑文件。文件更新后,请确保重新启动以完成更改!

非常感谢@Scheff 对此事的见解。我怀疑如果没有他们的建议我会解决这个问题!非常感谢,哇!

于 2021-02-05T14:57:38.243 回答