当前位置:   article > 正文

【鱼眼镜头10】等距Equidistant模型的Kannala-Brandt模型,opencv的鱼眼标定使用的模型。kalibr中的 pinhole + equidistant 都是指该模型。_摄像头等距模型的逆向

摄像头等距模型的逆向

Kannala Brandt 模型 / opencv中的fisheye / kalibr中的 pinhole + equidistant 都是指该模型。

  • opencv
    • https://docs.opencv.org/4.x/db/d58/group__calib3d__fisheye.html
  • kalibr
    • https://github.com/ethz-asl/kalibr/wiki/supported-models

在之前的博客【鱼眼镜头1】鱼眼镜头的四种投影模型(指导镜头的设计),中央镜头综述,说明了投影模型的重要性:为了从全向相机捕获的图像中提取有用的信息,我们需要知道光线如何从三维空间映射到二维图像平面。这就是投影模型的作用。一个准确的投影模型可以帮助我们更准确地估计场景中物体的位置、姿态和其他属性。

常见的鱼眼相机基本成像模型主要有四种,它们分别是等距投影(最广泛)、等立体角投影、体视投影、正交投影。镜头的设计基本是按照上述四种投影模型而制作的,可看出鱼眼相机成像模型通用性较差。

为了解决模型通用性较差的问题,可以引入畸变模型,将鱼眼成像模型等价成理想针孔成像模型与畸变模型的叠加作用。

以上是之前对鱼眼相机的标定和投影模型的理解。鱼眼相机由于其超大的视场角(Field of View, FOV),其成像过程并不完全符合传统的针孔相机模型。因此,需要使用特定的投影模型来描述鱼眼相机的成像过程。

  1. Equidistant模型

    • Equidistant模型(等距投影模型)是一种常用的鱼眼相机投影模型。在这个模型中,图像半径rd与入射角Θ(光线与相机光轴的夹角)之间的关系是线性的,即rd = f * Θ,其中f是相机的焦距。这个模型假设在图像平面上,沿各个方向上的距离都是等比例缩放的。
  2. 鱼眼相机的实际设计

    • 对于实际的鱼眼镜头来说,由于制造和设计的限制,它们不可能完全精确地按照某个特定的投影模型来设计。因此,为了更准确地描述鱼眼相机的成像过程,需要使用更复杂的模型或近似方法。
  3. Kannala的鱼眼相机多项式近似模型

    • Kannala提出了一种鱼眼相机的一般多项式近似模型。这个模型使用多项式来近似描述图像半径rd与入射角Θ之间的关系。这种方法的优点是可以更灵活地适应不同鱼眼相机的成像特性,提高标定的准确性。
  4. 奇函数和泰勒级数展开
    在这里插入图片描述

    • 在讨论鱼眼相机的投影模型时,提到了 Θ d \Theta_d Θd Θ \Theta Θ的奇函数。这意味着当 Θ \Theta Θ取正值和负值时, Θ d \Theta_d Θd的绝对值相同但符号相反。这是因为鱼眼相机的成像过程在光轴的两侧是对称的。
    • 将投影模型按泰勒级数展开,可以发现 Θ d \Theta_d Θd可以用 Θ \Theta Θ的奇次多项式来表示。这是因为奇次多项式在原点附近是对称的,这与鱼眼相机的成像特性相符。

综上所述,使用Equidistant模型可以简化鱼眼相机的成像过程,但实际的鱼眼镜头可能无法完全遵循这个模型。为了更准确地描述鱼眼相机的成像过程,可以使用更复杂的模型或近似方法,如Kannala的多项式近似模型。同时,通过泰勒级数展开和奇函数性质的分析,可以更好地理解这些投影模型的特点和适用性。
在这里插入图片描述在这里插入图片描述

其中使用最多的是Equidistant模型, 即rd=f*\Theta,对实际的鱼眼镜头来说,它们不可能精确地按照投影模型来设计,所以为了方便鱼眼相机的标定,Kannala提出了一种鱼眼相机的一般多项式近似模型。通过前面的四个模型,可以发现\Thetad 是 \Theta的奇函数,而且将这些式子按泰勒级数展开,发现 可以用 的奇次多项式表示

opencv中的fisheye::calibrate就是用的该模型. 也叫作kannala-brandt模型.

3D到2D投影

在这里插入图片描述

class SVCCalibrationSDK:
    def __init__(self, intrinsic_param, width, height):
        self.image_size = np.array([height, width])  # rows, cols
        self.world2cam = np.array(intrinsic_param["world2cam"]).reshape(-1, 1)
        self.world2cam_len = np.array(intrinsic_param["world2cam_len"])
        self.svc_rotation = np.array([[1., intrinsic_param["affine_e"]],
                                     [intrinsic_param["affine_d"], intrinsic_param["affine_c"]]])
        self.svc_translation = np.array(intrinsic_param["center"])
 
    def cam_to_pixel(self, points):
        num_points = len(points)
 
        if num_points == 0:
            return np.empty((0, 3))
        else:
            norm = np.sqrt(np.sum(points[:, 0:2] * points[:, 0:2], axis=1, keepdims=True))
            theta = np.arctan(points[:, 2:3] * (-1 / norm))
 
            poly_theta = np.power(theta, np.arange(self.world2cam_len))
            rho = (poly_theta @ self.world2cam)
 
            pixels = (points[:, 0:2] * (rho / norm)) @ self.svc_rotation + self.svc_translation
 
        return pixels
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

2D到3D投影

在这里插入图片描述

参考

https://zhuanlan.zhihu.com/p/532501102

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/710577
推荐阅读
相关标签
  

闽ICP备14008679号