Bun*_*ing 2 opengl shader gpu glsl distortion
所以我有一台带广角镜头的相机.我知道失真系数,焦距,光学中心.我想要反映我从这台相机获得的图像.我第一次尝试使用OpenCV(cv :: undistort),效果很好,但速度太慢了.
现在我想在gpu上做这个.有一个着色器正是在http://willsteptoe.com/post/67401705548/ar-rift-aligning-tracking-and-video-spaces-part-5中记录了这一点.
公式可以在这里看到:http: //en.wikipedia.org/wiki/Distortion_%28optics%29#Software_correction
所以我去实现了我自己的版本作为glsl着色器.我发送一个四边形纹理坐标在0..1之间的角落.我假设到达的纹理坐标是未失真图像的坐标.我计算与我的纹理坐标对应的扭曲点的坐标.然后我对失真的图像纹理进行采样.
使用此着色器在最终图像中没有任何变化.我通过cpu实现确定的问题是,系数项非常接近于零.通过半径平方等数字变得越来越小.所以我有一个缩放问题 - 我无法弄明白该做什么不同!我尝试了所有的东西......我想这是非常明显的事情,因为这种过程似乎适用于很多人.
为简单起见,我省略了切向失真校正.
#version 330 core
in vec2 UV;
out vec4 color;
uniform sampler2D textureSampler;
void main()
{
vec2 focalLength = vec2(438.568f, 437.699f);
vec2 opticalCenter = vec2(667.724f, 500.059f);
vec4 distortionCoefficients = vec4(-0.035109f, -0.002393f, 0.000335f, -0.000449f);
const vec2 imageSize = vec2(1280.f, 960.f);
vec2 opticalCenterUV = opticalCenter / imageSize;
vec2 shiftedUVCoordinates = (UV - opticalCenterUV);
vec2 lensCoordinates = shiftedUVCoordinates / focalLength;
float radiusSquared = sqrt(dot(lensCoordinates, lensCoordinates));
float radiusQuadrupled = radiusSquared * radiusSquared;
float coefficientTerm = distortionCoefficients.x * radiusSquared + distortionCoefficients.y * radiusQuadrupled;
vec2 distortedUV = ((lensCoordinates + lensCoordinates * (coefficientTerm))) * focalLength;
vec2 resultUV = (distortedUV + opticalCenterUV);
color = texture2D(textureSampler, resultUV);
}
Run Code Online (Sandbox Code Playgroud)
我看到你的解决方案有两个问题.主要问题是你混合了两个不同的空间.您似乎通过将光学中心转换为该空间来在[0,1]纹理空间中工作,但您没有进行调整focalLenght.关键点在于,对于这种失真模型,焦距是以像素为单位确定的.然而,现在的像素不为1个基本单位宽了,但1/width与1/height分别单位.
您可以添加vec2 focalLengthUV = focalLength / imageSize,但在计算时,您会看到两个分区将相互抵消lensCoordinates.将纹理空间UV坐标转换为像素坐标并直接使用该空间更方便:
vec2 lensCoordinates = (UV * imageSize - opticalCenter) / focalLenght;
Run Code Online (Sandbox Code Playgroud)
(也分别改变用于计算distortedUV和resultUV).
到目前为止我所描述的方法仍然存在一个问题:我之前提到的像素空间的约定.在GL,原点将左下角,而在大多数像素的空间,原产地是在顶部左侧.在进行转换时,您可能必须翻转y坐标.另一件事是确切的像素中心位于何处.到目前为止,代码假设像素中心为整数+ 0.5.纹理坐标(0,0)不是左下像素的中心,而是角点.用于失真的参数可能(我不知道OpenCV的约定)假设像素以整数为中心,因此pixelSpace = uv * imageSize您可能需要将此偏移半个像素,而不是转换pixelSpace = uv * imageSize - vec2(0.5).
我看到的第二个问题是
float radiusSquared = sqrt(dot(lensCoordinates, lensCoordinates));
Run Code Online (Sandbox Code Playgroud)
这sqrt在这里是不正确的,因为dot(a,a)已经给出了矢量的平方长度a.