在Unity中获取颜色数据

时间:2014-11-26 22:21:49

标签: google-project-tango

release notes提到在Unity中无法访问颜色数据,但我相信您可以将回调附加到视频覆盖侦听器并在Unity中接收YUV12字节数组并手动将其转换为RGB565在屏幕上显示,可能使用着色器。

有没有人在Unity中成功访问和显示颜色数据(例如在AR覆盖中)?如果是这样,你可以分享一些关于如何开始的指针/代码吗?

4 个答案:

答案 0 :(得分:3)

视频叠加回调适用于Unity。从理论上讲,你可以使用YUV到RGBA着色器并在Unity中渲染它。这样做的唯一缺点是,由于Unity纹理/颜色格式的方式,它将需要多个“memcpy”。

Tango的YV12数据打包在C-API标题中解释:https://developers.google.com/project-tango/apis/c/struct_tango_image_buffer

它说:“首先是宽度x高度的Y样本,然后是V样本,其中一半是步幅,一半是Y数据的行,然后是U样本,其尺寸与V样本相同。” / p>

所以我认为你可以有三个Unity纹理,每个包含一个Y,U,V通道,并将它们传递到一个着色器来计算RGBA颜色。

有关YUV图像和转换的更多信息:http://en.wikipedia.org/wiki/YUV

答案 1 :(得分:3)

我使用以下脚本在Unity四维网格上显示视频叠加。适用于探戈平板电脑。但是fps很低,我猜是因为彩色相机的分辨率(1280 x 720)。

using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;
using System.Runtime.InteropServices;
using Tango;

public class CameraBackgorund : VideoOverlayListener
{
    Texture2D backgroundTexture = null;

    // texture data
    bool    isDirty = false;
    byte[]  yuv12   = null;
    int     width;
    int     height;

    private void Update() 
    {
        if (isDirty)
        {
            if (backgroundTexture == null)
                backgroundTexture = new Texture2D (width, height);

            // convert from YV12 to RGB
            int size = (int)(width * height);
            for (int i = 0; i < height; ++i)
            {
                for (int j = 0; j < width; ++j)
                {      
                    byte y = yuv12[i * width + j];
                    byte v = yuv12[(i / 2) * (width / 2) + (j / 2) + size];
                    byte u = yuv12[(i / 2) * (width / 2) + (j / 2) + size + (size / 4)];
                    backgroundTexture.SetPixel(j, height - i - 1, YUV2Color(y, u, v));
                }
            }

            // update texture
            backgroundTexture.Apply(true);
            GetComponent<MeshRenderer> ().material.mainTexture = backgroundTexture;

            isDirty = false;
        }
    }

    protected override void _OnImageAvailable(IntPtr callbackContext,
                                              Tango.TangoEnums.TangoCameraId cameraId, 
                                              Tango.TangoImageBuffer imageBuffer)
    {
        if (cameraId != Tango.TangoEnums.TangoCameraId.TANGO_CAMERA_COLOR)
            return;

        // allocate for the first time
        width = (int)imageBuffer.width;
        height = (int)imageBuffer.height;
        if (yuv12 == null)
            yuv12 = new byte[width * height * 2];

        // copy data in yv12 format
        IntPtr dataPtr = imageBuffer.data;
        int    offset  = 0;
        Int64  stride  = (Int64)imageBuffer.stride;
        for (int i = 0; i < height; ++i, dataPtr = new IntPtr(dataPtr.ToInt64() + stride), offset += width)
            Marshal.Copy(dataPtr, yuv12, offset, width);
        for (int i = 0; i < height / 2; ++i, dataPtr = new IntPtr(dataPtr.ToInt64() + stride / 2), offset += width / 2)
            Marshal.Copy(dataPtr, yuv12, offset, width / 2);
        for (int i = 0; i < height / 2; ++i, dataPtr = new IntPtr(dataPtr.ToInt64() + stride / 2), offset += width / 2)
            Marshal.Copy(dataPtr, yuv12, offset, width / 2);
        isDirty = true;
    }

    public static Color YUV2Color(byte y, byte u, byte v)
    {
        // http://en.wikipedia.org/wiki/YUV
        const float Umax = 0.436f;
        const float Vmax = 0.615f;

        float y_scaled = y / 255.0f;
        float u_scaled = 2 * (u / 255.0f - 0.5f) * Umax;
        float v_scaled = 2 * (v / 255.0f - 0.5f) * Vmax; 

        return new Color(y_scaled + 1.13983f * v_scaled,
                         y_scaled - 0.39465f * u_scaled - 0.58060f * v_scaled,
                         y_scaled + 2.03211f * u_scaled);
    }
}

使用Unity WebCamTexture成功检索颜色,但会破坏深度提供程序。

答案 2 :(得分:0)

您可以使用WebCamTexture.GetPixel获取点位置的颜色,并使用该信息制作纹理。 http://docs.unity3d.com/ScriptReference/WebCamTexture.GetPixel.html

答案 3 :(得分:0)

您可以使用以下代码将YV12转换为2D纹理

private void YV12_To_Texture2D(byte[] data, uint width, uint height, out Texture2D tex)
{
    tex = new Texture2D((int)width, (int)height);

    uint size = 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[size + ((i / 2) * width) + x_index + 1];
            int vValue = data[size + ((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;

            tex.SetPixel((int)width - j - 1, (int)height - i - 1, co);
        }
    }
}