无人机实战系列(二)本地摄像头 + Depth-Anything V2

这篇文章介绍了如何在本地运行 Depth-Anything V2,因为我使用的无人机是Tello,其本身仅提供了一个单目视觉相机,在众多单目视觉转 Depth 的方案中我选择了 Depth-Anything V2,这个库的强大在于其基于深度学习模型将单目视觉以较低的代价转换成 RGBD 图像,可以用来无人机避障与SLAM。


Step1. 拉取 Depth-Anything V2 源码与模型下载

官方仓库 提供了两种方式调用Depth-Anything,这里先介绍第一种即直接源码调用,后面会补充他们说的第二种使用 HuggingFacetransformers 库的调用方式。

  • 直接clone仓库:
$ git clone git@github.com:DepthAnything/Depth-Anything-V2.git
  • 安装必要的库:
$ pip install -r requirements.txt
  • 下载官方提供的预训练模型:
    这里建议新建一个文件夹 checkpoints 用来保存模型,这样在运行示例的时候就不需要对源码进行修改:
$ cd Depth-Anything-V2
$ mkdir checkpoints

在官方仓库中的 README.md 文件的 Pre-trained Models 章节提供了三个预训练好的模型,我将其下载后统计了一下实际模型大小:

ModelParamsCheckpointSize
Depth-Anything-V2-Small24.8MDownload99.2 MB
Depth-Anything-V2-Base97.5MDownload390 MB
Depth-Anything-V2-Large335.3MDownload1.34 GB
Depth-Anything-V2-Giant1.3BComing soon

此时你的文件结构应该如下:

(LLM) ~/Desktop/Depth-Anything-V2 $ tree -L 2
.
├── DA-2K.md
├── LICENSE
├── README.md
├── app.py
├── assets
│   ...
├── depth_anything_v2
│   ...
├── metric_depth
│   ...
├── checkpoints    # 上一步创建的存放模型的文件夹
│   ├── depth_anything_v2_vitb.pth    	# 390 MB
│   ├── depth_anything_v2_vitl.pth		# 1.34 GB
│   └── depth_anything_v2_vits.pth		# 99.2 MB
├── requirements.txt
├── run.py
└── run_video.py

Step2. 【可选】准备示例图像与视频

为了能测试效果,我这里提供了一个自己拍摄的餐桌图像 dining-table.jpg与风景区视频 landsacpe.mp4 放在网盘上,这两个文件不涉及任何版权问题,可以随意下载。

链接: https://pan.baidu.com/s/1i3COEYRJgzsCSG4O3doekg?pwd=7dba 提取码: 7dba 

Step3. 运行单个图像示例

将测试数据下载好后就可以运行官方提供的示例 run.py ,这里假设使用的是我提供的图像 dining-table.jpg 并放在当前目录下:

此处还需要根据实际情况修改源码处的一个位置,大概在第19行,这里是让你选择用于计算的模型,其默认是使用最大的即效果最好的模型,如果你只下载了上面的一个模型就需要对下面的代码中的 default='vitl' 进行修改,修改依据就是下方代码中的 model_configs 内容:

parser.add_argument('--encoder', type=str, default='vitl', choices=['vits', 'vitb', 'vitl', 'vitg'])
...
model_configs = {
    'vits': {'encoder': 'vits', 'features': 64, 'out_channels': [48, 96, 192, 384]},
    'vitb': {'encoder': 'vitb', 'features': 128, 'out_channels': [96, 192, 384, 768]},
    'vitl': {'encoder': 'vitl', 'features': 256, 'out_channels': [256, 512, 1024, 1024]},
    'vitg': {'encoder': 'vitg', 'features': 384, 'out_channels': [1536, 1536, 1536, 1536]}
}

完成修改后就可以运行demo了,会在当前目录下生成一个 vis_depth 文件夹:

$ python run.py --img-path ./dining-table.jpg

在这里插入图片描述


Step4. 运行单个视频示例

与上一步运行单个图像示例一致,同样需要在第19行 处根据自己实际情况修改要加载的模型,然后执行命令:

$  python run_video.py --video-path ./landscape.mp4 

执行后会在当前路径下生成一个vis_video_depth文件夹:
在这里插入图片描述


Step5. 使用opencv调用本地摄像头

成功运行完上面两个demo后我在网盘中也提供了一个 python 脚本 local-camera.py 功能是使用opencv调用本地摄像头实时转换单目图像到深度图上:

【注意】:在我的 MacBook Pro M2 笔记本上运行后会非常卡顿并且有较大的延迟,处理一帧图像大概需要250ms左右,后续我会写一篇文章来展示如何将计算部署到远程GPU Server上并将计算结果回传到本地。

import argparse
import cv2
import matplotlib
import numpy as np
import torch
import time

from depth_anything_v2.dpt import DepthAnythingV2

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Depth Anything V2')
    
    parser.add_argument('--input-size', type=int, default=518)
    parser.add_argument('--encoder', type=str, default='vits', choices=['vits', 'vitb', 'vitl', 'vitg'])
    parser.add_argument('--pred-only', dest='pred_only', action='store_true', help='only display the prediction')
    parser.add_argument('--grayscale', dest='grayscale', action='store_true', help='do not apply colorful palette')
    
    args = parser.parse_args()
    
    DEVICE = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
    
    model_configs = {
        'vits': {'encoder': 'vits', 'features': 64, 'out_channels': [48, 96, 192, 384]},
        'vitb': {'encoder': 'vitb', 'features': 128, 'out_channels': [96, 192, 384, 768]},
        'vitl': {'encoder': 'vitl', 'features': 256, 'out_channels': [256, 512, 1024, 1024]},
        'vitg': {'encoder': 'vitg', 'features': 384, 'out_channels': [1536, 1536, 1536, 1536]}
    }
    
    depth_anything = DepthAnythingV2(**model_configs[args.encoder])
    depth_anything.load_state_dict(torch.load(f'./models/depth_anything_v2_{args.encoder}.pth', map_location='cpu'))
    depth_anything = depth_anything.to(DEVICE).eval()
    
    margin_width = 50
    cmap = matplotlib.colormaps.get_cmap('Spectral_r')
    
    cap = cv2.VideoCapture(0)
    
    if not cap.isOpened():
        print("Error: Could not open camera.")
        exit()
    print("Successed: Camera opened.")
    while True:
        ret, raw_frame = cap.read()
        if not ret:
            print("Error: Failed to capture image.")
            continue
        
        start_time = time.time()
        depth = depth_anything.infer_image(raw_frame, args.input_size)
        
        depth = (depth - depth.min()) / (depth.max() - depth.min()) * 255.0
        depth = depth.astype(np.uint8)
        print(f"Calculate cost time: {time.time() - start_time}")
        
        if args.grayscale:
            depth = np.repeat(depth[..., np.newaxis], 3, axis=-1)
        else:
            depth = (cmap(depth)[:, :, :3] * 255)[:, :, ::-1].astype(np.uint8)
        
        if args.pred_only:
            cv2.imshow('Depth Prediction', depth)
        else:
            split_region = np.ones((raw_frame.shape[0], margin_width, 3), dtype=np.uint8) * 255 # 分割线
            combined_frame = cv2.hconcat([raw_frame, split_region, depth])      # 将原始图像和深度图进行拼接
            cv2.imshow('Raw Frame and Depth Prediction', combined_frame)
            
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
            
        print(f"[{args.encoder}] Single frame cost time {time.time() - start_time}")
        print(f"    origin frame shape={raw_frame.shape}, processed shape={depth.shape}")
    
    cap.release()
    cv2.destroyAllWindows()

运行:

$ python local-camera.py

在这里插入图片描述


总体而言 Depth-Anything V2 在单目项目转深度方面效果是目前开源的几个方案中比较好且稳定的,特别是对于精度要求不高的情况下,虽然没有 RealSence 这种从硬件层面进行转换的快,但其最大的优势在于可以让Tello这种无人机在不进行任何改装的前提下就能够获取深度信息,这可以极大降低无人机单体的硬件成本,你需要的仅仅是一台能够运行模型的3060服务器,这个服务器在未来还可以肩负LLM Agent的功能。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值