2012-01-31 365 views
1

我试图用GLSL着色器将YUV(YV12)转换为RGB。关于使用GLSL将YUV(YV12)转换为RGB

如下图所示。

  1. 读取图像文件原始YUV(YV12)数据
  2. 滤波Y,Cb和Cr从原始YUV(YV12)数据
  3. 映射纹理
  4. 发送片段着色器。

但结果图像与原始数据不一样。

下面的图像是原始数据。

screenshot of raw image link(Available for download)

和下方图像是转换数据。

screenshot of convert image link(Available for download)

以下是我的源代码。

- (void) readYUVFile  
{  
     ...  
     NSData* fileData = [NSData dataWithContentsOfFile:file];  
     NSInteger width = 720;  
     NSInteger height = 480;  
     NSInteger uv_width = width/2;  
     NSInteger uv_height = height/2;  
     NSInteger dataSize = [fileData length];  

     GLint nYsize = width * height;  
     GLint nUVsize = uv_width * uv_height;  
     GLint nCbOffSet = nYsize;  
     GLint nCrOffSet = nCbOffSet + nUVsize;  

     Byte* uData = spriteData + nCbOffSet;  
     Byte* vData = uData + nUVsize;  
     GLfloat imageY[ 345600 ], imageU[ 86400 ], imageV[ 86400 ];  

     int x, y, nIndexY = 0, nIndexUV = 0;  
     for(y = 0; y < height; y++)  
     {  
       for(x = 0; x < width; x++)  
       {  
          imageY[ nIndexY ] = (GLfloat)spriteData[ nIndexY ] - 16.0;  
          if((y < uv_height) && (x < uv_width))  
          {   
            imageU[ nIndexUV ] = (GLfloat)uData[ nIndexUV ] - 128.0;  
            imageV[ nIndexUV ] = (GLfloat)vData[ nIndexUV ] - 128.0;  
            nIndexUV++;  
          }  
          nIndexY++;  
       }  
     }  

     m_YpixelTexture = [self textureY:imageY widthType:width heightType:height];  
     m_UpixelTexture = [self textureU:imageU widthType:uv_width heightType:uv_height];  
     m_VpixelTexture = [self textureV:imageV widthType:uv_width heightType:uv_height];  

     ...  
} 


- (GLuint) textureY: (GLfloat*)imageData   
      widthType: (int) width  
     heightType: (int) height  
{   
    GLuint texName;  
    glActiveTexture(GL_TEXTURE0);  
    glGenTextures(1, &texName);  
    glBindTexture(GL_TEXTURE_2D, texName);  

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);  

    return texName;  
}  

- (GLuint) textureU: (GLfloat*)imageData   
      widthType: (int) width  
     heightType: (int) height  
{   
    GLuint texName;  
    glActiveTexture(GL_TEXTURE1);  
    glGenTextures(1, &texName);  
    glBindTexture(GL_TEXTURE_2D, texName);  

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);  

    return texName;  
}  

- (GLuint) textureV: (GLfloat*)imageData   
      widthType: (int) width  
     heightType: (int) height  
{   
    GLuint texName;  
    glActiveTexture(GL_TEXTURE2);  
    glGenTextures(1, &texName);  
    glBindTexture(GL_TEXTURE_2D, texName);  

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);  

    return texName;  
}  

以下是Fragment Shader的源代码。

uniform sampler2D Ytexture; // Y Texture Sampler  
uniform sampler2D Utexture; // U Texture Sampler  
uniform sampler2D Vtexture; // V Texture Sampler  
varying highp vec2 TexCoordOut;  

void main()  
{  
    highp float y, u, v; 
    highp float r, g, b; 

    y = texture2D(Ytexture, TexCoordOut).p; 
    u = texture2D(Utexture, TexCoordOut).p; 
    v = texture2D(Vtexture, TexCoordOut).p; 

    y = 1.1643 * (y - 0.0625); 
    u = u - 0.5; 
    v = v - 0.5; 

    r = y + 1.5958 * v; 
    g = y - 0.39173 * u - 0.81290 * v; 
    b = y + 2.017 * u; 

    gl_FragColor = highp vec4(r, g, b, 1.0); 
} 

Y数据是好的,但U和V数据是不好的。图像数据的y轴是反向输出。

如何解决此问题?

+0

第二个截图对我不起作用。有没有重新提供它的机会? – Tommy 2012-02-01 01:32:02

回答

1

由于坐标轴中存在简单的分歧,图像可能被镜像在水平面上 - OpenGL遵循方格纸惯例,其中(0,0)是左下角,y轴向上,而几乎所有图形图像格式遵循英语阅读顺序约定,其中(0,0)是左上角,y轴向下。只需翻转输入y坐标(如果需要,在顶点着色器中)。

至于颜色,第二个屏幕截图当前不适用于我(根据我的评论),但我最好的猜测是在构建imageU和imageV时减去128,然后在着色器中再次减去0.5 。据推测,你实际上只想做这一个或另一个(具体来说,因为纹理数据是无符号的,所以在着色器中做)?你用imageY犯了同样的错误,但最终的效果只是使图像变暗,而不是将所有的颜色转移到缩放比例的一半。

我唯一的想法是你的个人纹理只有一个通道,所以最好将它们上传为GL_LUMINANCE而不是GL_RGBA。