在 emgu CV 中进行相机校准后如何访问旋转和平移矢量?

How do I access the rotation and translation vectors after camera calibration in emgu CV?

相机标定的目标是找到内部和外部参数:

  1. 内在的是描述相机本身的那些(焦点 长度、失真等)我得到了这些值,没问题。
  2. 外部参数基本上是相机的位置。当我尝试访问那些时,我得到一个 AccessViolationException.

执行此类校准的一种方法是

  1. 拍摄具有已知角的校准目标的图像
  2. 找到图像中的那些角
  3. 从3D点和2D点的对应关系中,找出一个变换成另一个的矩阵
  4. 该矩阵由内部参数和外部参数组成。

对 calibration function 的调用如下所示:

Mat[] rotationVectors = new Mat[1];
Mat[] translationVectors = new Mat[1];

double error = CvInvoke.CalibrateCamera(realCorners,
                                        detectedCorners,
                                        calibrationImages[0].Image.Size,
                                        cameraMatrix,
                                        distortionCoefficients,
                                        0,
                                        new MCvTermCriteria(30, 0.1),
                                        out rotationVectors,
                                        out translationVectors);

Console.WriteLine(rotationVectors[0].Size); // AccessViolationException

为什么我在 rotationVectorstranslationVectors 上得到 AccessViolationException

我下了断点,发现内部Data属性是null。查看 VS 调试器的屏幕截图:

这就是为什么我无法访问它的原因。但是为什么是null呢?

这是因为 EmguCV 中的错误。您正在呼叫

public static double CalibrateCamera(
   MCvPoint3D32f[][] objectPoints,
   PointF[][] imagePoints,
   Size imageSize,
   IInputOutputArray cameraMatrix,
   IInputOutputArray distortionCoeffs,
   CvEnum.CalibType calibrationType,
   MCvTermCriteria termCriteria,
   out Mat[] rotationVectors,
   out Mat[] translationVectors)

在此方法中调用了

public static double CalibrateCamera(
   IInputArray objectPoints,
   IInputArray imagePoints,
   Size imageSize,
   IInputOutputArray cameraMatrix,
   IInputOutputArray distortionCoeffs,
   IOutputArray rotationVectors,
   IOutputArray translationVectors,
   CvEnum.CalibType flags,
   MCvTermCriteria termCriteria)

IOutputArray rotationVectors 应复制到 Mat[] rotationVectors。在 translationVectors 的情况下也是如此。问题出在 this 循环中。

for (int i = 0; i < imageCount; i++)
{
   rotationVectors[i] = new Mat();
   using (Mat matR = rotationVectors[i]) // <- bug
      matR.CopyTo(rotationVectors[i]);
   translationVectors[i] = new Mat();
   using (Mat matT = translationVectors[i]) // <- bug
      matT.CopyTo(translationVectors[i]);                
}

而且应该有

for (int i = 0; i < imageCount; i++)
{
   rotationVectors[i] = new Mat();
   using (Mat matR = rVecs[i]) 
      matR.CopyTo(rotationVectors[i]);
   translationVectors[i] = new Mat();
   using (Mat matT = tVecs[i]) 
      matT.CopyTo(translationVectors[i]);                
}

最后要获得旋转和平移值,您可以使用 DataPointer

复制数据
var rotation = new Matrix<float>(rotationVectors[0].Rows, rotationVectors[0].Cols, rotationVectors[0].DataPointer);