【OPENCV源码阅读】鱼眼镜头标定

Opencv的鱼眼镜头模型

  • 空间中的三维点P,在世界坐标系下为X,在相机坐标系下坐标为 X c X_c Xc,R是旋转对阵。
    X c = R X + T Xc=RX+T Xc=RX+T

  • x,y,z是 X c X_c Xc的三个坐标值
    x = X c 1 x=X_{c1} x=Xc1
    y = X c 2 y=X_{c2} y=Xc2
    z = X c 3 z=X_{c3} z=Xc3

  • 三维点P在相机归一化平面上的投影p的坐标为(a,b)
    a = x / z a=x/z a=x/z and b = y / z b=y/z b=y/z

  • 其在镜头上的入射角θ为
    r 2 = a 2 + b 2 r^2=a^2+b^2 r2=a2+b2
    θ = a t a n ( r ) θ=atan(r) θ=atan(r)
    θ是入射角(入射光与光轴夹角),r是归一化平面上p到平面中心距离。

  • 鱼眼畸变模型,注意 θ d θ_d θd不是角度而是r畸变后的长度。
    r d = θ ( 1 + k 1 θ 2 + k 2 θ 4 + k 3 θ 6 + k 4 θ 8 ) r_d=θ(1+k_1θ_2+k_2θ_4+k_3θ_6+k_4θ_8) rd=θ(1+k1θ2+k2θ4+k3θ6+k4θ8)

  • 畸变点坐标 [x’; y’]为:
    x ′ = ( r d / r ) ⋅ a x′=(r_d/r)·a x=(rd/r)a
    y ′ = ( r d / r ) ⋅ b y′=(r_d/r)·b y=(rd/r)b

  • 最后乘焦距映射成像素坐标 [u; v]:
    u = f x ( x ′ + α y ′ ) + c x u=f_x(x′+αy′)+c_x u=fx(x+αy)+cx
    v = f y y ′ + c y v=f_yy′+c_y v=fyy+cy

去畸变(到小孔成像的变换)

图像去畸变

cv::fisheye::initUndistortRectifyMap (InputArray K, InputArray D, InputArray R, InputArray P, const cv::Size &size, int m1type, OutputArray map1, OutputArray map2)
用后向映射的方式,计算目的图像上每个点对应源图像的位置。

点去畸变

void cv::fisheye::undistortPoints (InputArray distorted, OutputArray undistorted, InputArray K, InputArray D, InputArray R=noArray(), InputArray P=noArray())

这个要用前向映射的方式,计算源图像上点在目的图像上的位置。这涉及一个问题,需要利用 r d r_d rd求解 θ d θ_d θd。Opencv使用的是最优化的方法,利用牛顿法求入射角:

目标函数: f ( θ ) = θ ( 1 + k 1 θ 2 + k 2 θ 4 + k 3 θ 6 + k 4 θ 8 ) − θ d = 0 f(θ)=θ(1+k_1θ_2+k_2θ_4+k_3θ_6+k_4θ_8)-θ_d=0 f(θ)=θ(1+k1θ2+k2θ4+k3θ6+k4θ8)θd=0
方向和步长为: − f ( θ ) / f ′ ( θ ) -f(θ)/f'(θ) f(θ)/f(θ)

这是Opencv的实现代码,最大迭代次数为10次。

            for (int j = 0; j < 10; j++)
            {
                double theta2 = theta*theta, theta4 = theta2*theta2, theta6 = theta4*theta2, theta8 = theta6*theta2;
                double k0_theta2 = k[0] * theta2, k1_theta4 = k[1] * theta4, k2_theta6 = k[2] * theta6, k3_theta8 = k[3] * theta8;
                /* new_theta = theta - theta_fix, theta_fix = f0(theta) / f0'(theta) */
                double theta_fix = (theta * (1 + k0_theta2 + k1_theta4 + k2_theta6 + k3_theta8) - theta_d) /
                                   (1 + 3*k0_theta2 + 5*k1_theta4 + 7*k2_theta6 + 9*k3_theta8);
                theta = theta - theta_fix;
                if (fabs(theta_fix) < EPS)
                    break;
            }

初始值如下,即取 θ = θ d θ=θ_d θ=θd

min(max(-CV_PI/2., theta_d), CV_PI/2.);
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

blanklog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值