如何使用OpenGL模拟OpenCV的warpPerspective功能(透视变换)

bad*_*nts 5 c++ android opencv opengl-es homography

我已经在 Python 和 C++ 中使用 OpenCV 完成了图像变形,在我选择的角落看到了变形的可口可乐标志:

最终图像

使用以下图像:

形象标识

和这个:

在此处输入图片说明

带有过渡图片和描述的完整专辑在这里

我需要这样做,但在 OpenGL 中。我会有:

  • 我必须在其中映射扭曲图像的角落

  • 一个单应矩阵,将徽标图像的变换映射到您在最终图像中看到的徽标图像(使用 OpenCV 的 warpPerspective),如下所示:

    [[  2.59952324e+00,   3.33170976e-01,  -2.17014066e+02],
    [  8.64133587e-01,   1.82580111e+00,  -3.20053715e+02],
    [  2.78910149e-03,   4.47911310e-05,   1.00000000e+00]]
    
    Run Code Online (Sandbox Code Playgroud)
  • 主图(这里是跑步轨迹图)

  • 叠加图像(此处为可口可乐图像)

是否可以 ?我已经阅读了很多并开始了 OpenGL 基础教程,但是可以从我所拥有的内容中完成吗?OpenGL 实现会更快吗,比如大约 10 毫秒?

我目前正在使用本教程:http : //ogldev.atspace.co.uk/www/tutorial12/tutorial12.html 我是否朝着正确的方向前进?这里是 OpenGL 新手,请多多包涵。谢谢。

Tim*_*Tim 5

在尝试了此处和其他地方提出的许多解决方案后,我通过编写一个复制“warpPerspective”功能的片段着色器来解决这个问题。

片段着色器代码如下所示:

varying highp vec2 textureCoordinate;

uniform sampler2D inputImageTexture;

// NOTE: you will need to pass the INVERSE of the homography matrix, as well as 
// the width and height of your image as uniforms!
uniform highp mat3 inverseHomographyMatrix;
uniform highp float width;
uniform highp float height;

void main()
{
   // Texture coordinates will run [0,1],[0,1];
   // Convert to "real world" coordinates
   highp vec3 frameCoordinate = vec3(textureCoordinate.x * width, textureCoordinate.y * height, 1.0);

   // Determine what 'z' is
   highp vec3 m = inverseHomographyMatrix[2] * frameCoordinate;
   highp float zed = 1.0 / (m.x + m.y + m.z);
   frameCoordinate = frameCoordinate * zed;

   // Determine translated x and y coordinates
   highp float xTrans = inverseHomographyMatrix[0][0] * frameCoordinate.x + inverseHomographyMatrix[0][1] * frameCoordinate.y + inverseHomographyMatrix[0][2] * frameCoordinate.z;
   highp float yTrans = inverseHomographyMatrix[1][0] * frameCoordinate.x + inverseHomographyMatrix[1][1] * frameCoordinate.y + inverseHomographyMatrix[1][2] * frameCoordinate.z;

   // Normalize back to [0,1],[0,1] space
   highp vec2 coords = vec2(xTrans / width, yTrans / height);

   // Sample the texture if we're mapping within the image, otherwise set color to black
   if (coords.x >= 0.0 && coords.x <= 1.0 && coords.y >= 0.0 && coords.y <= 1.0) {
       gl_FragColor = texture2D(inputImageTexture, coords);
   } else {
       gl_FragColor = vec4(0.0,0.0,0.0,0.0);
   }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我们在这里传递的单应矩阵是逆单应矩阵!您必须反转要传递到“warpPerspective”中的单应性矩阵 - 否则此代码将无法工作。

顶点着色器除了传递坐标之外什么也不做:

// Vertex shader
attribute vec4 position;
attribute vec4 inputTextureCoordinate;

varying vec2 textureCoordinate;

void main() {
   // Nothing happens in the vertex shader
   textureCoordinate = inputTextureCoordinate.xy;
   gl_Position = position;
}
Run Code Online (Sandbox Code Playgroud)

传入未改变的纹理坐标和位置坐标(即textureCoordinates = [(0,0),(0,1),(1,0),(1,1)]和positionCoords = [(-1,-1),( -1,1),(1,-1),(1,1)],对于三角形带),这应该可以!


use*_*906 0

您可以使用 来对纹理进行透视变形texture2DProj(),或者texture2D()通过除以st纹理的坐标来使用(这就是所做texture2DProj的)。

看看这里:OpenGL ES 2.0 中梯形的透视正确纹理

warpPerspective将 (x,y,1) 坐标投影到矩阵,然后除以(u,v)wtexture2DProj()。您必须修改矩阵,以便得到的坐标正确标准化。

在性能方面,如果你想将数据读回CPU,你的瓶颈是glReadPixels。需要多长时间取决于您的设备。如果您只是进行显示,假设您已将两个纹理加载到 GPU 内存,则 OpenGL ES 调用将花费不到 10 毫秒的时间。