2012-01-31 363 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。