单目深度估计模型 lite-mono 测试

news2025/7/15 21:17:19

lite-mono 使用工业数据集kitti 进行训练,目的使用单目摄像头实现物体深度预测,关于kitti数据集的介绍和下载参考


(二)一文带你了解KITTI数据集-CSDN博客文章浏览阅读2.7w次,点赞64次,收藏294次。文章介绍了KITTI数据集的起源、组成、传感器配置和数据结构,包括图像、点云、相机校准和物体标签的详细信息。此外,还阐述了数据预处理步骤、数据集的组织结构和文件解析,以及用于3D目标检测的评价指标。该数据集对于开发和评估自动驾驶场景中的计算机视觉算法至关重要。https://blog.csdn.net/m0_46556474/article/details/130944612

另一篇介绍lite-mono的帖子可以提前看看

CVPR‘2023 | Lite-Mono: 一种新的轻量级自监督单目深度估计方法_litemono内容-CSDN博客文章浏览阅读842次。本文提出了一种新的轻量级单目自监督单目深度估计方法。设计了一种混合的CNN和Transformer架构来建模多尺度增强的局部特征和全局上下文信息。在8个KITTI数据集上的实验结果证明了该方法的优越性。通过在提出的CDC块中设置优化的扩张率,并插入LGFI模块来获得局部-全局特征相关性,Lite-Mono可以感知不同尺度的物体,甚至是对靠近摄像机的移动物体。论文还验证了该模型在Make3D数据集上的泛化能力。此外,Lite-Mono在模型复杂性和推理速度之间实现了良好的权衡。_litemono内容https://blog.csdn.net/CVHub/article/details/130236211

本文主要尝试把模型转化为onnx,  再利用这个单眼深度估计模型Lite-Mono进行推理

权重的下载

wget -O weights/lite-mono_640x192.zip 'https://surfdrive.surf.nl/files/index.php/s/CUjiK221EFLyXDY/download'

wget -O weights/lite-mono-small_640x192.zip 'https://surfdrive.surf.nl/files/index.php/s/8cuZNH1CkNtQwxQ/download'

wget -O weights/lite-mono-tiny_640x192.zip 'https://surfdrive.surf.nl/files/index.php/s/TFDlF3wYQy0Nhmg/download'

wget -O weights/lite-mono-8m_640x192.zip 'https://surfdrive.surf.nl/files/index.php/s/UlkVBi1p99NFWWI/download'

wget -O weights/lite-mono_1024x320.zip 'https://surfdrive.surf.nl/files/index.php/s/IK3VtPj6b5FkVnl/download'

wget -O weights/lite-mono-small_1024x320.zip 'https://surfdrive.surf.nl/files/index.php/s/w8mvJMkB1dP15pu/download'

wget -O weights/lite-mono-tiny_1024x320.zip 'https://surfdrive.surf.nl/files/index.php/s/myxcplTciOkgu5w/download'

wget -O weights/lite-mono-8m_1024x320.zip 'https://surfdrive.surf.nl/files/index.php/s/mgonNFAvoEJmMas/download'

解压

unzip weights/lite-mono_640x192.zip -d weights
unzip weights/lite-mono-small_640x192.zip -d weights
unzip weights/lite-mono-tiny_640x192.zip -d weights
unzip weights/lite-mono-8m_640x192.zip -d weights

unzip weights/lite-mono_1024x320.zip -d weights
unzip weights/lite-mono-small_1024x320.zip -d weights
unzip weights/lite-mono-tiny_1024x320.zip -d weights
unzip weights/lite-mono-8m_1024x320.zip -d weights

Lite-Mono 模型加载

import os

import torch
from torchvision import transforms, datasets

import networks

def load_network(model='lite-mono', load_weights_folder=None, device='cuda'):
    device = torch.device('cuda')

    encoder_path = os.path.join(load_weights_folder, 'encoder.pth')
    decoder_path = os.path.join(load_weights_folder, 'depth.pth')

    encoder_dict = torch.load(encoder_path)
    decoder_dict = torch.load(decoder_path)

    feed_height = encoder_dict['height']
    feed_width = encoder_dict['width']
   
    encoder = networks.LiteMono(
        model=model,
        height=feed_height,
        width=feed_width,
    )

    model_dict = encoder.state_dict()
    encoder.load_state_dict(
        {k: v
        for k, v in encoder_dict.items() if k in model_dict})

    encoder.to(device)
    encoder.eval()

    depth_decoder = networks.DepthDecoder(encoder.num_ch_enc, scales=range(3))
    depth_model_dict = depth_decoder.state_dict()
    depth_decoder.load_state_dict(
        {k: v
        for k, v in decoder_dict.items() if k in depth_model_dict})

    depth_decoder.to(device)
    depth_decoder.eval()

    return encoder, depth_decoder

ONNX 模型变换方法

def convert_to_onnx(
    input_shape=(640, 192), 
    output_dir='',
    encoder=None, 
    decoder=None, 
    device='cpu',
):
    os.makedirs(output_dir, exist_ok=True)

    # encoder
    input_image = torch.randn(1, 3, input_shape[1], input_shape[0]).to(device)

    input_layer_names = ['input_image']
    output_layer_names = ['features']

    torch.onnx.export(
        encoder, 
        input_image,
        file_name + '/encoder.onnx', 
        verbose=True,
        input_names=input_layer_names,
        output_names=output_layer_names,
        do_constant_folding=False,
        opset_version=13,
    )
    
    # decoder
    encoder_results = encoder(input_image)

    features = []
    features.append(torch.randn(*list(encoder_results[0].shape)).to(device))
    features.append(torch.randn(*list(encoder_results[1].shape)).to(device))
    features.append(torch.randn(*list(encoder_results[2].shape)).to(device))

    input_layer_names = ['features_1', 'features_2', 'features_3']
    output_layer_names = ['depth']

    torch.onnx.export(
        decoder, 
        features,
        file_name + '/decoder.onnx', 
        verbose=True,
        input_names=input_layer_names,
        output_names=output_layer_names,
        do_constant_folding=False,
        opset_version=13,
    )

onnx格式变换

file_name = 'lite-mono_640x192'
input_shape = (640, 192)
model='lite-mono'

load_weights_folder = 'weights/' + file_name
encoder, decoder = load_network(model, load_weights_folder)

convert_to_onnx(
    input_shape=input_shape, 
    output_dir=file_name, 
    encoder=encoder, 
    decoder=decoder, 
    device='cuda:0',
)

file_name = 'lite-mono-small_640x192'
input_shape = (640, 192)
model='lite-mono-small'

load_weights_folder = 'weights/' + file_name
encoder, decoder = load_network(model, load_weights_folder)

convert_to_onnx(
    input_shape=input_shape, 
    output_dir=file_name, 
    encoder=encoder, 
    decoder=decoder, 
    device='cuda:0',
)

file_name = 'lite-mono-tiny_640x192'
input_shape = (640, 192)
model='lite-mono-tiny'

load_weights_folder = 'weights/' + file_name
encoder, decoder = load_network(model, load_weights_folder)

convert_to_onnx(
    input_shape=input_shape, 
    output_dir=file_name, 
    encoder=encoder, 
    decoder=decoder, 
    device='cuda:0',
)

file_name = 'lite-mono-8m_640x192'
input_shape = (640, 192)
model='lite-mono-8m'

load_weights_folder = 'weights/' + file_name
encoder, decoder = load_network(model, load_weights_folder)

convert_to_onnx(
    input_shape=input_shape, 
    output_dir=file_name, 
    encoder=encoder, 
    decoder=decoder, 
    device='cuda:0',
)

file_name = 'lite-mono_1024x320'
input_shape = (1024, 320)
model='lite-mono'

load_weights_folder = 'weights/' + file_name
encoder, decoder = load_network(model, load_weights_folder)

convert_to_onnx(
    input_shape=input_shape, 
    output_dir=file_name, 
    encoder=encoder, 
    decoder=decoder, 
    device='cuda:0',
)


file_name = 'lite-mono-small_1024x320'
input_shape = (1024, 320)
model='lite-mono-small'

load_weights_folder = 'weights/' + file_name
encoder, decoder = load_network(model, load_weights_folder)

convert_to_onnx(
    input_shape=input_shape, 
    output_dir=file_name, 
    encoder=encoder, 
    decoder=decoder, 
    device='cuda:0',
)


file_name = 'lite-mono-tiny_1024x320'
input_shape = (1024, 320)
model='lite-mono-tiny'

load_weights_folder = 'weights/' + file_name
encoder, decoder = load_network(model, load_weights_folder)

convert_to_onnx(
    input_shape=input_shape, 
    output_dir=file_name, 
    encoder=encoder, 
    decoder=decoder, 
    device='cuda:0',
)

file_name = 'lite-mono-8m_1024x320'
input_shape = (1024, 320)
model='lite-mono-8m'

load_weights_folder = 'weights/' + file_name
encoder, decoder = load_network(model, load_weights_folder)

convert_to_onnx(
    input_shape=input_shape, 
    output_dir=file_name, 
    encoder=encoder, 
    decoder=decoder, 
    device='cuda:0',
)

使用onnx进行推理

  • 视频捕获:首先初始化视频捕获设备。
  • 模型加载:加载编码器和解码器的 ONNX 模型。
  • 主循环:在无限循环中读取视频帧,进行推理,处理输出图像,直到按下 ESC 键。
  • 资源释放:在结束时释放视频捕获资源并关闭所有窗口。

需要以下库

os:用于文件和路径操作。
copy:用于深拷贝对象。
time:用于时间测量。
argparse:用于处理命令行参数。
cv2:OpenCV库,用于图像处理。
numpy:用于处理数组和矩阵。
onnxruntime:用于运行 ONNX 模型。

def run_inference(encoder, decoder, image):

  • 输入:编码器和解码器模型,以及输入图像。
  • 处理
    • 预处理:调整图像大小、颜色空间转换、转置和归一化。
    • 推理:将处理后的图像输入编码器和解码器,生成深度图。
    • 后处理:归一化深度图并转换为 uint8 格式。

def main():

  • 解析命令行参数:包括设备编号、视频文件路径和模型路径。
  • 视频捕获:使用 OpenCV 从指定设备或视频文件读取帧。
  • 加载模型:使用 ONNX Runtime 加载编码器和解码器模型。
  • 循环处理
    • 捕获视频帧,进行深度推理,并绘制调试信息。
    • 显示输入和输出图像。

def draw_debug(image, elapsed_time, depth_map):

  • 输入:原始图像、推理耗时和深度图。
  • 处理
    • 使用 cv.applyColorMap 为深度图应用色彩映射。
    • 在调试图像上显示推理耗时。

完整代码如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import copy
import time
import argparse

import cv2 as cv
import numpy as np
import onnxruntime


def run_inference(encoder, decoder, image):
    # ONNX Input Size
    input_size = encoder.get_inputs()[0].shape
    input_width = input_size[3]
    input_height = input_size[2]

    # Pre process:Resize, BGR->RGB, Transpose, float32 cast
    input_image = cv.resize(image, dsize=(input_width, input_height))
    input_image = cv.cvtColor(input_image, cv.COLOR_BGR2RGB)
    input_image = input_image.transpose(2, 0, 1)
    input_image = np.expand_dims(input_image, axis=0)
    input_image = input_image.astype('float32')
    input_image = input_image / 255.0

    # Inference
    input_name = encoder.get_inputs()[0].name
    features = encoder.run(None, {input_name: input_image})

    input_name_01 = decoder.get_inputs()[0].name
    input_name_02 = decoder.get_inputs()[1].name
    input_name_03 = decoder.get_inputs()[2].name
    depth_map = decoder.run(
        None,
        {
            input_name_01: features[0],
            input_name_02: features[1],
            input_name_03: features[2]
        },
    )

    # Post process
    depth_map = np.squeeze(depth_map[0])
    d_min = np.min(depth_map)
    d_max = np.max(depth_map)
    depth_map = (depth_map - d_min) / (d_max - d_min)
    depth_map = depth_map * 255.0
    depth_map = np.asarray(depth_map, dtype="uint8")

    return depth_map


def main():
    parser = argparse.ArgumentParser()

    parser.add_argument("--device", type=int, default=0)
    parser.add_argument("--movie", type=str, default=None)
    parser.add_argument(
        "--model",
        type=str,
        default='model/lite-mono-tiny_640x192',
    )

    args = parser.parse_args()
    model_dir = args.model
    encoder_path = os.path.join(model_dir, 'encoder.onnx')
    decoder_path = os.path.join(model_dir, 'decoder.onnx')

    # Initialize video capture
    cap_device = args.device
    if args.movie is not None:
        cap_device = args.movie
    cap = cv.VideoCapture(cap_device)

    # Load model
    encoder = onnxruntime.InferenceSession(
        encoder_path,
        providers=[
            'CUDAExecutionProvider',
            'CPUExecutionProvider',
        ],
    )
    decoder = onnxruntime.InferenceSession(
        decoder_path,
        providers=[
            'CUDAExecutionProvider',
            'CPUExecutionProvider',
        ],
    )

    while True:
        start_time = time.time()

        # Capture read
        ret, frame = cap.read()
        if not ret:
            break
        debug_image = copy.deepcopy(frame)

        # Inference execution
        depth_map = run_inference(
            encoder,
            decoder,
            frame,
        )

        elapsed_time = time.time() - start_time

        # Draw
        debug_image, depth_image = draw_debug(
            debug_image,
            elapsed_time,
            depth_map,
        )

        key = cv.waitKey(1)
        if key == 27:  # ESC
            break
        cv.imshow('Input', debug_image)
        cv.imshow('Output', depth_image)

    cap.release()
    cv.destroyAllWindows()


def draw_debug(image, elapsed_time, depth_map):
    image_width, image_height = image.shape[1], image.shape[0]
    debug_image = copy.deepcopy(image)

    # Apply ColorMap
    depth_image = cv.applyColorMap(depth_map, cv.COLORMAP_JET)
    depth_image = cv.resize(depth_image, dsize=(image_width, image_height))

    # Inference elapsed time
    cv.putText(debug_image,
               "Elapsed Time : " + '{:.1f}'.format(elapsed_time * 1000) + "ms",
               (10, 40), cv.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2,
               cv.LINE_AA)

    return debug_image, depth_image

window下启动测试main会有报错

cv2.error: OpenCV(4.10.0) D:\a\opencv-python\opencv-python\opencv\modules\highgui\src\window.cpp:1301: error: (-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Cocoa support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function 'cvShowImage'

解决方法参考

https://stackoverflow.com/questions/67120450/error-2unspecified-error-the-function-is-not-implemented-rebuild-the-libraicon-default.png?t=O83Ahttps://stackoverflow.com/questions/67120450/error-2unspecified-error-the-function-is-not-implemented-rebuild-the-libra

安装下面模块

pip install opencv-contrib-python 

使用一个行车记录仪视频进行测试

2905c3d871374931af52209aecc7b83d.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2259296.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单片机锂电池电量电压检测

一、引言 (一)锂电池电量检测的重要性简述 在如今这个科技飞速发展的时代,众多电子设备都依赖锂电池来供电,像我们日常使用的智能手机、平板电脑、笔记本电脑,还有出行必备的电动自行车、电动汽车等等,锂…

Android通过okhttp下载文件(本文案例 下载mp4到本地,并更新到相册)

使用步骤分为两步 第一步导入 okhttp3 依赖 第二步调用本文提供的 utils 第一步这里不做说明了,直接提供第二步复制即用 DownloadUtil 中 download 为下载文件 参数说明 这里主要看你把 destFileName 下载文件名称定义为什么后缀,比如我定义为 .mp4 下…

华为eNSP:VRRP

一、VRRP背景概述 在现代网络环境中,主机通常通过默认网关进行网络通信。当默认网关出现故障时,网络通信会中断,影响业务连续性和稳定性。为了提高网络的可靠性和冗余性,采用虚拟路由冗余协议(VRRP)是一种…

2.生成Transformation

目录 前言 Source FlatMap KeyBy sum print 总结 前言 以下面的WordCount为例 package com.wlh.p1;import org.apache.flink.api.common.functions.FlatMapFunction; import org.apache.flink.api.java.functions.KeySelector; import org.apache.flink.api.java.tuple…

PCL点云库入门——PCL库可视化之CloudViewer类简单点云信息显示

1、前言 可视化(visualization)涉及运用计算机图形学和图像处理技术,将数据转换成图像并在屏幕上展示,同时支持交互式处理。在PCL库中,一系列强大的可视化工具可供使用,其中较为流行的包括CloudViewer和PCL…

AI大模型学习笔记|多目标算法梳理、举例

多目标算法学习内容推荐: 1.通俗易懂讲算法-多目标优化-NSGA-II(附代码讲解)_哔哩哔哩_bilibili 2.多目标优化 (python pyomo pareto 最优)_哔哩哔哩_bilibili 学习笔记: 通过网盘分享的文件:多目标算法学习笔记 链接: https://pan.baidu.com…

印闪网络:阿里云数据库MongoDB版助力金融科技出海企业降本增效

客户背景 上海印闪网络科技有限公司,于2017年1月成立,投资方包括红杉资本等多家国际知名风投公司。公司业务聚焦东南亚普惠金融,常年稳居行业头部。创始团队来自腾讯,中国团队主要由运营、风控及产研人员组成,核心成员…

路由引入问题(双点双向路由回馈问题)

简介 总所周知,路由引入import又称路由重分发redistribute,为了解决不同路由协议进程间路由信息不互通而使用的技术,由于不同路由协议的算法、机制、开销等因素的差异,它们之间无法直接交换路由信息。因此,路由引入技…

windows安装gradle

目录 1. gradle的简介2. 安装操作2.1 下载2.2 配置环境变量2.3 测试验证 3. 总结 1. gradle的简介 Gradle 是一个开源的项目自动化构建工具,专注于灵活性和性能。它基于 Apache Ant 和 Apache Maven 的概念,但采用了 Groovy 或 Kotlin 作为领域特定语言…

数据库中的代数运算

这些代数基本运算通常被封装在数据库查询语言中,如SQL中的SELECT、FROM、WHERE等子句,使得用户可以更方便地对数据库进行查询和处理。 下面的介绍基于以下两个关系来说明: 传统的集合运算 并(∪) 合并两个关系中的元组…

Linux驱动开发(12):中断子系统–按键中断实验

本章我们以按键为例讲解在驱动程序中如何使用中断, 在学习本章之前建议先回顾一下关于中断相关的裸机部分相关章节, 这里主要介绍在驱动中如何使用中断,对于中断的概念及GIC中断控制器相关内容不再进行讲解。 本章配套源码和设备树插件位于“…

智能家居WTR096-16S录放音芯片方案,实现语音播报提示及录音留言功能

前言: 在当今社会的高速运转之下,夜幕低垂之时,许多辛勤工作的父母尚未归家。对于肩负家庭责任的他们而言,确保孩童按时用餐与居家安全成为心头大事。此时,家居留言录音提示功能应运而生,恰似家中的一位无形…

【Qt】信号、槽

目录 一、信号和槽的基本概念 二、connect函数:关联信号和槽 三、自定义信号和槽 1.自定义槽函数 2.自定义信号函数 例子: 四、带参的信号和槽 例子: 五、Q_OBJECT宏 六、断开信号和槽的连接 例子: 一、信号和槽的基本…

Zemax 中的 LED 阵列模型

LED 阵列的光学特性 LED 阵列由多个发光二极管 (LED) 组成,这些二极管以特定模式或配置排列,以实现均匀照明、更高强度或特定照明特性。这些阵列广泛用于显示器、照明系统、光通信和传感等应用。 LED 阵列的光学特性对于了解它如…

Qt编写区位码gb2312、机内码、国标码————附带详细介绍和编码实现

文章目录 0 背景1 了解编码1.1 ASCII码1.2 机内码、国标码、区位码1.2.1 区位码1.2.2 国标码(GB 2312-80)1.2.3 汉字机内码(GB 2312) 1.3 GBK和GB2312的区别2 编码实现2.1 QString数据转QByteArray类型2.1.1 使用QTextCodec2.1.2 …

【Linux系统】—— 权限的概念

【Linux系统】—— 权限的概念 1 权限1.1 什么是权限1.2 为什么要有权限1.3 理解权限 2 文件的权限2.1 文件角色2.2 文件权限2.3 修改文件权限2.3.1 修改目标属性2.3.1.1 字符修改法2.3.1.2 8进制修改法 2.3.2 修改角色 3 文件权限补充知识点3.1 只能修改自己的文件权限3.2 没有…

js:我要在template中v-for循环遍历这个centrerTopdata,我希望自循环前面三个就可以了怎么写

问&#xff1a; 我按在要在template中v-for循环遍历这个centrerTopdata&#xff0c;我希望自循环前面三个就可以了怎么写&#xff1f; 回答&#xff1a; 问&#xff1a; <div v-for"(item, index) in centrerTopdata.slice(0, 3)" :key"index"> d…

016 在路由器上配置 DHCP

配置路由器端口IP地址 将路由器的端口地址配置好&#xff0c; 左边的网络地址是 192.168.1.0 右边的网络地址是 192.168.2.0 配置路由器的DHCP服务 打开命令窗口&#xff0c;进入特权模式 进入全局配置 conf t创建一个DHCP地址池&#xff1b; po1 是地址池的名称&#xf…

使用IP自签名SSL证书

最近需要创建WebSocket服务器并使用SSL证书&#xff0c;由于是内网测试&#xff0c;所以需要使用指定IP的自签SSL证书。 其实笔者前面博文 使用nexus3作为Docker镜像仓库 解决nexus3登录x509: certificate has expired or is not yet valid 中有创建过相应的证书&#xff0c;这…

多模态大模型(二)——用Transformer Encoder和Decoder的方法(BLIP、CoCa、BEiTv3)

文章目录 BLIP: Bootstrapping Language-Image Pre-training for Unified Vision-Language Understanding and Generation 理解、生成我都要&#xff0c;一个很有效的、根据图片生成caption的工具1. BLIP的研究动机2. BLIP的模型结构3. CapFilt Model4. BLIP的训练过程 CoCa: C…