我正在按照教程对相机进行标定,我已经了解了用棋盘来求相机的内参数和畸变系数的整个过程,但我不明白的是,为什么在那之后我们还要叫getOptimalNewCameraMatrix
?特别是alpha
参数,我已经看过文档了,但可能是因为缺乏相机标定的知识,我真的不明白。
这是原始图像。x1c 0d1x
下面是上述图像的未失真图像的示例(使用OpenCV的undistort
)。
对于这一个,我只是直接使用获得的固有相机和失真系数来消除图像失真。
对于这一个,我在恢复扭曲之前用alpha=0
(左)和alpha=1
(右)调用getOptimalNewCameraMatrix
。
从我所看到的,getOptimalNewCameraMatrix
是保留原始图像而不丢失信息?我希望有人能解释这个函数真正的作用。
如果我想用来自这台相机的图片构建一个3D模型,我应该首先调用getOptimalNewCameraMatrix
吗?
- 谢谢-谢谢
4条答案
按热度按时间a14dhokn1#
我也有同样的问题。我在网上搜索找不到明确的直接答案,但在运行了一些测试后,我知道X1 M0 N1 X函数实际上为用户做了什么。
我使用了openCV calibration tutorial中提到的相同图像(您可以在here中找到名为left01.jpg到left14.jpg的图像(实际上left10.jpg似乎丢失了,但这很好))校准步骤后-假设正方形大小为30毫米-在教程中,我得到了这个相机矩阵:
另一方面,使用命令
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))
获得的新摄像机矩阵为注意这里的
alpha=1
,但它可能是[0,1]之间的另一个值。使用另一个值将给予不同的newcameramtx
。到目前为止没有什么新的。然后,我“未扭曲”所有使用的图像在校准和保存到两个新的文件夹。一个文件夹(让我们称之为第一文件夹)直接使用获得的固有相机填充无失真图像(即
mtx
)和失真系数(dist
),另一个(我们称之为第2个文件夹)填充了使用newcameramtx
和相同失真系数的未失真图像(dist
)。为了明确起见,我分别使用了命令cv2.undistort(img, mtx, dist, None, mtx)
和cv2.undistort(img, mtx, dist, None, newcameramtx)
,并将结果图像保存到上述两个文件夹中。在保存之前,我没有使用roi
裁剪未失真的图像。结果图像就像您在问题中找到并给出的一样。然后,使用第一个文件夹中的未失真图像,我重新执行校准过程,并找到以下相机矩阵:
第一次
对第2个文件夹进行相同操作,得到以下摄像机矩阵:
第一个
现在,请注意
mtx
、mtx_1stFolder
和newcameramtx_1stFolder
之间的距离,同样,请注意newcameramtx
、mtx_2ndFolder
和newcameramtx_2ndFolder
之间的距离。基于这些观察,我的想法是,直接使用获得的相机固有系数和失真系数对图像进行去失真处理不会影响相机矩阵,并且它会相应地返回相同大小的图像,但这些结果图像会丢失一些像素。如果你对丢失的像素没有意见,你可以完全不使用
cv2.getOptimalNewCameraMatrix
。但是,如果你需要丢失像素中给出的信息,您也可以选择将您的图像反扭曲为相同的图像大小或您想要的任何大小。但是,肯定会破坏你的相机矩阵,你将需要一个新的校准后,新的未失真的图像。cv2.getOptimalNewCameraMatrix
函数可以估计新的摄像机矩阵,而无需重新校准。这解释了为什么newcameramtx
和mtx_2ndFolder
彼此非常接近。这似乎也解释了为什么
mtx_2ndFolder
和newcameramtx_2ndFolder
彼此接近,因为没有太多的东西可以去扭曲(mtx_1stFolder
和newcameramtx_1stFolder
也是如此)。到目前为止,我还没有提到每个校准过程的失真系数(
dist
)。这实际上使我不能说我的想法是肯定的,所以我完全可以对我的想法进行修正。直观地说,我希望第一次校准会有一些失真系数,因为图像明显失真。正如预期的那样,失真系数矢量如下:另一方面,我希望对未失真图像进行校准会给予更少的系数,理想情况下为0,因为所有失真都被理想地去除了。然而,对第一个文件夹进行校准会给出:
第二个文件夹上的校准给出:
对于前三项,结果与期望值一样,在幅度上向零变小,但它们并没有急剧接近0。同样,对于最后两项,系数增加,这与我的期望相反。如果有人知道为什么会出现这种情况,我将非常感谢。
xdnvmnnf2#
如果您想得到与原始图像形状相同的图像,则必须丢失一些像素。
opencv文档中的“alpha”参数描述指出...
自由缩放参数,介于0(未失真图像中的所有像素均有效时)和1(未失真图像中保留所有源图像像素时)之间
对我来说,这意味着如果值为0,所有的像素都将进行几何变换,径向和切向失真将被消除,但图像的几何形状将不正确。
getOptimalNewCameraMatrix
用于使用来自具有相同校准的相同相机的不同分辨率。当我使用
getOptimalNewCameraMatrix
,然后对返回的感兴趣区域应用裁剪时,我得到了最佳结果。下面是我用于此目的的python代码片段。
这应该采取你的最后一个图像(针垫一个在右边),并给予你最有用的图像。
我还将
undistort
方法分为两部分,因为只要从摄像头接收到的新图像具有相同的分辨率,就可以继续调用remap
nsc4cvqm3#
ff29svar4#
正如您自己已经正确认识到的,原则上不需要调用getOptimalNewCameraMatrix函数。但是,使用此函数有一些优点:
1.α = 1。当调用α = 1时,失真图像的所有原始区域也包含在校正图像中。新的摄像机矩阵以这样的方式确定,即失真图像的角点Map到校正图像的角点。这是函数的设计标准。但是,使用alpha = 1有一个缺点,即校正后的图像还包含无效区域,在您的示例中这些区域被着色为黑色。如果您不想使用这些区域,您可以使用函数返回的ROI值。
另请参阅https://answers.ros.org/question/392890/why-the-left-3x3-portion-of-projection-matrixp-is-different-from-the-intrinsic-camera-matrixk/