【3D入门-指标篇下】 3D重建评估指标对比-附实现代码

3D重建评估指标对比表

每个指标的具体代码位于文章末尾

指标计算方法数值范围评估重点优缺点适用场景
Chamfer Distance (C1)从预测网格到真实网格的平均距离[0, +∞)几何形状准确性优点:直观、计算高效
缺点:对噪声敏感
整体形状评估
Chamfer Distance (C2)从真实网格到预测网格的平均距离[0, +∞)几何形状完整性优点:检测缺失部分
缺点:可能被异常值影响
完整性评估
Normal Consistency对应点法向量点积的平均值[0, 1]表面细节质量优点:反映表面光滑度
缺点:不关注几何形状
表面质量评估
F-Score基于距离阈值的精确率/召回率调和平均[0, 100]高精度区域占比优点:关注高精度区域
缺点:依赖阈值选择
精度评估
Bounding Box IoU边界框交集体积/并集体积[0, 1]整体形状重叠度优点:计算简单快速
缺点:忽略细节差异
粗略形状评估

详细指标说明

1. Chamfer Distance (C1 & C2)

# C1: 预测→真实
c1 = np.mean(dist_pred_to_gt) * 1000# C2: 真实→预测  
c2 = np.mean(dist_gt_to_pred) * 1000

特点对比

  • C1:检测预测网格中多余的部分
  • C2:检测预测网格中缺失的部分
  • 理想情况:C1 ≈ C2,且都接近0

2. Normal Consistency

normal_consistency = np.mean(normal_pred_to_gt) + np.mean(normal_gt_to_pred)

评估维度

  • 表面光滑度:法向量变化是否平滑
  • 细节保持:能否保持原始表面的细节特征
  • 方向一致性:表面朝向是否一致

3. F-Score

tau = 1e-2  # 1cm阈值
prec_tau = (dist_pred_to_gt <= tau).mean() * 100
recall_tau = (dist_gt_to_pred <= tau).mean() * 100
fscore = (2 * prec_tau * recall_tau) / (prec_tau + recall_tau)

评估重点

  • 高精度区域:关注距离小于1cm的区域
  • 平衡性:同时考虑精确率和召回率
  • 实用性:反映实际应用中的可用性

4. Bounding Box IoU

iou = inter_vol / (vol1 + vol2 - inter_vol)

评估范围

  • 整体形状:不考虑内部细节
  • 空间位置:反映整体定位准确性
  • 尺度一致性:检测尺寸是否合理

指标组合使用建议

评估目标推荐指标组合原因
整体质量C1 + C2 + F-Score全面评估几何准确性
表面质量Normal Consistency专注表面细节
快速筛选Bounding Box IoU计算快速,适合大规模筛选
高精度应用F-Score关注高精度区域
研究对比全部指标提供全面的评估维度

实际应用中的选择

  • 服装重建:重点关注C1、C2和Normal Consistency
  • 快速原型:使用Bounding Box IoU进行初步筛选
  • 生产应用:重点关注F-Score确保高精度
  • 学术研究:使用全部指标进行综合评估

这些指标各有侧重,组合使用能够全面评估3D重建的质量。

import os 
import torch
import scipy as sp
import numpy as np
import argparse
import trimeshfrom tqdm import tqdm   def compute_iou_bbox(mesh, gt_mesh):mesh_bounds = mesh.boundsgt_mesh_bounds = gt_mesh.boundsxx1 = np.max([mesh_bounds[0, 0], gt_mesh_bounds[0, 0]])yy1 = np.max([mesh_bounds[0, 1], gt_mesh_bounds[0, 1]])zz1 = np.max([mesh_bounds[0, 2], gt_mesh_bounds[0, 2]])xx2 = np.min([mesh_bounds[1, 0], gt_mesh_bounds[1, 0]])yy2 = np.min([mesh_bounds[1, 1], gt_mesh_bounds[1, 1]])zz2 = np.min([mesh_bounds[1, 2], gt_mesh_bounds[1, 2]])vol1 = (mesh_bounds[1, 0] - mesh_bounds[0, 0]) * (mesh_bounds[1, 1] - mesh_bounds[0, 1]) * (mesh_bounds[1, 2] -mesh_bounds[0, 2])vol2 = (gt_mesh_bounds[1, 0] - gt_mesh_bounds[0, 0]) * (gt_mesh_bounds[1, 1] - gt_mesh_bounds[0, 1]) * (gt_mesh_bounds[1, 2] -gt_mesh_bounds[0, 2])inter_vol = np.max([0, xx2 - xx1]) * np.max([0, yy2 - yy1]) * np.max([0, zz2 - zz1])iou = inter_vol / (vol1 + vol2 - inter_vol + 1e-11)return ioudef calculate_iou(gt, prediction):intersection = torch.logical_and(gt, prediction)union = torch.logical_or(gt, prediction)return torch.sum(intersection) / torch.sum(union)def compute_surface_metrics(mesh_pred, mesh_gt):"""Compute surface metrics (chamfer distance and f-score) for one example.Args:mesh: trimesh.Trimesh, the mesh to evaluate.Returns:chamfer: float, chamfer distance.fscore: float, f-score."""# Chamfereval_points = 100000point_gt, idx_gt = mesh_gt.sample(eval_points, return_index=True)normal_gt = mesh_gt.face_normals[idx_gt]point_gt = point_gt.astype(np.float32)point_pred, idx_pred = mesh_pred.sample(eval_points, return_index=True)normal_pred = mesh_pred.face_normals[idx_pred]point_pred = point_pred.astype(np.float32)dist_pred_to_gt, normal_pred_to_gt = distance_field_helper(point_pred, point_gt, normal_pred, normal_gt)dist_gt_to_pred, normal_gt_to_pred = distance_field_helper(point_gt, point_pred, normal_gt, normal_pred)# TODO: subdivide by 2 following OccNet # https://github.com/autonomousvision/occupancy_networks/blob/406f79468fb8b57b3e76816aaa73b1915c53ad22/im2mesh/eval.py#L136chamfer_l1 = np.mean(dist_pred_to_gt) + np.mean(dist_gt_to_pred)c1 = np.mean(dist_pred_to_gt)c2 = np.mean(dist_gt_to_pred)normal_consistency = np.mean(normal_pred_to_gt) + np.mean(normal_gt_to_pred)# Fscoretau = 1e-2eps = 1e-6#dist_pred_to_gt = (dist_pred_to_gt**2)#dist_gt_to_pred = (dist_gt_to_pred**2)prec_tau = (dist_pred_to_gt <= tau).astype(np.float32).mean() * 100.recall_tau = (dist_gt_to_pred <= tau).astype(np.float32).mean() * 100.fscore = (2 * prec_tau * recall_tau) / max(prec_tau + recall_tau, eps)# Following the tradition to scale chamfer distance up by 10.return c1 * 1000., c2 * 1000., normal_consistency / 2., fscoredef distance_field_helper(source, target, normals_src=None, normals_tgt=None):target_kdtree = sp.spatial.cKDTree(target)distances, idx = target_kdtree.query(source, n_jobs=-1)if normals_src is not None and normals_tgt is not None:normals_src = \normals_src / np.linalg.norm(normals_src, axis=-1, keepdims=True)normals_tgt = \normals_tgt / np.linalg.norm(normals_tgt, axis=-1, keepdims=True)normals_dot_product = (normals_tgt[idx] * normals_src).sum(axis=-1)# Handle normals that point into wrong direction gracefully# (mostly due to mehtod not caring about this in generation)normals_dot_product = np.abs(normals_dot_product)else:normals_dot_product = np.array([np.nan] * source.shape[0], dtype=np.float32)return distances, normals_dot_productdef main(args):input_subfolder =  [x for x in sorted(os.listdir(args.input_path)) if os.path.isdir(os.path.join(args.input_path, x))]gt_subfolder = [x for x in sorted(os.listdir(args.gt_path)) if os.path.isdir(os.path.join(args.gt_path, x))]eval_name = args.input_path.split('/')[-1]mean_c1_list = []mean_c2_list = []mean_fscore_list = []mean_normal_consistency_list = []iou_list = []for pred, gt in tqdm(zip(input_subfolder, gt_subfolder)):pred_path = [x for x in sorted(os.listdir(os.path.join(args.input_path, pred))) ifx.endswith('shoes.obj') and not x.startswith('init')and not x.startswith('.')]if len(pred_path) == 0:continuemesh_pred = trimesh.load(os.path.join(args.input_path, pred, pred_path[0]))gt_path = [x for x in sorted(os.listdir(os.path.join(args.gt_path, gt, 'clothing'))) if x.endswith('shoe.obj')and not x.startswith('.')][0]mesh_gt = trimesh.load(os.path.join(args.gt_path, gt, 'clothing', gt_path))pred_2_scan, scan_2_pred, normal_consistency, fscore = compute_surface_metrics(mesh_pred, mesh_gt)iou = compute_iou_bbox(mesh_pred, mesh_gt)#print('Chamfer: {:.3f}, {:.3f}, Normal Consistency: {:.3f}, Fscore: {:.3f}, IOU: {:.3f}'.format(pred_2_scan, scan_2_pred, normal_consistency, fscore, iou))#print((pred_2_scan + scan_2_pred) / 2.0)iou_list.append(iou)mean_c1_list.append(pred_2_scan)mean_c2_list.append(scan_2_pred)mean_fscore_list.append(fscore)mean_normal_consistency_list.append(normal_consistency)mean_c1 = np.mean(mean_c1_list)mean_c2 = np.mean(mean_c2_list)mean_fscore = np.mean(mean_fscore_list)mean_normal_consistency = np.mean(mean_normal_consistency_list)mean_iou = np.mean(iou_list)std_c1 = np.std(mean_c1_list)std_c2 = np.std(mean_c2_list)std_fscore = np.std(mean_fscore_list)std_normal_consistency = np.std(mean_normal_consistency_list)std_iou = np.std(iou_list)print('Mean Chamfer: {:.3f} ({:.3f}), {:.3f} ({:.3f}), Normal Consistency: {:.3f} ({:.3f}), Fscore: {:.3f} ({:.3f})'.format(mean_c1, std_c1, mean_c2, std_c2, mean_normal_consistency, std_normal_consistency, mean_fscore, std_fscore))print('{:.3f} ({:.3f}),{:.3f} ({:.3f}),{:.3f} ({:.3f}),{:.3f} ({:.3f}),{:.3f} ({:.3f})'.format(mean_c1, std_c1, mean_c2, std_c2, mean_normal_consistency, std_normal_consistency, mean_fscore, std_fscore, mean_iou, std_iou))print('{:.6f}, {:.6f}, {:.6f}, {:.6f}, {:.6f}'.format(mean_c1, mean_c2, mean_normal_consistency, mean_fscore, mean_iou))output_txt = eval_name + '.txt'out = np.stack([mean_c1_list, mean_c2_list, mean_normal_consistency_list, mean_fscore_list], axis=1)np.savetxt(output_txt, out, fmt='%.6f', delimiter=' ')
if __name__ == '__main__':parser = argparse.ArgumentParser()#parser.add_argument('-o', '--output_dir', required=True, help='Where to store the processed images and other data.')parser.add_argument('-i', '--input_path', required=True ,type=str)parser.add_argument('-g', '--gt_path', required=True ,type=str)main(parser.parse_args())

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

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

相关文章

香港电讯创新解决方案,开启企业数字化转型新篇章

在数字化浪潮席卷全球的今天&#xff0c;企业正加速突破传统办公和业务模式的桎梏&#xff0c;力求通过高效协同与业务创新实现跨越式发展。香港电讯作为科技解决方案提供商&#xff0c;持续推动技术创新应用。近期&#xff0c;香港电讯通过多项创新应用、产品升级及战略合作&a…

数据分析编程第六步:大数据运算

6.1 数据介绍直接打开集算器运行 createEventsAndUsers.splx 文件&#xff0c;就可以得到如下两张表&#xff08;也可以根据代码中的注释&#xff0c;修改起止日期以及每天的数据量&#xff09;&#xff1a;电商数据表 events.csv字段名含义eventID事件编号, 从 1 开始流水号us…

vue2+elementui 表格单元格增加背景色,根据每列数据的大小 颜色依次变浅显示2

注意&#xff1a; 正数前5和负数后5的颜色是固定的&#xff0c;剩下5之后的数据颜色是根据第5个颜色依次变浅的&#xff1b; 封装的js方法&#xff1a; /*** 最终版表格颜色处理器* param {Array} data 完整表格数据* param {String} field 当前字段名* param {Object} row 当前…

【AOSP】Android Dump 开发与调试指南

在 Android 系统开发与调试中&#xff0c;dump 是一个不可或缺的强大工具。它能够提供关于系统服务、应用程序状态以及底层硬件信息的详细快照。对于希望深入了解 Android 系统内部工作原理、排查复杂问题或进行性能优化的开发者来说&#xff0c;掌握 dump 的使用至关重要。一、…

Qt数据结构与编码技巧全解析

文章目录Qt中的数据结构QDebugqDebug函数QT的内置类型一般都会重载 << 运算符QT的几何规则QString 字符串编码变长 VS 定长QString 适合中转数据吗&#xff1f;Qstring 的底层使用写时复制QString的具体使用QString 的构造函数格式化构造数值转化为字符串字符串转成数值增…

Ubuntu操作系统下MySQL、MongoDB、Redis

在开发和运维过程中&#xff0c;经常需要从Windows客户端远程连接到Ubuntu服务器上的数据库。本文将详细介绍如何在Ubuntu操作系统下安装和配置MySQL、MongoDB和Redis&#xff0c;以允许从Windows客户端进行远程连接&#xff0c;并提供详细的远程连接命令和配置说明。一、MySQL…

校园勤工俭学微信小程序的设计与实现:基于数字化服务生态的赋能体系构建

在高等教育普及化与数字化校园建设的双重驱动下&#xff0c;传统校园勤工俭学管理模式正面临深刻变革。当前高校勤工俭学工作普遍存在岗位匹配效率低下、过程管理粗放、数据孤岛严重等痛点——根据教育部全国学生资助管理中心2022年统计数据&#xff0c;全国普通高校共有约450万…

Apisix工作流程

是的,你的理解基本正确:当请求到达APISIX时,它会先根据请求的URI、Host、请求方法、 headers等信息匹配最合适的路由,然后执行路由关联的插件逻辑,最后转发到路由配置的上游服务。下面详细讲解APISIX处理请求的全链路及可能的情况。 一、请求全链路流程 APISIX处理请求的…

InnoDB存储引擎底层拆解:从页、事务到锁,如何撑起MySQL数据库高效运转(上)

目录 Page页** B树查询 如何加快记录的查询&#xff1f; 索引** 聚簇索引(主键) 二级索引(非主键) 联合索引——多列 bufferPool* Free链表 flush链表 Flush链表刷新方式有如下两种&#xff1a; LRU链表 针对LRU链表方案缺点的优化 redoLog* redo简单日志类型 redo复杂日志类型…

【人工智能99问】GPT4的原理是什么?(32/99)

【人工智能99问】GPT4的原理是什么&#xff1f;(32/99) 文章目录GPT-4简介一、结构与原理二、使用场景三、优缺点分析四、训练技巧与关键改进五、示例说明六、总结GPT-4简介 一、结构与原理 1. 架构设计 GPT-4基于Transformer解码器架构&#xff0c;核心改进包括&#xff1a;…

//Q是一个队列,S是一个空栈,实现将队列中的元素逆置的算法。

#include<stdio.h> #include<stdbool.h> #include<stdlib.h> #define Size 6 typedef struct SqNode//队列结点 {int data;struct SqNode* next; }LinkNode; typedef struct SqQueue//队列 {LinkNode* front, * rear; //头指针和尾指针 }LinkQueue; typedef …

毕马威 —— 公众对人工智能的信任、态度及使用情况调查

文章目录 前言 一、背景介绍 二、对人工智能的信任与接受度 三、人工智能的使用与认知情况 四、人工智能的益处与风险 五、人工智能的监管与治理 六、工作场所的人工智能应用 七、人工智能对工作的影响 八、学生对人工智能的应用 九、核心启示 1.新兴经济体在公众与员工人工智能…

基于Spring Session + Redis + JWT的单点登录实现

实现思路 用户访问受保护资源时&#xff0c;若未认证则重定向到认证中心认证中心验证用户身份&#xff0c;生成JWT令牌并存储到Redis认证中心重定向回原应用并携带令牌应用验证JWT有效性并从Redis获取会话信息用户在其他应用访问时&#xff0c;通过相同机制实现单点登录 代码…

微服务Eureka组件的介绍、安装、使用

微服务 Eureka 组件的介绍、安装与使用详解 在微服务架构中&#xff0c;服务注册与发现是至关重要的一环&#xff0c;而 Eureka 作为 Netflix 开源的服务注册中心&#xff0c;广泛应用于 Spring Cloud 微服务体系中。本文将带你全面了解 Eureka 的概念、安装及在 Spring Boot …

【PostgreSQL内核学习:通过 ExprState 提升哈希聚合与子计划执行效率(一)】

PostgreSQL内核学习&#xff1a;通过 ExprState 提升哈希聚合与子计划执行效率&#xff08;一&#xff09;引言背景补丁的意义补丁概述JIT & LLVM实际例子&#xff08;以 PostgreSQL 为例&#xff09;提交信息提交描述引入 ExprState 进行哈希计算&#xff1a;支持 JIT 编译…

web端播放flv视频流demo(flv.js的使用)

需求&#xff1a;原本是需要前端播放RTMP视频流的&#xff0c;但是现在的浏览器都不支持flash插件了&#xff0c;让用户安装flash插件也不现实&#xff0c;所以直接让后端将RTMP视频流转换成flv视频流给到前端进行播放。 直接上demo&#xff0c;直接就能播放&#xff0c;如果遇…

【拍摄学习记录】04-拍摄模式/曝光组合

曝光组合全自动半自动光圈优先手动挡【固定物体长时间不变时候、闪光灯时候、】手机上的光学变焦与数码变焦是不同的&#xff0c;使用档位推荐可以提升画质。手机夜景模式长曝光【车流轨迹、星轨】HDR 大光比【日落时候使用】专业模式&#xff0c;【感光度iso、快门可以调节】…

新liunx部署mysql过程问题

首先看下是什么发行版 cat /etc/os-release CentOS Linux 7 ################################## 使用 yum下载包 发现不行 源不行 那就换成阿里的 # 进入 yum 源配置目录 cd /etc/yum.repos.d/ # 备份所有默认 repo 文件&#xff08;以 CentOS 为例&#xff0c;其他系统…

Python 第三方库:Beautiful Soup(HTML/XML 解释提取)

Beautiful Soup 是一个 用于从 HTML 和 XML 文件中提取数据的 Python 第三方库。它为复杂的网页结构提供了简单易用的解析接口&#xff0c;尤其适合网页爬虫和数据提取任务。Beautiful Soup 提供树型结构访问、标签搜索、属性提取等功能&#xff0c;并支持多种解析器&#xff0…

使用STM32CubeMX使用CAN驱动无刷电机DJI3508

简介 文章为笔记性质 硬件包括 大疆C板 电机调速器C620 DJI3508电机 CAN知识介绍 CAN的概念 CAN是控制器区域网络&#xff08;Controller Area Network&#xff09;的缩写。CAN总线是一种适用于工业设备的高性能总线网络。说白了就是也就是一种通讯方式而已。 把多个设…