OpenGL 中的相机镜头失真
Camera lens distortion in OpenGL
我正在尝试为我的 SLAM 项目模拟镜头畸变效果。
已在 OpenGL 中提供并加载了扫描的彩色 3D 点云。
我想要做的是以给定姿势渲染 2D 场景,并在鱼眼相机的真实图像和渲染图像之间进行一些视觉测距。
由于相机镜头畸变严重,在渲染阶段也要考虑。
问题是我不知道把镜头畸变放在哪里。着色器?
我发现 some open codes 将变形放入几何着色器中。但是我猜这个畸变模型与计算机视觉社区中的镜头畸变模型不同。在CV社区中,镜头畸变通常发生在投影平面上。
This one和我的作品很相似,但是他们没有使用失真模型。
有人有好主意吗?
我刚找到 another implementation。他们的代码在片段着色器和几何着色器中实现了失真。但是片段着色器版本可以应用于我的情况。因此,我猜下面的方法会起作用:
# vertex shader
p'=T.model x T.view x p
p_f = FisheyeProjection(p') // custom fish eye projection
镜头畸变通常会把直线变成曲线。当使用 OpenGL 光栅化线条和三角形时,无论您如何变换顶点,图元的边缘都保持笔直。
如果您的模型具有足够精细的曲面细分,那么将变形合并到顶点变换中是可行的。如果您只渲染点,它也适用。
然而,当您的目标是普遍适用性时,您必须以某种方式处理直边图元。一种方法是使用几何着色器进一步细分传入的模型;或者您可以使用曲面细分着色器。
另一种方法是渲染成立方体贴图,然后使用着色器为其创建等效的镜头。我实际上建议将其用于生成鱼眼图像。
畸变本身通常由 3 到 5 阶多项式表示,将光学中心轴的未畸变 angular 距离映射到畸变 angular 距离。
受 VR 社区的启发,我通过顶点位移实现了扭曲。
对于高分辨率,这在计算上更有效,但需要具有良好顶点密度的网格。您可能希望在扭曲图像之前应用曲面细分。
这里是实现OpenCV有理失真模型的代码(公式见https://docs.opencv.org/4.0.1/d9/d0c/group__calib3d.html):
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal_in;
layout (location = 2) in vec2 texture_coordinate_in;
uniform mat4 model_matrix;
uniform mat4 view_matrix;
uniform float dist_coeffs[8];
uniform mat4 projection_matrix;
uniform vec3 light_position;
out vec2 texture_coordinate;
out vec3 normal;
out vec3 light_direction;
// distort the real world vertices using the rational model
vec4 distort(vec4 view_pos)
{
// normalize
float z = view_pos[2];
float z_inv = 1 / z;
float x1 = view_pos[0] * z_inv;
float y1 = view_pos[1] * z_inv;
// precalculations
float x1_2 = x1*x1;
float y1_2 = y1*y1;
float x1_y1 = x1*y1;
float r2 = x1_2 + y1_2;
float r4 = r2*r2;
float r6 = r4*r2;
// rational distortion factor
float r_dist = (1 + dist_coeffs[0]*r2 +dist_coeffs[1]*r4 + dist_coeffs[4]*r6)
/ (1 + dist_coeffs[5]*r2 + dist_coeffs[6]*r4 + dist_coeffs[7]*r6);
// full (rational + tangential) distortion
float x2 = x1*r_dist + 2*dist_coeffs[2]*x1_y1 + dist_coeffs[3]*(r2 + 2*x1_2);
float y2 = y1*r_dist + 2*dist_coeffs[3]*x1_y1 + dist_coeffs[2]*(r2 + 2*y1_2);
// denormalize for projection (which is a linear operation)
return vec4(x2*z, y2*z, z, view_pos[3]);
}
void main()
{
vec4 local_pos = vec4(position, 1.0);
vec4 world_pos = model_matrix * local_pos;
vec4 view_pos = view_matrix * world_pos;
vec4 dist_pos = distort(view_pos);
gl_Position = projection_matrix * dist_pos;
// lighting on world coordinates not distorted ones
normal = mat3(transpose(inverse(model_matrix))) * normal_in;
light_direction = normalize(light_position - world_pos.xyz);
texture_coordinate = texture_coordinate_in;
}
重要的是要注意,畸变是在 z 归一化坐标中计算的,但在畸变的最后一行中被反归一化为视图坐标。这允许使用像 post 中的投影矩阵:http://ksimek.github.io/2013/06/03/calibrated_cameras_in_opengl/
编辑:对于任何有兴趣在上下文中查看代码的人,我已经在一个小 library the distortion shader is used in this example.
中发布了代码
我正在尝试为我的 SLAM 项目模拟镜头畸变效果。 已在 OpenGL 中提供并加载了扫描的彩色 3D 点云。 我想要做的是以给定姿势渲染 2D 场景,并在鱼眼相机的真实图像和渲染图像之间进行一些视觉测距。 由于相机镜头畸变严重,在渲染阶段也要考虑。
问题是我不知道把镜头畸变放在哪里。着色器?
我发现 some open codes 将变形放入几何着色器中。但是我猜这个畸变模型与计算机视觉社区中的镜头畸变模型不同。在CV社区中,镜头畸变通常发生在投影平面上。
This one和我的作品很相似,但是他们没有使用失真模型。
有人有好主意吗?
我刚找到 another implementation。他们的代码在片段着色器和几何着色器中实现了失真。但是片段着色器版本可以应用于我的情况。因此,我猜下面的方法会起作用:
# vertex shader
p'=T.model x T.view x p
p_f = FisheyeProjection(p') // custom fish eye projection
镜头畸变通常会把直线变成曲线。当使用 OpenGL 光栅化线条和三角形时,无论您如何变换顶点,图元的边缘都保持笔直。
如果您的模型具有足够精细的曲面细分,那么将变形合并到顶点变换中是可行的。如果您只渲染点,它也适用。
然而,当您的目标是普遍适用性时,您必须以某种方式处理直边图元。一种方法是使用几何着色器进一步细分传入的模型;或者您可以使用曲面细分着色器。
另一种方法是渲染成立方体贴图,然后使用着色器为其创建等效的镜头。我实际上建议将其用于生成鱼眼图像。
畸变本身通常由 3 到 5 阶多项式表示,将光学中心轴的未畸变 angular 距离映射到畸变 angular 距离。
受 VR 社区的启发,我通过顶点位移实现了扭曲。 对于高分辨率,这在计算上更有效,但需要具有良好顶点密度的网格。您可能希望在扭曲图像之前应用曲面细分。
这里是实现OpenCV有理失真模型的代码(公式见https://docs.opencv.org/4.0.1/d9/d0c/group__calib3d.html):
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal_in;
layout (location = 2) in vec2 texture_coordinate_in;
uniform mat4 model_matrix;
uniform mat4 view_matrix;
uniform float dist_coeffs[8];
uniform mat4 projection_matrix;
uniform vec3 light_position;
out vec2 texture_coordinate;
out vec3 normal;
out vec3 light_direction;
// distort the real world vertices using the rational model
vec4 distort(vec4 view_pos)
{
// normalize
float z = view_pos[2];
float z_inv = 1 / z;
float x1 = view_pos[0] * z_inv;
float y1 = view_pos[1] * z_inv;
// precalculations
float x1_2 = x1*x1;
float y1_2 = y1*y1;
float x1_y1 = x1*y1;
float r2 = x1_2 + y1_2;
float r4 = r2*r2;
float r6 = r4*r2;
// rational distortion factor
float r_dist = (1 + dist_coeffs[0]*r2 +dist_coeffs[1]*r4 + dist_coeffs[4]*r6)
/ (1 + dist_coeffs[5]*r2 + dist_coeffs[6]*r4 + dist_coeffs[7]*r6);
// full (rational + tangential) distortion
float x2 = x1*r_dist + 2*dist_coeffs[2]*x1_y1 + dist_coeffs[3]*(r2 + 2*x1_2);
float y2 = y1*r_dist + 2*dist_coeffs[3]*x1_y1 + dist_coeffs[2]*(r2 + 2*y1_2);
// denormalize for projection (which is a linear operation)
return vec4(x2*z, y2*z, z, view_pos[3]);
}
void main()
{
vec4 local_pos = vec4(position, 1.0);
vec4 world_pos = model_matrix * local_pos;
vec4 view_pos = view_matrix * world_pos;
vec4 dist_pos = distort(view_pos);
gl_Position = projection_matrix * dist_pos;
// lighting on world coordinates not distorted ones
normal = mat3(transpose(inverse(model_matrix))) * normal_in;
light_direction = normalize(light_position - world_pos.xyz);
texture_coordinate = texture_coordinate_in;
}
重要的是要注意,畸变是在 z 归一化坐标中计算的,但在畸变的最后一行中被反归一化为视图坐标。这允许使用像 post 中的投影矩阵:http://ksimek.github.io/2013/06/03/calibrated_cameras_in_opengl/
编辑:对于任何有兴趣在上下文中查看代码的人,我已经在一个小 library the distortion shader is used in this example.
中发布了代码