当前位置: 首页 > 知识库问答 >
问题:

当使用OpenGL ES从YUV-NV12转换为RGB时,颜色/色度纹理会被拉伸

仲孙献
2023-03-14

我有一个YUV-NV12格式化图像数据的字节缓冲区。当我试图将其转换为RGB时,我得到了一个像下面图像中一样具有拉伸颜色(色度)层的输出。

我遵循了这个伟大的答案,它引导我将YUV-NV21转换为RGB。由于NV-12只是带有翻转U和V数据的NV-21,所以我应该做的唯一更改是替换片段着色器中的UV值。

顶点着色器:

precision mediump float;
uniform mat4 uMVPMatrix;
attribute vec4 vPosition;
attribute vec4 vTextureCoordinate;
varying vec2 position;

void main()
{
   gl_Position = uMVPMatrix * vPosition;
   position = vTextureCoordinate.xy;
}

片段着色器:

precision mediump float;
varying vec2 position;
uniform sampler2D uTextureY;
uniform sampler2D uTextureUV;

void main() 
{
    float y, u, v;
    y = texture2D(uTextureY, position).r;
    u = texture2D(uTextureUV, position).a - 0.5;
    v = texture2D(uTextureUV, position).r - 0.5;

    float r, g, b;
    r = y + 1.13983 * v;
    g = y - 0.39465 * u - 0.58060 * v;
    b = y + 2.03211 * u;

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

将图像数据拆分并放入2个ByteBuffer,分别是mYBuffermUVBuffermSourceImage只是一个缓冲区,其中包含的图像数据为字节数据。

ByteBuffer bb = (ByteBuffer) mSourceImage;
if (bb == null) {
    return;
}
int size = mWidth * mHeight;

bb.position(0).limit(size);
mYBuffer = bb.slice();
bb.position(size).limit(bb.remaining());
mUVBuffer = bb.slice();

生成纹理:

GLES20.glGenTextures(2, mTexture, 0);

for(int i = 0; i < 2; i++) {
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture[i]);

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

将缓冲区数据传递到纹理:

mTextureYHandle = GLES20.glGetUniformLocation(mProgramId, "uTextureY");
mTextureUVHandle = GLES20.glGetUniformLocation(mProgramId, "uTextureUV");

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, mWidth, mHeight, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, mYBuffer);
GLES20.glUniform1i(mTextureYHandle, 0);

GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture[1]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE_ALPHA, mWidth / 2, mHeight / 2, 0, GLES20.GL_LUMINANCE_ALPHA, GLES20.GL_UNSIGNED_BYTE, mUVBuffer);
GLES20.glUniform1i(mTextureUVHandle, 1);

我不明白为什么我会得到这样的结果。任何帮助都将不胜感激。

共有1个答案

仲孙阳
2023-03-14

没关系,这是我代码中的一个小错误。

拆分字节缓冲区时,我已经使用了bb.position(size). limited(bb.remaining())作为UV缓冲区,由于某种原因,bb.remaining()在得到一些帧后变成了0(这实际上是相机预览),因此我已经将其更改为bb.position(size). limited(size size/2)

也是我通过阅读本文所做的假设,

我应该做的唯一更改是替换片段着色器中的u和v值

似乎是错误的。据观察,GL20.GL_LUMINANCE_ALPHA总是将U字节放入纹理的A组件中,将V字节放入R,G,B组件中(您可以使用任何一个)。因此,不需要在片段着色器中交换uv值(我已经用正确的片段着色器代码编辑了我的问题)。

我会保留这个问题,希望这对将来的人有所帮助。

 类似资料:
  • 我有一个返回十进制值的java代码,如下所示 第一个值表示红色的颜色代码,第二个值表示绿色的颜色代码,第三个值表示蓝色的颜色代码。 有没有什么方法可以将这些RGB值转换为java中相应的颜色?

  • 问题内容: 我想将颜色元组转换为颜色名称,例如“黄色”或“蓝色” python中有一种简单的方法可以做到这一点吗? 问题答案: 看起来webcolors将允许您执行以下操作: rgb_to_name(rgb_triplet,spec =’css3’) 将存在于rgb()颜色三元组中的3元整数转换为其对应的归一化颜色名称(如果存在);有效值为html4,css2,css21和css3,默认值为css

  • 我目前正在尝试开发一个Android上的视频播放器,但是在颜色格式上却很纠结。 上下文:我通过MediaExtractor/MediaCodec的标准组合来提取和解码视频。因为我需要提取的帧作为OpenGLES纹理(RGB)可用,所以我设置了解码器(MediaCodec),以便它通过SurfaceTexture提供外部GLES纹理(GL_TEXTURE_EXTERNAL_OES)。我知道我的HW解

  • 问题内容: 我在该主题上找到的所有内容都只是将十六进制转换为rgb,然后添加一个Alpha1。我也想从十六进制数字中获得所需的Alpha。 诸如或明显具有不为0或1的Alpha值的颜色。 问题答案: 我已经制作了一个快速的JSfiddle表格,可以将8位十六进制代码转换为CSS rgba值;) 基础很简单-将您提供的字符串分成两位数的一部分,并转换为alpha通道的百分比率和RGB通道的小数位。标

  • 这就是我所做的 这将返回一个字符串“0XFFhexcode”,我想将其转换为long,将其存储,然后将其用作颜色 我有以下错误

  • 更新2:XSSFWorkbook不提供对调色板的访问,因此我要问以下问题:访问XSSFWorkbook中的调色板