Camera2:获取Depth16深度图并进行可视化转换

        camera2提供了获取Depth16深度图的api,不过并不是所有设备都支持获取深度图,可以通过以下的方式检测设备是否支持:


CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);

//遍历设备上的摄像头
for (String cameraId : manager.getCameraIdList()) {
    //获取每个摄像头的参数信息管理对象
    characteristics = manager.getCameraCharacteristics(cameraId);
    //获取摄像头参数信息
    int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
    //遍历参数信息
    for (int capability : capabilities) {
     if(capability ==CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT){
        //说明此摄像头支持获取深度图
        break;
       }
    }

    //判断是否支持同时输出深度图和jpeg主图,false:支持   true:不支持 
    boolean isExclusive = characteristics.get(CameraCharacteristics.DEPTH_DEPTH_IS_EXCLUSIVE);
    
}

通过上面的判断若设备支持获取深度图,我们可以通过一下方式拿到一张深度图:

ImageReader mImageReaderDepth = ImageReader.newInstance(480,640,ImageFormat.DEPTH16, 1);

mImageReaderDepth.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);

//会在此回调方法里返回图片信息
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {

        @Override
        public void onImageAvailable(ImageReader reader) {
            Image image = reader.acquireNextImage();
            switch (image.getFormat()) {
                case ImageFormat.JPEG:
                    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                    byte[] bytes = new byte[buffer.capacity()];
                    buffer.get(bytes);
                    Bitmap bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                    break;
                case ImageFormat.DEPTH_JPEG:

                    break;

                case ImageFormat.DEPTH16: 
                    //此image对象就包含了图片信息
                    Bitmap bitmapDepth = convertToRGBBitmap(image);
                    break;

                default:
                    break;
            }
            image.close();
        }
    };

到此,我们拿到了depth16格式的图片,通过查看官方文档ImageFormat.DEPTH16,我们能得知一下信息:

且深度值单位是:毫米。

        到此,我们根据官方文档提供的方法可以得到每个像素点的深度值和置信度值,但遗憾的是这种格式的Image对象并不能像ImageFormat.JPEG格式的Image对象能直接生成Bitmap位图,而对于此种格式如何进行可视化操作,官方文档中也没有提及,可能官方也没想到会有这种需求吧。幸运的是在调研如何获取深度图时,还有一种方案是使用ARCore的api获取,在查看文档时捕捉到一个关键信息:即ImageFormat.DEPTH16的深度信息值为0~8191mm

 ,后来发现8191是2进制13位的值,也就是文档中提到的16位数据中,高3位是置信度值,低13位是深度值。

既然如此深度值有了范围区间,我们就可以把深度值映射到rgb值,从而得到一张图片了,以下是转换操作:

private Bitmap convertToRGBBitmap(Image image) {
        //得到对应宽高 
        int width = image.getWidth();
        int height = image.getHeight();
        //读出所有深度信息,因为每个点的深度信息都是用16位表示的,所以用short[]接收
        ShortBuffer shortDepthBuffer = image.getPlanes()[0].getBuffer().asShortBuffer();
        short[] shorts = new short[shortDepthBuffer.capacity()];
        shortDepthBuffer.get(shorts);


        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        int res[] = new int[shorts.length];
        for (int i = 0; i < shorts.length; i++) {
            //根据官方文档,去低13位得到深度信息
            short depth = (short) (shorts[i] & 0x1FFF);
            if (depth == 0) { //若深度信息为0,直接赋值黑色色值(计算优化)
                res[i] = 0xFF000000;
            } else {
                //depth是上一步计算出的深度值,所以将深度值映射到颜色值的公式是:
                // int color = 深度值 ÷ 深度值区间上限(8191) x 255
                // int color = depth / 8191f * 255
                // 优化一 :浮点数运算开销大,优化为整数运算:int color = depth * 255 / 8191
                // 优化二:既然这样干脆直接使用位运算 depth * 255 = depth << 8     depth / 8191 = depth >> 13 
                int color = depth >> 5;
                //将 r、g、b通道设为相同的值(0~255),得到一张灰度图
                int grey = Color.argb(255, color, color, color);
                res[i] = grey;
            }
        }
        bitmap.setPixels(res, 0, width, 0, 0, width, height);
        return bitmap;
    }

最后附一张转换得到的深度图:

 

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 好的,这个问题是关于技术方面的,我可以帮您回答。您可以通过安装点云库,如PCL或Open3D,将深度图转换为点云数据。然后,您可以使用Python可视化库,如Matplotlib或Mayavi,对其进行可视化。在处理点云数据时,请确保您已经掌握了基本的点云操作和基本的Python编程知识。 ### 回答2: 要将Python中的深度图转换为点云图并进行可视化,可以使用一些库和工具。 首先,我们需要导入所需的库,包括OpenCV、NumPy和pyntcloud。使用OpenCV加载深度图像,然后使用NumPy将其转换为浮点数类型。 接下来,我们可以使用函数将深度图转换为点云。在此过程中,可以使用相机内部参数(如焦距和光心坐标)来校正点云。 可以将点云保存为Ply文件格式,然后使用pyntcloud库加载点云数据。使用pyntcloud的可视化函数可以将点云图像展示出来。 以下是一个示例代码: ```python import cv2 import numpy as np from pyntcloud import PyntCloud def depth_to_pointcloud(depth_map, fx, fy, cx, cy, scale=1.0): rows, cols = depth_map.shape u, v = np.meshgrid(np.arange(cols), np.arange(rows)) x = (u - cx) * depth_map / fx y = (v - cy) * depth_map / fy z = depth_map * scale points = np.stack((x, y, z), axis=-1) return points # 读取深度图depth_map = cv2.imread('depth_image.png', cv2.IMREAD_UNCHANGED).astype(float) / 1000.0 # 相机内参 fx = 500.0 fy = 500.0 cx = 320.0 cy = 240.0 # 深度图转换为点云 point_cloud = depth_to_pointcloud(depth_map, fx, fy, cx, cy) # 保存点云为Ply文件 PyntCloud.from_pandas(point_cloud).to_file('point_cloud.ply') # 加载点云数据 point_cloud_data = PyntCloud.from_file('point_cloud.ply') # 可视化点云 point_cloud_data.plot() ``` 在此示例中,我们假设深度图像是以png格式存储的,并且深度值以毫米为单位。请根据实际情况进行调整。 执行上述代码后,将会生成一个点云图,并通过pyntcloud库进行可视化展示。 ### 回答3: Python深度图转点云图并可视化的实例可以通过使用Python中的库进行实现。其中,可以使用NumPy库来处理图像数据,使用Matplotlib库来进行可视化。 首先,需要从文件中读取深度图像。可以使用OpenCV库来读取深度图像文件,并将其转换为灰度图像: ```python import cv2 depth_image = cv2.imread('depth_image.png', cv2.IMREAD_GRAYSCALE) ``` 接下来,可以使用NumPy库将深度图转换为点云数据。点云是由三维坐标组成的数据集。深度图像中的每个像素值表示了相应位置的点在相机坐标系下的深度。 ```python import numpy as np # 相机内参 focal_length = 500 # 相机焦距 center_x = 320 # 图像中心点的x坐标 center_y = 240 # 图像中心点的y坐标 # 获取深度图像的尺寸 height, width = depth_image.shape # 创建空的点云数据集 point_cloud = [] # 根据深度图像生成点云数据 for y in range(height): for x in range(width): # 获取深度值 depth = depth_image[y, x] # 转换成相机坐标系下的二维坐标 camera_x = (x - center_x) * depth / focal_length camera_y = (y - center_y) * depth / focal_length # 将相机坐标系下的二维坐标与深度值组成三维坐标,加入到点云数据集中 point_cloud.append([camera_x, camera_y, depth]) # 将点云数据集转换为NumPy数组 point_cloud = np.array(point_cloud) ``` 最后,可以使用Matplotlib库将点云数据可视化: ```python from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt # 创建三维图形对象 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # 绘制点云数据 ax.scatter(point_cloud[:, 0], point_cloud[:, 1], point_cloud[:, 2]) # 设置坐标轴标签 ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') # 显示图形 plt.show() ``` 通过上述步骤,可以将深度图转换为点云图,并使用Matplotlib库进行可视化

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值