ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于YOLO与OpenCV的高尔夫球实时追踪系统开发实战

基于YOLO与OpenCV的高尔夫球实时追踪系统开发实战 猫儿这个高尔夫捕手从零实现一个智能高尔夫球追踪系统在计算机视觉和运动分析领域动物行为追踪一直是个有趣且具有挑战性的课题。最近在开发一个高尔夫球轨迹分析系统时我意外发现家里的猫对滚动的高尔夫球表现出惊人的追踪能力这启发了我将动物行为分析与运动物体检测技术相结合的想法。本文将完整分享如何构建一个基于OpenCV和YOLO的智能高尔夫球追踪系统包含从环境搭建到算法优化的全流程实战代码。无论你是计算机视觉初学者还是希望将AI技术应用于体育分析的开发者本文都能为你提供一套可落地的解决方案。我们将使用Python作为主要开发语言结合OpenCV进行图像处理YOLOv5进行目标检测最终实现高尔夫球的实时追踪和轨迹分析。1. 项目背景与核心概念1.1 高尔夫球追踪的技术价值高尔夫球追踪在体育训练、比赛分析和智能场馆建设中具有重要应用价值。传统的追踪方法依赖人工观察或昂贵的专业设备而基于计算机视觉的解决方案可以大幅降低成本并提高分析效率。通过实时检测高尔夫球的运动轨迹我们可以计算球速、飞行角度、落点预测等关键数据为运动员和教练提供数据支持。1.2 计算机视觉在运动分析中的应用计算机视觉技术通过模拟人类视觉系统让计算机能够看懂图像和视频中的内容。在高尔夫球追踪场景中我们需要解决几个关键技术问题目标检测识别高尔夫球、目标追踪连续帧间的关联、轨迹分析运动路径计算。本文将重点介绍前两个环节的实现方案。1.3 系统架构概述我们的智能高尔夫球追踪系统采用模块化设计主要包含以下组件视频输入模块支持摄像头实时流和视频文件预处理模块图像增强和噪声过滤目标检测模块基于YOLOv5的高尔夫球识别追踪模块基于卡尔曼滤波的多目标追踪分析模块轨迹可视化和运动参数计算2. 环境准备与依赖配置2.1 系统环境要求本项目在以下环境中测试通过建议使用相似配置以获得最佳效果操作系统Windows 10/11, Ubuntu 18.04 或 macOS 10.15Python版本3.8-3.103.11可能存在兼容性问题内存至少8GB RAM显卡支持CUDA的NVIDIA显卡可选可加速推理2.2 创建虚拟环境为避免依赖冲突我们首先创建独立的Python虚拟环境# 创建虚拟环境 python -m venv golf_tracker # 激活虚拟环境Windows golf_tracker\Scripts\activate # 激活虚拟环境Linux/macOS source golf_tracker/bin/activate2.3 安装核心依赖包创建requirements.txt文件包含项目所需的所有依赖# requirements.txt torch1.9.0 torchvision0.10.0 opencv-python4.5.0 numpy1.21.0 ultralytics8.0.0 # YOLOv8官方库 filterpy1.4.5 # 卡尔曼滤波实现 scipy1.7.0 matplotlib3.5.0 Pillow8.3.0使用pip安装依赖pip install -r requirements.txt2.4 验证安装创建验证脚本检查关键库是否正常安装# verify_installation.py import torch import cv2 import numpy as np from ultralytics import YOLO print(fPyTorch版本: {torch.__version__}) print(fOpenCV版本: {cv2.__version__}) print(fCUDA可用: {torch.cuda.is_available()}) # 测试基本功能 try: model YOLO(yolov5n.pt) # 加载纳米版YOLOv5进行测试 print(YOLO模型加载成功) except Exception as e: print(fYOLO加载失败: {e})3. 高尔夫球检测模型训练3.1 数据集准备与标注高质量的数据集是模型准确性的基础。我们需要收集包含高尔夫球在不同场景下的图像并进行精确标注。3.1.1 数据收集策略收集数据时需要考虑以下场景多样性不同光照条件室内、室外、阴影不同背景环境草地、沙坑、天空不同球体状态静止、运动、半遮挡不同拍摄角度和距离建议收集500-1000张高质量图像按8:1:1的比例分割为训练集、验证集和测试集。3.1.2 数据标注工具使用使用LabelImg或CVAT进行边界框标注创建PASCAL VOC格式的标注文件!-- 示例标注文件 annotations/image001.xml -- annotation filenameimage001.jpg/filename size width1920/width height1080/height depth3/depth /size object namegolf_ball/name bndbox xmin850/xmin ymin420/ymin xmax890/xmax ymax460/ymax /bndbox /object /annotation3.2 YOLOv5模型配置创建自定义的模型配置文件针对高尔夫球检测进行优化# golf_ball_yolov5s.yaml # YOLOv5 by Ultralytics, GPL-3.0 license # 参数配置 nc: 1 # 类别数量只有高尔夫球 depth_multiple: 0.33 # 模型深度倍数 width_multiple: 0.50 # 层通道倍数 # 锚点框配置针对高尔夫球大小优化 anchors: - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 - [116,90, 156,198, 373,326] # P5/32 # 骨干网络 backbone: # [来源, 重复次数, 模块, 参数] [[-1, 1, Focus, [64, 3]], # 0-P1/2 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 3, C3, [128]], [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 9, C3, [256]], [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 9, C3, [512]], [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 1, SPP, [1024, [5, 9, 13]]], [-1, 3, C3, [1024, False]], # 9 ] # 头部网络 head: [[-1, 1, Conv, [512, 1, 1]], [-1, 1, nn.Upsample, [None, 2, nearest]], [[-1, 6], 1, Concat, [1]], # 猫系骨干P4 [-1, 3, C3, [512, False]], # 13 [-1, 1, Conv, [256, 1, 1]], [-1, 1, nn.Upsample, [None, 2, nearest]], [[-1, 4], 1, Concat, [1]], # 猫系骨干P3 [-1, 3, C3, [256, False]], # 17 (P3/8-small) [-1, 1, Conv, [256, 3, 2]], [[-1, 14], 1, Concat, [1]], # 猫系骨干P4 [-1, 3, C3, [512, False]], # 20 (P4/16-medium) [-1, 1, Conv, [512, 3, 2]], [[-1, 10], 1, Concat, [1]], # 猫系骨干P5 [-1, 3, C3, [1024, False]], # 23 (P5/32-large) [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ]3.3 模型训练脚本创建完整的训练脚本包含数据加载、模型训练和验证# train_golf_detector.py import torch import yaml from pathlib import Path from ultralytics import YOLO import argparse def setup_training_config(): 配置训练参数 config { data: golf_ball_dataset.yaml, cfg: golf_ball_yolov5s.yaml, weights: yolov5s.pt, epochs: 100, batch_size: 16, img_size: 640, device: 0 if torch.cuda.is_available() else cpu, workers: 4, patience: 10, save_period: 10 } return config def create_dataset_yaml(): 创建数据集配置文件 dataset_config { path: ./datasets/golf_ball, train: images/train, val: images/val, test: images/test, nc: 1, names: [golf_ball] } with open(golf_ball_dataset.yaml, w) as f: yaml.dump(dataset_config, f) def main(): # 创建数据集配置 create_dataset_yaml() # 设置训练配置 config setup_training_config() # 加载预训练模型 model YOLO(config[weights]) # 开始训练 results model.train( dataconfig[data], epochsconfig[epochs], batch_sizeconfig[batch_size], imgszconfig[img_size], deviceconfig[device], workersconfig[workers], patienceconfig[patience], save_periodconfig[save_period] ) print(训练完成模型保存在 runs/train/exp/weights/best.pt) if __name__ __main__: main()4. 实时追踪系统实现4.1 多目标追踪算法选择针对高尔夫球追踪的特点我们选择DeepSORT算法作为基础结合自定义的卡尔曼滤波器进行优化# tracker.py import numpy as np from filterpy.kalman import KalmanFilter from scipy.optimize import linear_sum_assignment import cv2 class GolfBallTracker: def __init__(self, max_age30, min_hits3, iou_threshold0.3): self.max_age max_age # 最大丢失帧数 self.min_hits min_hits # 最小确认命中次数 self.iou_threshold iou_threshold # IOU匹配阈值 self.trackers [] # 当前活动的追踪器 self.frame_count 0 # 帧计数器 self.next_id 1 # 下一个追踪ID def create_kalman_filter(self): 创建针对高尔夫球运动的卡尔曼滤波器 kf KalmanFilter(dim_x7, dim_z4) # 状态转移矩阵 [x, y, w, h, vx, vy, vw] kf.F np.array([ [1,0,0,0,1,0,0], [0,1,0,0,0,1,0], [0,0,1,0,0,0,1], [0,0,0,1,0,0,0], [0,0,0,0,1,0,0], [0,0,0,0,0,1,0], [0,0,0,0,0,0,1] ]) # 测量矩阵 kf.H np.array([ [1,0,0,0,0,0,0], [0,1,0,0,0,0,0], [0,0,1,0,0,0,0], [0,0,0,1,0,0,0] ]) # 协方差矩阵 kf.P[4:,4:] * 1000. # 速度不确定性 kf.P * 10. # 测量噪声 kf.R[2:,2:] * 10. # 过程噪声 kf.Q[-1,-1] * 0.01 kf.Q[4:,4:] * 0.01 return kf def update(self, detections): 更新追踪器状态 self.frame_count 1 # 预测当前帧所有追踪器的位置 for tracker in self.trackers: tracker.kf.predict() # 匹配检测结果和现有追踪器 matched, unmatched_detections, unmatched_trackers \ self.associate_detections_to_trackers(detections) # 更新匹配的追踪器 for detection_idx, tracker_idx in matched: detection detections[detection_idx] self.trackers[tracker_idx].update(detection) self.trackers[tracker_idx].hits 1 self.trackers[tracker_idx].time_since_update 0 # 为未匹配的检测创建新追踪器 for idx in unmatched_detections: self.create_new_tracker(detections[idx]) # 处理未匹配的追踪器 i len(self.trackers) for tracker_idx in reversed(unmatched_trackers): self.trackers[tracker_idx].time_since_update 1 # 移除长时间未更新的追踪器 if self.trackers[tracker_idx].time_since_update self.max_age: self.trackers.pop(tracker_idx) # 返回当前活跃的追踪结果 return self.get_tracked_objects()4.2 视频处理流水线创建完整的视频处理流水线实现端到端的高尔夫球追踪# golf_tracker_pipeline.py import cv2 import numpy as np from ultralytics import YOLO from tracker import GolfBallTracker import time class GolfBallTrackingPipeline: def __init__(self, model_pathbest.pt, conf_threshold0.5): # 加载训练好的YOLO模型 self.model YOLO(model_path) self.conf_threshold conf_threshold # 初始化追踪器 self.tracker GolfBallTracker() # 性能统计 self.frame_count 0 self.fps 0 self.start_time time.time() def preprocess_frame(self, frame): 帧预处理增强对比度和减少噪声 # 转换为HSV色彩空间进行光照归一化 hsv cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) h, s, v cv2.split(hsv) # 对亮度通道进行直方图均衡化 v_eq cv2.equalizeHist(v) hsv_eq cv2.merge([h, s, v_eq]) frame_eq cv2.cvtColor(hsv_eq, cv2.COLOR_HSV2BGR) # 高斯模糊减少噪声 blurred cv2.GaussianBlur(frame_eq, (5, 5), 0) return blurred def detect_golf_balls(self, frame): 使用YOLO检测高尔夫球 results self.model(frame, confself.conf_threshold) detections [] for result in results: boxes result.boxes if boxes is not None: for box in boxes: # 获取边界框坐标和置信度 x1, y1, x2, y2 box.xyxy[0].cpu().numpy() conf box.conf[0].cpu().numpy() detections.append({ bbox: [x1, y1, x2, y2], confidence: conf, class: golf_ball }) return detections def draw_tracking_results(self, frame, tracked_objects): 在帧上绘制追踪结果 for obj in tracked_objects: x1, y1, x2, y2 obj[bbox] track_id obj[track_id] confidence obj[confidence] # 绘制边界框 color self.get_color(track_id) cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), color, 2) # 绘制标签 label fBall {track_id}: {confidence:.2f} label_size cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2)[0] cv2.rectangle(frame, (int(x1), int(y1 - label_size[1] - 10)), (int(x1 label_size[0]), int(y1)), color, -1) cv2.putText(frame, label, (int(x1), int(y1 - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) # 绘制轨迹 if trajectory in obj: trajectory obj[trajectory] if len(trajectory) 1: points np.array(trajectory, dtypenp.int32) cv2.polylines(frame, [points], False, color, 2) # 显示FPS cv2.putText(frame, fFPS: {self.fps:.1f}, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) return frame def get_color(self, track_id): 根据追踪ID生成颜色 colors [ (255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255), (0, 255, 255), (128, 0, 0), (0, 128, 0), (0, 0, 128) ] return colors[track_id % len(colors)] def process_video(self, video_path, output_pathNone): 处理视频文件 cap cv2.VideoCapture(video_path) # 获取视频属性 width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps cap.get(cv2.CAP_PROP_FPS) # 设置输出视频 if output_path: fourcc cv2.VideoWriter_fourcc(*XVID) out cv2.VideoWriter(output_path, fourcc, fps, (width, height)) while cap.isOpened(): ret, frame cap.read() if not ret: break # 预处理帧 processed_frame self.preprocess_frame(frame) # 检测高尔夫球 detections self.detect_golf_balls(processed_frame) # 更新追踪器 tracked_objects self.tracker.update(detections) # 绘制结果 result_frame self.draw_tracking_results(frame.copy(), tracked_objects) # 计算FPS self.frame_count 1 if self.frame_count % 30 0: elapsed time.time() - self.start_time self.fps self.frame_count / elapsed # 显示结果 cv2.imshow(Golf Ball Tracker, result_frame) # 保存输出视频 if output_path: out.write(result_frame) # 退出条件 if cv2.waitKey(1) 0xFF ord(q): break # 释放资源 cap.release() if output_path: out.release() cv2.destroyAllWindows() # 使用示例 if __name__ __main__: pipeline GolfBallTrackingPipeline(model_pathruns/train/exp/weights/best.pt) pipeline.process_video(golf_swing.mp4, output_pathtracked_output.avi)5. 轨迹分析与数据可视化5.1 运动参数计算实现高尔夫球运动轨迹的物理参数分析# trajectory_analyzer.py import numpy as np from scipy import stats import matplotlib.pyplot as plt class TrajectoryAnalyzer: def __init__(self): self.trajectories {} # 存储不同球的轨迹数据 def add_trajectory_point(self, track_id, point, timestamp): 添加轨迹点 if track_id not in self.trajectories: self.trajectories[track_id] { points: [], timestamps: [], velocities: [], accelerations: [] } trajectory self.trajectories[track_id] trajectory[points].append(point) trajectory[timestamps].append(timestamp) # 计算速度和加速度 if len(trajectory[points]) 2: self.calculate_motion_parameters(track_id) def calculate_motion_parameters(self, track_id): 计算运动参数 trajectory self.trajectories[track_id] points np.array(trajectory[points]) timestamps np.array(trajectory[timestamps]) # 计算速度像素/秒 if len(points) 2: displacements np.diff(points, axis0) time_diffs np.diff(timestamps) velocities displacements / time_diffs[:, np.newaxis] trajectory[velocities].extend(velocities) # 计算加速度 if len(velocities) 2: acceleration np.diff(velocities, axis0) / time_diffs[1:, np.newaxis] trajectory[accelerations].extend(acceleration) def analyze_trajectory(self, track_id): 分析完整轨迹 if track_id not in self.trajectories: return None trajectory self.trajectories[track_id] points np.array(trajectory[points]) if len(points) 2: return None # 基本统计信息 analysis { total_distance: self.calculate_total_distance(points), average_speed: self.calculate_average_speed(trajectory), max_speed: self.calculate_max_speed(trajectory), flight_time: trajectory[timestamps][-1] - trajectory[timestamps][0], trajectory_angle: self.calculate_launch_angle(points) } return analysis def calculate_total_distance(self, points): 计算总移动距离 displacements np.diff(points, axis0) distances np.linalg.norm(displacements, axis1) return np.sum(distances) def calculate_average_speed(self, trajectory): 计算平均速度 if not trajectory[velocities]: return 0 speeds np.linalg.norm(trajectory[velocities], axis1) return np.mean(speeds) def calculate_max_speed(self, trajectory): 计算最大速度 if not trajectory[velocities]: return 0 speeds np.linalg.norm(trajectory[velocities], axis1) return np.max(speeds) def calculate_launch_angle(self, points, num_points5): 计算发射角度 if len(points) num_points: return 0 # 使用前几个点计算初始方向 initial_points points[:num_points] x_coords initial_points[:, 0] y_coords initial_points[:, 1] # 线性回归计算角度 slope, intercept, r_value, p_value, std_err stats.linregress(x_coords, y_coords) angle np.degrees(np.arctan(slope)) return angle def visualize_trajectory(self, track_id, save_pathNone): 可视化轨迹 if track_id not in self.trajectories: return trajectory self.trajectories[track_id] points np.array(trajectory[points]) plt.figure(figsize(12, 8)) # 绘制轨迹 plt.subplot(2, 2, 1) plt.plot(points[:, 0], points[:, 1], b-, linewidth2, labelTrajectory) plt.scatter(points[:, 0], points[:, 1], crange(len(points)), cmapviridis) plt.xlabel(X Position) plt.ylabel(Y Position) plt.title(fGolf Ball Trajectory - ID {track_id}) plt.colorbar(labelFrame Number) plt.grid(True) # 绘制速度变化 plt.subplot(2, 2, 2) if trajectory[velocities]: speeds np.linalg.norm(trajectory[velocities], axis1) plt.plot(range(len(speeds)), speeds, r-, linewidth2) plt.xlabel(Frame) plt.ylabel(Speed (pixels/frame)) plt.title(Speed Over Time) plt.grid(True) # 绘制运动方向 plt.subplot(2, 2, 3) if len(points) 2: displacements np.diff(points, axis0) angles np.degrees(np.arctan2(displacements[:, 1], displacements[:, 0])) plt.plot(range(len(angles)), angles, g-, linewidth2) plt.xlabel(Frame) plt.ylabel(Direction (degrees)) plt.title(Movement Direction) plt.grid(True) # 显示分析结果 plt.subplot(2, 2, 4) analysis self.analyze_trajectory(track_id) if analysis: metrics [Total Distance, Avg Speed, Max Speed, Flight Time, Launch Angle] values [ f{analysis[total_distance]:.1f} px, f{analysis[average_speed]:.1f} px/frame, f{analysis[max_speed]:.1f} px/frame, f{analysis[flight_time]:.2f} s, f{analysis[trajectory_angle]:.1f}° ] plt.axis(off) for i, (metric, value) in enumerate(zip(metrics, values)): plt.text(0.1, 0.9 - i*0.15, f{metric}: {value}, fontsize12, transformplt.gca().transAxes) plt.tight_layout() if save_path: plt.savefig(save_path, dpi300, bbox_inchestight) plt.show()5.2 实时数据显示界面创建实时数据显示界面方便训练和比赛中的即时分析# realtime_dashboard.py import cv2 import numpy as np from datetime import datetime class RealtimeDashboard: def __init__(self, width1200, height800): self.width width self.height height self.canvas np.ones((height, width, 3), dtypenp.uint8) * 40 # 深灰色背景 # 显示区域划分 self.video_width int(width * 0.6) self.stats_width width - self.video_width def update_dashboard(self, video_frame, tracked_objects, analysis_data): 更新仪表板显示 # 清空画布 self.canvas.fill(40) # 显示视频帧 if video_frame is not None: video_frame self.resize_frame(video_frame, self.video_width, self.height) self.canvas[0:video_frame.shape[0], 0:video_frame.shape[1]] video_frame # 显示统计信息 self.display_statistics(tracked_objects, analysis_data) # 显示时间戳 self.display_timestamp() return self.canvas def resize_frame(self, frame, target_width, target_height): 调整帧尺寸 h, w frame.shape[:2] scale min(target_width / w, target_height / h) new_w, new_h int(w * scale), int(h * scale) resized cv2.resize(frame, (new_w, new_h)) return resized def display_statistics(self, tracked_objects, analysis_data): 显示统计信息 x_start self.video_width 20 y_start 20 line_height 30 # 标题 cv2.putText(self.canvas, GOLF BALL TRACKING STATS, (x_start, y_start), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) y_start line_height * 2 # 追踪对象信息 cv2.putText(self.canvas, fActive Balls: {len(tracked_objects)}, (x_start, y_start), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1) y_start line_height for i, obj in enumerate(tracked_objects): track_id obj[track_id] confidence obj[confidence] text fBall {track_id}: {confidence:.3f} cv2.putText(self.canvas, text, (x_start, y_start), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) y_start line_height # 分析数据 if analysis_data: y_start line_height cv2.putText(self.canvas, ANALYSIS RESULTS:, (x_start, y_start), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 0), 1) y_start line_height for key, value in analysis_data.items(): text f{key}: {value} cv2.putText(self.canvas, text, (x_start, y_start), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1) y_start line_height def display_timestamp(self): 显示时间戳 timestamp datetime.now().strftime(%Y-%m-%d %H:%M:%S) cv2.putText(self.canvas, timestamp, (10, self.height - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)6. 性能优化与工程实践6.1 模型推理优化针对实时性要求实施多种优化策略# optimization.py import torch import torch_tensorrt import onnxruntime as ort from ultralytics import YOLO class ModelOptimizer: def __init__(self, model_path): self.model_path model_path self.original_model YOLO(model_path) def optimize_for_inference(self, precisionfp16): 模型推理优化 # 切换到评估模式 self.original_model.model.eval() # 示例优化配置 optimization_config { precision: precision, workspace_size: 1 30, # 1GB min_block_size: 5, torch_executed_ops: [aten::view, aten::reshape] } # 使用TorchScript优化 traced_model self.convert_to_torchscript() # 使用TensorRT进一步优化如果可用 if torch.cuda.is_available(): optimized_model self.optimize_with_tensorrt(traced_model, optimization_config) return optimized_model return traced_model def convert_to_torchscript(self): 转换为TorchScript格式 example_input torch.randn(1, 3, 640, 640).cuda() if torch.cuda.is_available() else torch.randn(1, 3, 640, 640) traced_script_module torch.jit.trace(self.original_model.model, example_input) # 保存优化后的模型 torch.jit.save(traced_script_module, optimized_model.pt) return traced_script_module def optimize_with_tensorrt(self, model, config): 使用TensorRT优化 try: # 编译模型 trt_model torch_tensorrt.compile( model, inputs[torch_tensorrt.Input((1, 3, 640, 640))], enabled_precisions{torch.float16} if config[precision] fp16 else {torch.float32}, workspace_sizeconfig[workspace_size], min_block_sizeconfig[min_block_size], torch_executed_opsconfig[torch_executed_ops] ) return trt_model except Exception as e: print(fTensorRT优化失败: {e}回退到TorchScript) return model def export_to_onnx(self): 导出为ONNX格式 success self.original_model.export(formatonnx, dynamicTrue, simplifyTrue) if success: print(ONNX导出成功) return True else: print(ONNX导出失败) return False # 使用示例
返回列表