华为AREngine根据深度图获取深度信息

我们知道华为AREngine可以根据接口acquireDepthImage()获取得到深度图,获取得到的深度图是DEPTH16格式的,AREngine中又没有给出例子怎样根据深度图求得深度信息,吐槽一下文档不够详细。

 

Image

acquireDepthImage()

在camera状态为tracking状态下,获取当前帧对应的深度图像,返回图像格式为DEPTH16,只能在下一次ARSession.update()前使用。

DEPTH16格式是Android dense depth image format.

每个像素是16位,代表深度摄像机或类似传感器的深度范围测量。16位样本由置信度值和实际测距测量组成。

置信度值是对样本正确性的估计。它编码在样本的3个最高有效位中,值0表示100%置信度,值1表示0%置信度,值2表示1/7,值3表示2/7,依此类推。

当由照相机拍摄时,射程的单位是毫米。

例如,以下示例从DEPTH16格式图像的第一个像素中提取范围和置信度,并将置信度转换为介于0和1.f之间的浮点值,其中1.f表示最大置信度:

    ShortBuffer shortDepthBuffer = img.getPlanes()[0].getBuffer().asShortBuffer();
    short depthSample = shortDepthBuffer.get()
    short depthRange = (short) (depthSample & 0x1FFF);
    short depthConfidence = (short) ((depthSample >> 13) & 0x7);
    float depthPercentage = depthConfidence == 0 ? 1.f : (depthConfidence - 1) / 7.f;
 

好了,我们已经知道DEPTH16格式的含义,那我们怎样在opengl中以纹理的方式在片元着色器里面求得相机坐标下的深度呢?

1、创建纹理ID,并且纹理可以传入无符号整型,这一定要注意GL_TEXTURE_MIN_FILTER与GL_TEXTURE_MAG_FILTER一定不要使用GL_NEAREST,否则整型数字传入不到纹理。

    public void createOnGlThread() {
        int[] textureId = new int[1];
        glGenTextures(1, textureId, 0);
        depthTextureId = textureId[0];
        glBindTexture(GL_TEXTURE_2D, depthTextureId);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        //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_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    }

2、每次更新纹理,因为我们获取的是16位的,所以glTexImage2D第三个参数使用GL_R16UI, 第7个参数使用GL_RED_INTEGER,第8个参数使用GL_UNSIGNED_SHORT,参数不要使用错,否则很容易纹理写入不了数据。

    public void update(final ARFrame frame) {
        try {
            Image depthImage = frame.acquireDepthImage();
            depthTextureWidth = depthImage.getWidth();
            depthTextureHeight = depthImage.getHeight();
//            String msg = String.format("width: %s, height: %s", depthTextureWidth, depthTextureHeight);
//            Log.d("render", msg);
            glBindTexture(GL_TEXTURE_2D, depthTextureId);
            glTexImage2D(
                    GL_TEXTURE_2D,
                    0,
                    GL_R16UI,
                    depthTextureWidth,
                    depthTextureHeight,
                    0,
                    GL_RED_INTEGER,
                    GL_UNSIGNED_SHORT,
                    depthImage.getPlanes()[0].getBuffer().asShortBuffer());
            depthImage.close();

        } catch (Exception e) {
            Log.d(TAG, "XXXXXXXXXXXX" + e);
            // This normally means that depth data is not available yet.
        }
    }

3、数据传入到纹理中了,看看shader中怎样处理纹理,获取相机坐标下的深度,单位是毫米。这一定注意,我们使用usampler2D类型接收纹理。

precision highp usampler2D;
layout (binding=2) uniform usampler2D bgDepthTexture;

float GetBgDepthMillimeters(in vec2 depth_uv) {
  uvec3 rawDepth = texture(bgDepthTexture, depth_uv).xyz;
  int depthRange = int(rawDepth.r) & 0x1FFF;
  int depthConfidence = ((int(rawDepth.r) >> 13) & 0x7);
  float depthPercentage = depthConfidence == 0 ? 1.0 : float(depthConfidence - 1) / 7.0;
  float depth = depthPercentage > 0.1 ? float(depthRange) : FAR * 1000.0;
  depth = max(depth, NEAR * 1000.0);
  depth = min(depth, FAR * 1000.0);
  return depth;
}

这样就获得了相机坐标下的深度信息。

 

参考文档:

https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/frame-0000001050121447-V5

https://developer.android.com/reference/android/graphics/ImageFormat#DEPTH16

https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XR风云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值