[译]径向镜片反畸变滤波
操作系统:Windows8.1
显卡:Nivida GTX965M
开发工具:Unity2017.2.0f3
原文出处 : Radial lens undistortion filtering
在处理涉及广角相机的计算机视觉任务时可能发生畸变,这种畸变是由于镜头中心处的放大倍数大于在边缘处的放大倍数造成的桶形畸变,英文称之为 barrel distortion 。
Zhang, 1999 证明了具有两个系数的多项式径向畸变模型可以模拟为如下公式:
我们也可以考虑一个更简单的近似这个模型的径向畸变 Fitzgibbon, 2001
其中 ru 和 rd 分别是非畸变和畸变后的图像中心距离。α 是每一个镜片固有的常量系数。
为了实际实现这样的近似模型,需要图像中的点的原始坐标与归一化的 [-1; +1] [-1; +1] 坐标系中的坐标进行映射。
(xn,yn) 代表归一化后的坐标系,w 和 h 代表宽和高,变换后的公式为:
Implementing with OpenGL shaders
给定一个简单的带纹理的四边形映射到一个径向畸变的图像,滤波的功能可以有效的在片段着色器中执行。
precision mediump float; uniform sampler2D texture_diffuse; uniform vec2 image_dimensions; uniform float alphax; uniform float alphay; varying vec4 pass_Color; varying vec2 pass_TextureCoord; void main(void) { // Normalize the u,v coordinates in the range [-1;+1] float x = (2.0 * pass_TextureCoord.x - 1.0) / 1.0; float y = (2.0 * pass_TextureCoord.y - 1.0) / 1.0; // Calculate l2 norm float r = x*x + y*y; // Calculate the deflated or inflated new coordinate (reverse transform) float x3 = x / (1.0 - alphax * r); float y3 = y / (1.0 - alphay * r); float x2 = x / (1.0 - alphax * (x3 * x3 + y3 * y3)); float y2 = y / (1.0 - alphay * (x3 * x3 + y3 * y3)); // Forward transform // float x2 = x * (1.0 - alphax * r); // float y2 = y * (1.0 - alphay * r); // De-normalize to the original range float i2 = (x2 + 1.0) * 1.0 / 2.0; float j2 = (y2 + 1.0) * 1.0 / 2.0; if(i2 >= 0.0 && i2 <= 1.0 && j2 >= 0.0 && j2 <= 1.0) gl_FragColor = texture2D(texture_diffuse, vec2(i2, j2)); else gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); }
考虑目前基于U3D的项目比较多,同样提供一份基于Unity Shader编写的Shader。
Shader "Heitao/VR/Distortion" { Properties { _MainTex ("Texture", 2D) = "white" {} _AlphaScaleX ("Alpha scale x", Range(0.0, 0.25)) = 0.0 _AlphaScaleY ("Alpha scale y", Range(0.0, 0.25)) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float _AlphaScaleX; float _AlphaScaleY; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { float x = (2.0 * i.uv.x - 1.0) / 1.0f; float y = (2.0 * i.uv.y - 1.0) / 1.0f; float r = x * x + y * y; float x3 = x / (1.0 - _AlphaScaleX * r); float y3 = y / (1.0 - _AlphaScaleY * r); float x2 = x / (1.0 - _AlphaScaleX * (x3 * x3 + y3 * y3)); float y2 = y / (1.0 - _AlphaScaleY * (x3 * x3 + y3 * y3)); // Forward transform // float x2 = x * (1.0 - _AlphaScaleX * r); // float y2 = y * (1.0 - _AlphaScaleY * r); float i2 = (x2 + 1.0) * 1.0 / 2.0; float j2 = (y2 + 1.0) * 1.0 / 2.0; fixed4 col = fixed4(0.0, 0.0, 0.0, 1.0); if (i2 >= 0.0 && i2 <= 1.0 && j2 >= 0.0 && j2 <= 1.0) { col = tex2D(_MainTex, fixed2(i2, j2)); } return col; } ENDCG } } }
在 AlphaScaleX 和 AlphaScaleY 为 0 的时候:
调整畸变系数 AlphaScaleX = AlphaScaleY = 0.25 后:
通过调整参数观测畸变与反畸变的转换关系。
References
Zhang Z. (1999). Flexible camera calibration by viewing a plane from unknown orientation
Andrew W. Fitzgibbon (2001). Simultaneous linear estimation of multiple view geometry and lens distortion