摄像机成像、畸变模型(一)

本文详细介绍了摄像机成像模型、畸变原理及其校正方法。包括坐标系转换、投影矩阵、畸变参数等内容,并通过实例展示了如何使用Matlab进行畸变校正。

一 摄像机成像模型

成像的过程实质上是几个坐标系的转换。首先空间中的一点由世界坐标系转换到摄像机坐标系,然后再将其投影到成像平面(摄像机的CCD),最后再将成像平面上的数据转换到图像平面(最后生成的图像)。


  图1-1

世界空间内的一个点在图像上成像的过程称为投影成像过程,这中间转换过程构成的矩阵M称为投影矩阵


摄像机的畸变参数与相机成像时采用的分辨率无关,而fx,fy和光心位置cx,cy与分辨率有关,但是成倍数关系,例如在分辨率320×240分辨率标定得到内参数为fx0,fy0,cx0,cy0,那么在分辨率640×480下对应的参数则为2fx0,2fy0,2cx0,2cy0。


上面这些参数中,f,t所采用的量纲都是mm,而dx和dy指的是每个像素个数的大小,即mm/pixel,那么经过换算最后得到的u、v的量纲自然也就是像素。fx和fy是由f/dx,f/dy计算而来,表示的是长度值为f时对应的像素个数,也即长度值为f(mm)时,在图像平面的x方向和y方向的像素个数,fx、fy、u0、v0构成A,A右边的数据为[R|t]M’,看起来[R|t]M’对应的数据的量纲好像是mm,因为M’和t的量纲都是mm,这样A里面的量纲又为像素,这样乘起来的量纲就是mm*pixel了,这显然不对。但是事实情况并不是真的这样,最后[R|t]M’与A相乘的时候,[R|t]M’的结果是需要进行归一化的,即[xc yc zc 1] →[xc/zc yc/zc 1],这个时候它的量纲其实就只是倍数了。整个过程如下图


图 1-2


opencv标定出来的内参数矩阵一般为(分辨率为640×480)

<Camera_Matrix type_id="opencv-matrix">

 <rows>3</rows>

 <cols>3</cols>

 <dt>d</dt>

 <data>

   5.3193633829444082e+002 0. 3.1950000000000000e+002 0.

   5.3193633829444082e+002 2.3950000000000000e+002 0. 0. 1.</data></Camera_Matrix>


这里的fx≈531.9,fy≈531.9,u0=319.5,v0=239.5。u0和v0比较好理解,差不多就是图像的中心,但是这里的fx和fy为500多还是有点抽象,虽然前面已经说了表示焦距长度对应的像素个数。根据上图中u和v的计算公式,还有标定的内参矩阵值,其实可以反推出x’、y’的大致大小,这里u的最大值是640,v的最大值为480,用这些值可以算出x’和y’的最大值分别为0.6025和0.4521,它们分别代表经过Z值归一化后的比例值,这个值实质上反映了相机的视角


二 成像畸变

在没有畸变的情况下,理想的成像的过程是如图1-2所示


但是在实际的情况中,真正的镜头通常有一些形变,主要的变形为径向形变,也会有轻微的切向形变。所以上面的模型需要扩展为


                                       图2-1

k1和k2是径向形变系数,p1和p2是切向形变系数。OpenCV中没有考虑高阶系数。形变系数跟拍摄的场景无关,因此它们是内参数,而且与拍摄图像的分辨率无关。参见opencv中文wiki


opencv计算得到的畸变参数形式为:

<Distortion_Coefficients type_id="opencv-matrix">

 <rows>5</rows>

 <cols>1</cols>

 <dt>d</dt>

 <data>

   6.7442695842244271e-002 2.4180872220967919e-001 0. 0.

   -3.3970575589699975e-001</data></Distortion_Coefficients>

对应存放的畸变参数为[k1,k2,p1,p2[,k3[,k4,k5,k6]]


三 畸变校正

根据前面的说明,可以知道摄像机拍下来的图片是存在畸变的,现在需要根据内参矩阵和畸变参数对存在畸变的图像进行校正。校正的过程就是就是图2-1描述的过程。


首先是根据拍摄得到的存在畸变图像的坐标,计算出根据畸变模型得到的校正图像对应的坐标,这样就建立了畸变图像坐标和校正图像坐标之间的映射关系。同时计算出来的校正坐标存在小数,所以就需要对其插值。

例如XYsrc(1,1)<-->XYrect(1.5,1.0),那么假如采用简单的线性插值的话,Irect(1.5,1.0)=[Isrc(1,1)+Isrc(2,1)]*0.5

Irect就是算出来的校正后的像素值。


进行畸变的matlab校正代码(参见stackoverflow)如下:

[cpp]  view plain copy
  1. clear;  
  2. clc;  
  3. A =[5.9418398977142772e+002 0 3.1950000000000000e+002;  
  4.     0    5.941839897714e+002 2.3950000000000000e+002;  
  5.     0 0 1];  
  6. D = [6.7442695842244271e-002 2.4180872220967919e-001 0 0 -3.3970575589699975e-001];  
  7. fx = A(1,1);  
  8. fy = A(2,2);  
  9. cx = A(1,3);  
  10. cy = A(2,3);  
  11. k1 = D(1);  
  12. k2 = D(2);  
  13. k3 = D(5);  
  14. p1 = D(3);  
  15. p2 = D(4);  
  16.   
  17. K = A;  
  18. Idistorted = imread('logi.jpg');  
  19. Idistorted = rgb2gray(Idistorted);  
  20. Idistorted = im2double(Idistorted);  
  21. I = zeros(size(Idistorted));  
  22. [i j] = find(~isnan(I));  
  23.   
  24. % Xp = the xyz vals of points on the z plane  
  25. Xp = inv(K)*[j i ones(length(i),1)]';  
  26.   
  27. % Now we calculate how those points distort i.e forward map them through the distortion  
  28. r2 = Xp(1,:).^2+Xp(2,:).^2;  
  29. x = Xp(1,:);  
  30. y = Xp(2,:);  
  31.   
  32. x = x.*(1+k1*r2 + k2*r2.^2) + 2*p1.*x.*y + p2*(r2 + 2*x.^2);  
  33. y = y.*(1+k1*r2 + k2*r2.^2) + 2*p2.*x.*y + p1*(r2 + 2*y.^2);  
  34.   
  35. % u and v are now the distorted cooridnates  
  36. u = reshape(fx*x + cx,size(I));  
  37. v = reshape(fy*y + cy,size(I));  
  38.   
  39. % Now we perform a backward mapping in order to undistort the warped image coordinates  
  40. I = interp2(Idistorted, u, v);  
  41. subplot(121); imagesc(Idistorted);  
  42. subplot(122); imagesc(I);  



得到的结果图为:


转自:http://blog.youkuaiyun.com/kfqcome/article/details/9411711

### OpenCV 中畸变校正的原理 #### 畸变模型 OpenCV 校准中的失真校正基于对相机固有参数的估计,特别是镜头失真系数。OpenCV 使用数学模型来描述相机镜头引起的失真效果,主要包括径向和切向失真[^1]。 对于不同的镜头类型,如标准摄像头(cv)和鱼眼镜头(fisheye),其畸变模型存在差异,因此畸变系数也会有所不同,在实际应用中使用的公式也不尽相同。具体细节可参照 OpenCV 官方文档版本 2.0 和 3.0 的说明[^2]。 #### 实现方法 在 OpenCV 中实现畸变校正主要有两种方式: - **`undistort()` 函数** 这是个便捷的方法,它内部集成了 `initUndistortRectifyMap()` 和 `remap()` 函数的功能,用于矫正输入图像并返回已修正的结果。此过程简化了编程流程,使得开发者无需手动处理映射表创建与重映射操作。 - **`initUndistortRectifyMap()` 结合 `remap()`** 此种做法提供了更灵活的操作选项。先通过调用 `initUndistortRectifyMap()` 来计算新的投影关系,并生成两个映射数组;随后利用这两个数组作为参数传递给 `remap()` 函数完成最终的图像变形调整工作。这种方式允许用户自定义更多的参数设置,适用于复杂场景下的精确控制需求。 ```cpp // C++ 示例代码展示如何使用 initUndistortRectifyMap() 和 remap() #include <opencv2/opencv.hpp> using namespace cv; Mat cameraMatrix, distCoeffs; Mat map1, map2; Size imageSize(Size(640, 480)); // 初始化无畸变映射 void InitUndistortMaps(){ Mat R = getIdentity(); initUndistortRectifyMap(cameraMatrix, distCoeffs, R, cameraMatrix, imageSize, CV_32FC1, map1, map2); } // 应用映射到图片上 void ApplyRemap(Mat& srcImg, Mat& dstImg){ remap(srcImg, dstImg, map1, map2, INTER_LINEAR); } ``` #### 像素损失现象解释 经过畸变校正之后,图像确实会出现定程度的有效像素丢失情况。这是因为原始带有桶形或其他形式畸变的区域被拉伸展平的过程中不可避免地引入了些空白区,这些部分无法填充有效的视觉数据而形成黑边或裁剪边缘的现象[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值