RGBD(realsense, kinect等) 相机 储存深度图(depth_map)视频流(即uint16视频)

如果你使用的是realsense相机可以参见我封装好的代码: python RealSense相机 二次封装工具包_tycoer的博客-CSDN博客

问题: 最近在做 室内场景的三维重建, 需要同时储存深度图(depth_map)视频流和彩色图(color_img)的视频流, 即储存一系列连续的帧. realsense 提供了 .bag 文件格式用于记录视频流, 但该文件占用空间极大, 基本大概5~6秒的视频需要1G上下的硬盘空间(因为realsense在记录.bag文件时会同时记录多个视频流, 包含深度,彩色 , 左右emiter 的视频流, 当然也可以调api让其少记录几个视频流,但文件依旧很大), 故需要其他的一种文件格式来记录视频流以获得更小的储存空间:

方案如下(python 实现):

color_img.avi : 采用opencv 中的 cv2.VideoWriter直接以.avi格式录制, 以及cv2.VideoCapture(视频拆分) ;

depth_map.h5: 采用h5文件(由于depth_map采集出来的都是uint16的格式, 然而opencv不支持uint16的视频录制,仅支持uint8视频录制, 本人曾尝试多种编码例如'H265'的,但均不能正常录制, github上有一篇说是可以采取.oni格式, 但这个未尝试不置评): 很重要的一条是该depth_map需要使用cv2.imencode 进行编码, h5文件大小便会急剧下降, 代码:

#保存
import cv2
import h5py # 版本3.2.1

# 初始化 h5 文件 
h5=h5py.File('./depth_map.hdf5','w') #创建一个空的h5文件

# 初始化 avi文件
fourcc = cv2.VideoWriter_fourcc(*'XVID')
avi = cv2.VideoWriter('color_img.avi',fourcc, 30, (1280, 720),True)
# cv2.VideoWriter参数:
# 1-需保存视频的文件名
# 2-解码参数
# 3-fps帧率
# 4-分辨率
# 5-True为彩色视频, False为黑白视频

id = 0
while True:
    # 这里可能有一大段从相机api获取depth_map, color_img的代码
    # 例如:
    # depth_map, color_img = camera.get_frame() # camera.get_frame()是我瞎编的, 根据你自己        
    # 使用的相机api来写吧
    # depth_map, color_img 应为 numpy.ndarray
    # depth_map的典型shape为 (720, 1280) uint16, color_img的典型shape为 (720, 1280, 3) uint8
    # 把彩色图写入 avi
    avi.write(color_img)
    # 把深度图写入 h5
    res, depth_map_encode=cv2.imencode('.png',depth_map) # 编码depth_map 将depth_map 传入, res为bool, 用于判断是否编码成功
    # .png的原因: opencv 支持将16位图片写入.png, .jpg仅能写入8位图片
    h5[str(id)] = depth_map_encode # h5类似于字典, 即key 对应 data, 并且key不能重复
    id += 1
    
    '''
    一般会设置某个按键 让相机退出视频流并结束循环
    if 按键:
        break
    '''
h5.close() #关闭文件

将h5文件拆解成图片:

​
import os
import h5py # 版本3.2.1
import cv2
import numpy as np
def h52img(h5_path,save_dir='./'):
    # h5_path: h5文件路径
    # save_dir: 图片需要存入文件夹
    h5 = h5py.File(h5_path, 'r') 
    os.makedirs(save_dir,exist_ok=True)
    for key in h5.keys():
        img=cv2.imdecode(np.array(h5[key]),-1)  # 解码
        img_name = os.path.join(save_dir, key)  if key.endswith('.png') else os.path.join(save_dir, key +'.png' )# 判断文件名是否以 '.png' 结尾
        cv2.imwrite(img_name ,img)
    h5.close()

​

另外, 如果后续 使用opencv接口 cv2.imread读取 .png文件, 应设置flags = cv2.IMREAD_UNCHANGED 即 img = cv2.imread('xxx.png', flags = cv2.IMREAD_UNCHANGED), 才能正确的将 '.png' 文件读取为uint16格式单通道, 如果未设置flags = cv2.IMREAD_UNCHANGED 即 img=cv2.imread('xxx.png'), 将导致读取的'.png'文件为uint8三通道.

结果:

可以看到大约7秒的视频(二者分辨率均为1280x720, 帧率30fps), color_img.avi 大约仅有7M, depth_map.h5 大约仅有13.5M 

好的,您可以使用Python中的OpenCV库来读取彩色图像和深度图像。OpenCV还提供了一个函数cv2.remap,可以根据相机的内部参数和外部姿态对图像进行校正,这对于后续生成点云非常重要。 以下是一个基本的代码框架,您可以根据您的需求进行修改: ```python import cv2 import numpy as np # 读取彩色图像和深度图像 colorImage = cv2.imread('colorImage.png') depthImage = cv2.imread('depthImage.png', cv2.IMREAD_UNCHANGED) # 根据相机的内部参数和外部姿态对图像进行校正 R = np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]) T = np.array([0.0, 0.0, 0.0]) cameraMatrix = np.array([[fx, 0.0, cx], [0.0, fy, cy], [0.0, 0.0, 1.0]]) distCoeffs = np.zeros((5, 1)) map1, map2 = cv2.initUndistortRectifyMap(cameraMatrix, distCoeffs, R, cameraMatrix, (1920, 1080), cv2.CV_16SC2) rectifiedColorImage = cv2.remap(colorImage, map1, map2, cv2.INTER_LINEAR) rectifiedDepthImage = cv2.remap(depthImage, map1, map2, cv2.INTER_NEAREST) # 将深度图像转换为点云 fx = 527.88 fy = 526.11 cx = 312.99 cy = 241.31 depthScale = 1000.0 depthData = depthImage.astype(np.float32) / depthScale x, y = np.meshgrid(np.arange(depthData.shape[1]), np.arange(depthData.shape[0])) z = np.where(depthData > 0.0, depthData, np.nan) x = np.where(z > 0.0, (x - cx) * z / fx, np.nan) y = np.where(z > 0.0, (y - cy) * z / fy, np.nan) x = x.flatten() y = y.flatten() z = z.flatten() rgb = rectifiedColorImage.reshape((-1, 3)) xyzrgb = np.column_stack((x, y, z, rgb)) # 保存点云 np.savetxt('pointCloud.txt', xyzrgb, fmt='%.4f %.4f %.4f %d %d %d') ``` 您需要将代码中的“colorImage.png”和“depthImage.png”替换为您自己的彩色图像和深度图像。可以根据您的环境和相机参数来调整代码中的一些参数,例如相机的焦距、光心、图像分辨率等。 祝好运!
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值