【问题标题】:distortion correction with gpu shader bug使用 gpu 着色器错误进行失真校正
【发布时间】:2014-11-10 08:40:13
【问题描述】:

所以我有一台带广角镜头的相机。我知道畸变系数、焦距、光学中心。我想不扭曲从这台相机获得的图像。我第一次尝试使用 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);
}

【问题讨论】:

  • 以下是 WebGL 中的一些类似工作:github.com/jywarren/fisheyegl 但我们看到非方形图像出现错误,如果有人能做到,我们真的可以使用一些帮助:stackoverflow.com/questions/45110817/…
  • 你真的需要在着色器中计算 UV 贴图吗?由于失真是恒定的,因此您只需执行一次。在开始渲染之前,可以使用 OpenCV 在 CPU 上简单地计算 UV 贴图。

标签: opengl glsl shader gpu distortion


【解决方案1】:

我发现您的解决方案存在两个问题。主要问题是你混合了两个不同的空间。您似乎通过将光学中心转换为该空间来在 [0,1] 纹理空间中工作,但您没有调整 focalLenght。关键是对于这样的畸变模型,焦距是以像素为单位确定的。但是,现在像素不再是 1 个基本单位宽,而是分别为 1/width 和 1/height 单位。

您可以添加vec2 focalLengthUV = focalLength / imageSize,但是当您计算lensCoordinates 时,您会看到两个除法会相互抵消。将纹理空间 UV 坐标转换为像素坐标并直接使用该空间要方便得多:

vec2 lensCoordinates = (UV * imageSize - opticalCenter) / focalLenght;

(还分别更改distortedUV和resultUV的计算)。

到目前为止,我所勾画的方法仍然存在一个问题:我之前提到的像素空间的约定。在 GL 中,原点位于左下角,而在大多数像素空间中,原点位于 top 左侧。在进行转换时,您可能需要翻转 y 坐标。另一件事是像素中心的确切位置。到目前为止,代码假定像素中心为整数 + 0.5。纹理坐标(0,0)不是左下像素的中心,而是角点。您用于失真的参数可能(我不知道 OpenCV 的约定)假定像素中心为整数,因此您可能需要将其偏移一半而不是转换 pixelSpace = uv * imageSize像pixelSpace = uv * imageSize - vec2(0.5) 这样的像素。

我看到的第二个问题是

float radiusSquared = sqrt(dot(lensCoordinates, lensCoordinates));

sqrt 在这里不正确,因为dot(a,a) 已经给出向量a 的平方长度。

【讨论】:

  • 您好,感谢您的回答!所以它是显而易见的:) 现在着色器的工作就像一个魅力。并且感谢您发现 sqrt 错误 - 我一路上添加了它......隧道视觉是一件很糟糕的事情。很有帮助的答案!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-04
  • 1970-01-01
  • 1970-01-01
  • 2013-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多