【问题标题】:Color Image in the Google Tango Leibniz APIGoogle Tango Leibniz API 中的彩色图像
【发布时间】:2015-05-13 22:43:05
【问题描述】:

我正在尝试从 Google Tango 的 onFrameAvailable 方法中捕获图像数据。我正在使用 Leibniz 版本。在头文件中,据说缓冲区包含 HAL_PIXEL_FORMAT_YV12 像素数据。在release notes 他们说缓冲区包含 YUV420SP。但在documentation 中据说像素是RGBA8888 格式()。我有点困惑,另外。我并没有真正得到图像数据,而是很多洋红色和绿色。现在我正在尝试将 YUV 转换为 RGB,类似于 this one。我想步幅也有问题。这是 onFrameAvailable 方法的代码:

int size = (int)(buffer->width * buffer->height);
for (int i = 0; i < buffer->height; ++i)
{
   for (int j = 0; j < buffer->width; ++j)
   {
       float y = buffer->data[i * buffer->stride + j];
       float v = buffer->data[(i / 2) * (buffer->stride / 2) + (j / 2) + size];
       float u = buffer->data[(i / 2) * (buffer->stride  / 2) + (j / 2) + size + (size / 4)];

               const float Umax = 0.436f;
               const float Vmax = 0.615f;

               y = y / 255.0f;
               u =  (u / 255.0f - 0.5f) ;
               v =  (v / 255.0f - 0.5f) ;

               TangoData::GetInstance().color_buffer[3*(i*width+j)]=y;
               TangoData::GetInstance().color_buffer[3*(i*width+j)+1]=u;
               TangoData::GetInstance().color_buffer[3*(i*width+j)+2]=v;
   }
}

我正在片段着色器中进行 yuv 到 rgb 的转换。

有没有人获得过 Google Tango Leibniz 版本的 RGB 图像?或者在从 YUV 转换为 RGB 时遇到过类似的问题?

【问题讨论】:

    标签: android c camera yuv google-project-tango


    【解决方案1】:

    YUV420SP(又名 NV21)暂时是正确的。一个解释是here。在这种格式中,您有一个 width x height 数组,其中每个元素是一个 Y 字节,然后是一个 width/2 x height/2 数组,其中每个元素是一个 V 字节和一个 U 字节。您的代码正在实现 YV21,它为 V 和 U 提供了单独的数组,而不是将它们交错在一个数组中。

    您提到您正在片段着色器中进行 YUV 到 RGB 的转换。如果您只想绘制相机图像,那么您可以使用TangoService_connectTextureId()TangoService_updateTexture() 而不是TangoService_connectOnFrameAvailable()。这种方法已经在 OpenGL 纹理中向您提供相机图像,该纹理为您的片段着色器提供 RGB 值,而无需担心像素格式细节。你需要绑定到GL_TEXTURE_EXTERNAL_OES(而不是GL_TEXTURE_2D),你的片段着色器看起来像这样:

    #extension GL_OES_EGL_image_external : require
    
    precision mediump float;
    
    varying vec4 v_t;
    uniform samplerExternalOES colorTexture;
    
    void main() {
       gl_FragColor = texture2D(colorTexture, v_t.xy);
    }
    

    如果您出于某种原因确实想将 YUV 数据传递给片段着色器,则可以这样做,而无需将其预处理为浮点数。事实上,您根本不需要解压它——对于 NV21,只需为 Y 定义一个 1 字节纹理,为 VU 定义一个 2 字节纹理,然后按原样加载数据。您的片段着色器将为两者使用相同的纹理坐标。

    【讨论】:

    • 感谢您的回答。确定数据的格式真的很有帮助!我需要获取相机数据,我可能需要在片段着色器中处理它,甚至可能在此之前处理它。我现在尝试只处理灰色数据,但该输出也无法正常工作。我只需要读取缓冲区高度的前半部分来获取数据吗?还是宽度和高度实际上是 Y 数据,而缓冲区实际上更大?我创建了一个颜色缓冲区,因此我不使用纹理,因此着色器不使用纹理坐标。 (我需要为以后的任务这样做)。
    • widthheight 将以像素为单位的图像大小。 Y 在每个像素处进行采样,因此 datawidth x height 字节的 Y 开头(可能有填充取决于 stride)。
    • 比循环应该是正确的:) 很高兴知道!自 Leibniz 发布以来,我遇到了另一个问题。几帧后,相机似乎崩溃了,导致渲染出现问题(只是黑色像素):这是错误消息(第一个是 RAW 而不是 YUV):05-14 19:05:18.878 190-5445 /? E/camera-metadata:/home/ubuntu/jobs/redwood_internal/RedwoodInternal/Redwood/common/player-engine/src/camera-metadata.cc:56 YUV无法匹配帧1545.014677
    【解决方案2】:

    顺便说一句,如果有人在 Leibniz 版本中捕获图像数据时也遇到了问题:其中一位开发人员告诉我,相机存在一个错误,应该在 Nash 版本中修复。

    该错误导致我的缓冲区为空,但是当我使用 Nash 更新时,我再次获得了数据。但是,现在的问题是我使用的数据没有意义。我猜/希望原因是平板电脑尚未获得 OTA 更新(实际发布日期与 OTA 软件更新之间可能存在差距)。

    【讨论】:

      【解决方案3】:

      试试下面的代码:

      //C#    
      public bool YV12ToPhoto(byte[] data, int width, int height, out Texture2D photo)
              {
                  photo = new Texture2D(width, height);
      
                  int uv_buffer_offset = width * height;
      
                  for (int i = 0; i < height; i++)
                  {
                      for (int j = 0; j < width; j++)
                      {
                          int x_index = j;
                          if (j % 2 != 0)
                          {
                              x_index = j - 1;
                          }
      
                          // Get the YUV color for this pixel.
                          int yValue = data[(i * width) + j];
                          int uValue = data[uv_buffer_offset + ((i / 2) * width) + x_index + 1];
                          int vValue = data[uv_buffer_offset + ((i / 2) * width) + x_index];
      
                          // Convert the YUV value to RGB.
                          float r = yValue + (1.370705f * (vValue - 128));
                          float g = yValue - (0.689001f * (vValue - 128)) - (0.337633f * (uValue - 128));
                          float b = yValue + (1.732446f * (uValue - 128));
      
                          Color co = new Color();
                          co.b = b < 0 ? 0 : (b > 255 ? 1 : b / 255.0f);
                          co.g = g < 0 ? 0 : (g > 255 ? 1 : g / 255.0f);
                          co.r = r < 0 ? 0 : (r > 255 ? 1 : r / 255.0f);
                          co.a = 1.0f;
      
                          photo.SetPixel(width - j - 1, height - i - 1, co);
                      }
                  }
      
                  return true;
              }
      

      我成功了。

      【讨论】:

      • 欢迎来到 StackOverflow!请您添加描述以告诉操作员您的解决方案如何工作?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 1970-01-01
      • 2022-10-15
      • 2018-06-14
      相关资源
      最近更新 更多