news 2026/9/10 1:54:42

航拍路面病害检测:VOC+YOLO双格式数据集与YOLOv8训练实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
航拍路面病害检测:VOC+YOLO双格式数据集与YOLOv8训练实战

简介:航拍路面病害检测数据集提供3302张道路图像,配套Pascal VOC与YOLO两种标注格式,适合用于目标检测、裂缝定位等视觉任务,面向计算机视觉初学者与道路设施巡检算法开发者。压缩包共2000个文件,以1999个XML标注文件为主体,另含1个TXT使用说明,整体大小约166MB;每张图像均配套VOC格式XML与YOLO格式TXT,可免去手动格式转换,直接接入主流检测框架训练。数据集标注了7类路面病害,涵盖龟裂、纵向裂缝、斜裂缝、坑洞与修补区域等典型缺陷,图像来自航拍视角,贴近真实巡检场景。目前已有1197人学习下载,适合需要标准格式训练数据、开展裂缝检测算法验证与毕业设计的读者使用。

1. 航拍路面病害检测与道路裂缝数据集:为什么两条标注链路都得保留

航拍路面病害检测这几年在道路巡检里越来越常见,无人机带个相机扫完一段国道,回来就是几千张带坐标的影像。真正耗时间的不是飞,而是标注——裂缝细长、坑槽形状不规则,画框的工时常年压着项目进度。所以当你拿到一份 3302 张、7 类别的航拍路面病害 VOC+YOLO 双格式数据集时,等于把最贵的标注环节省掉了一半。这份数据最大的价值不在张数,而在“VOC+YOLO”双格式这个设计:VOC 方便人工检查和二次修正,YOLO 格式可以直接喂给检测框架训练。适合做道路养护信息化、桥梁检测、无人机巡检的工程师,也适合刚准备跑通第一个目标检测项目的算法同学——你不需要懂标注工具导出细节,把目录结构搞清楚就能开工。

2. 看懂 VOC 与 YOLO 双格式:目录结构、标注文件与转换逻辑

拿到压缩包之后第一件事不是解压就跑训练,而是先弄清里面两种标注格式各自的目录组织和坐标表达方式。这一章把 VOC 和 YOLO 的差异讲透,并给出一个可复用的转换脚本,方便你把它转成自己习惯的格式。

2.1 VOC 格式的组成:JPEGImages、Annotations 与 ImageSets 三层目录

VOC 格式源自 PASCAL VOC 竞赛,后来成为目标检测数据集的标准交换格式。常见目录组织如下:

dataset_root/ ├── JPEGImages/ # 原始图像,jpg或png ├── Annotations/ # 每个图像对应的XML标注 ├── ImageSets/ │ └── Main/ # train.txt / val.txt / test.txt

Annotations里的每个 XML 文件与 JPEGImages 下的图片一一对应,一个典型的 XML 标注文件包含这些关键节点:

<annotation> <filename>IMG_0001.jpg</filename> <size> <width>5472</width> <height>3648</height> <depth>3</depth> </size> <object> <name>crack</name> <bndbox> <xmin>1200</xmin> <ymin>850</ymin> <xmax>1420</xmax> <ymax>910</ymax> </bndbox> </object> </annotation>

XML 里记录的是绝对像素坐标,<size>节点里的宽高是转换时必须依赖的信息。ImageSets/Main/下的 txt 文件则按行列出图片文件名(不带扩展名),用来划分训练集和验证集。VOC 格式好排查——任何坐标异常都可以直接打开 XML 看原始数值,但它有两个问题:文件冗余(一张图配一个 XML),且不直接适合当前主流检测器的输入需求。这也是为什么 YOLO 格式能成为训练侧的主流。

2.2 YOLO 格式的 .txt 标注:归一化坐标与类别索引

YOLO 系列对标注的要求非常统一:每张图片对应一个同名 .txt 文件,每一行标注一个目标,格式如下:

<class_id> <x_center> <y_center> <width> <height>

所有数值都是归一化的。以 2.1 里那组坐标为例,假设图片宽 5472、高 3648,框的左上角 (1200, 850)、右下角 (1420, 910),中心点像素坐标就是 (1310, 880),框宽 220、高 60。归一化公式:

x_center = 1310 / 5472 = 0.2394 y_center = 880 / 3648 = 0.2412 width = 220 / 5472 = 0.0402 height = 60 / 3648 = 0.0164

最终在 txt 里写入0 0.2394 0.2412 0.0402 0.0164,其中 0 是crack类别在类别列表里的索引。注意 YOLO 的坐标是中心点加宽高,不是左上角加右下角——这是从 VOC 转 YOLO 时最容易出错的点。下表把两套格式的差异做了一个直接对比:

对比项VOCYOLO
标注文件后缀.xml.txt
坐标体系绝对像素坐标归一化浮点数
坐标表达左上角 (xmin, ymin) 与右下角 (xmax, ymax)中心点 (x_center, y_center) 与宽高 (w, h)
类别表达字符串名称整数索引
训练集划分ImageSets/Main 下的 txt由目录结构隐式划分
是否依赖图片尺寸本身不依赖,但读取时需配合 size 节点必须用图片宽高做归一化

类别索引不是随便排的。如果后续准备在 YOLOv8 或者 MMDetection 上训练,那个索引顺序在整个训练和推理阶段必须全局一致。航拍路面病害数据集的 7 个类别,通常按裂缝类型和病害程度划分,不同版本的数据集类别定义会有差异,动手前先核对一遍类别清单。

2.3 用 Python 脚本把 VOC 转成 YOLO,并校验样本数

虽然很多标注工具自带导出功能,但在命令行环境下用脚本转换永远是最后一道保险。下面是通用的 VOC 转 YOLO 脚本,核心逻辑是对每个 XML 做解析、归一化、写出对应 txt:

import xml.etree.ElementTree as ET from pathlib import Path # 类别顺序必须固定,之后训练配置里的 names 要与此处保持一致 CLASSES = ["crack", "longitudinal_crack", "transverse_crack", "pothole", "patch", "alligator", "repair"] def voc_to_yolo(xml_file: Path, output_dir: Path, classes: list) -> int: tree = ET.parse(xml_file) root = tree.getroot() # VOC XML 里带了真实图片宽高,优先用它;缺失时由外部传入 size = root.find("size") img_w = int(size.find("width").text) img_h = int(size.find("height").text) lines = [] for obj in root.findall("object"): name = obj.find("name").text.strip() if name not in classes: continue # 跳过不在类别清单里的目标 cls_id = classes.index(name) bbox = obj.find("bndbox") x1 = float(bbox.find("xmin").text) y1 = float(bbox.find("ymin").text) x2 = float(bbox.find("xmax").text) y2 = float(bbox.find("ymax").text) # 防呆:裁掉越界坐标,防止训练时出现负数宽高 x1 = max(0, min(x1, img_w)) x2 = max(0, min(x2, img_w)) y1 = max(0, min(y1, img_h)) y2 = max(0, min(y2, img_h)) if x2 <= x1 or y2 <= y1: continue cx = (x1 + x2) / 2 / img_w cy = (y1 + y2) / 2 / img_h w = (x2 - x1) / img_w h = (y2 - y1) / img_h # 归一化后的值理论上在 0~1 之间,超过要警惕标注异常 if cx > 1 or cy > 1 or w > 1 or h > 1: raise ValueError(f"{xml_file.name} 中存在非法归一化坐标") lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") if not lines: return 0 output_dir.mkdir(parents=True, exist_ok=True) txt_path = output_dir / f"{xml_file.stem}.txt" txt_path.write_text("\n".join(lines) + "\n", encoding="utf-8") return len(lines) input_dir = Path("Annotations") output_dir = Path("labels") total_objects = 0 for xml_path in input_dir.glob("*.xml"): count = voc_to_yolo(xml_path, output_dir, CLASSES) total_objects += count if count == 0: print(f"警告: {xml_path.name} 没有有效目标") print(f"处理完成,共转换 {total_objects} 个目标框")

脚本里的几个点值得注意:CLASSES列表顺序直接决定 txt 里的类别索引,训练配置里的names必须与其逐位对应;max/min裁剪逻辑是为了处理标注工具偶尔产生的越界框,如果裁剪后宽高仍不为正则丢弃;最后一步数值越界检查能在数据集层面帮你抓出异常标注,避免训练时 loss 异常炸掉。转换完成后建议立即对照检查——随机挑几张原图,把 txt 里的归一化坐标还原成像素坐标画框,目视确认框是否贴合裂缝目标。这一步成本很低,但能省掉后面排错的大量时间。

3. 用 YOLOv8 在本地跑通裂缝检测训练:环境、配置与最小命令

格式转好了,接下来的标准动作是跑 YOLOv8 训练。这章按当前社区最主流的 YOLOv8 流程来,涵盖环境准备、数据集目录整理、data.yaml 写法以及启动命令,完整走一遍训练前的最后 100 米。

3.1 数据集目录组织与 YOLO 环境配置

YOLOv8 对数据集目录并不苛求固定结构,只要 data.yaml 里写对路径即可。但按社区惯例,把图片和标签分开放是最不容易出错的:

datasets/RoadCrack/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 与 images/train 同名的 .txt │ └── val/ # 与 images/val 同名的 .txt

划分比例一般取 8:2 或 9:1。3302 张图不算多,9:1 的话验证集约 330 张,对裂缝这种长尾分布的数据更合理。划分时可以用sklearn.model_selection.train_test_split,也可以直接用 shell 脚本按文件名前缀分组——关键是保证同一张图的 jpg 和 txt 进同一个集合,不要出现图片在 train、标签在 val 的错位。

环境配置上,PyTorch 2.x + CUDA 的组合是当前最省心的路径。conda 创建独立环境,注意版本对齐问题:

conda create -n roadcrack python=3.10 -y conda activate roadcrack pip install ultralytics torch torchvision --index-url https://download.pytorch.org/whl/cu121

装完后先验证 GPU 是否被正确调用。torch.cuda.is_available()返回 True 还不够,最好看一眼实际显卡型号和显存——这决定了后面 batch size 和 imgsz 能开多大。显存低于 8GB 的卡,直接放弃 imgsz=1280 的念头,老实从 640 起步。如果你是 Mac 用户,mps设备也能跑,但航拍大图场景下 CPU/GPU 的吞吐差距会非常明显,能做迁移学习的还是优先 CUDA。

3.2 data.yaml 写给航拍小目标:imgsz 和类别顺序是关键

data.yaml 是整个训练配置里最不该想当然的文件。路径写错、类别顺序与转换脚本不一致,都会在训练早期以诡异的 loss 曲线形态暴露出来。下面是一个基准配置:

# datasets/RoadCrack/data.yaml path: /absolute/path/to/datasets/RoadCrack train: images/train val: images/val nc: 7 names: 0: crack 1: longitudinal_crack 2: transverse_crack 3: pothole 4: patch 5: alligator 6: repair

path建议写绝对路径,避免相对路径在不同工作目录下引发 FileNotFoundError。names的索引顺序必须严格等于第 2 章转换脚本里的CLASSES顺序,否则类别错位会静默地发生在训练数据里——模型不会报错,只会学到一个错误的映射。这点在多人协作时尤其危险,不同人跑过不同版本的格式转换脚本后,类别顺序很容易出现漂移。

航拍路面病害的特殊性在于:裂缝是典型的小目标,在原图上可能只占几十个像素宽、几百个像素长。imgsz 直接决定这些小目标在输入分辨率下还剩多少像素。经验上,航拍道路场景 imgsz=1280 比 640 有明显提升,显存足够就优先 1280,不够则用 960 折中,但不要低于 640。数据集的 7 个类别里,如果cracklongitudinal_crack这类细长目标占多数,imgsz 带来的收益会比一般数据集更显著。

3.3 启动训练:完整命令行与关键参数语义

ultralytics 包安装完毕后,训练入口统一收敛到yolo detect train命令。一个可直接执行的最小命令如下:

yolo detect train \ data=datasets/RoadCrack/data.yaml \ model=yolov8s.pt \ epochs=100 \ imgsz=1280 \ batch=8 \ device=0 \ workers=4 \ patience=20 \ project=outputs/roadcrack \ name=exp_s_1280

逐项说明:model=yolov8s.pt表示加载 YOLOv8s 的预训练权重,COCO 上训过的特征提取器对裂缝边缘纹理的迁移效果通常好于从零训练;epochs=100是总轮数,配合patience=20实现早停——验证集 mAP 连续 20 轮不提升就自动结束,防止过拟合;batch=8在 1280 分辨率下约占 16GB 显存,如果你的卡是 12GB 建议降到 4;workers=4是数据加载线程数,Windows 上过高的 workers 容易触发 DataLoader 报错,4 到 8 是安全区间。

训练开始后不需要干等,盯两个信号即可。第一是前 20 轮的train/box_loss是否平滑下降,如果 loss 曲线在前几轮剧烈震荡且伴随 NaN,优先怀疑类别索引错位或标签文件里有空行。第二是验证集metrics/mAP50(B)是否在 30 轮左右进入上升通道。如果 mAP50 始终低于 0.3,后面第 4 章的优化手段会帮你找到瓶颈。

训练日志会同步输出预测样例图到outputs/roadcrack/exp_s_1280/,建议每 20 轮打开看一眼。注意观察裂缝的检出框是否连续——裂缝检测里最常见的失败模式是“一段断成好几截”,即模型把一整条裂缝识别成多段,mAP 看着还行,实际工程上没法用。这种情况在训练阶段就要看出来,不要拖到部署后才返工。

4. 针对道路裂缝的二阶段优化:类别不均衡、损失函数与增强策略

第一轮 baseline 跑完后,通常要面对两个现实问题:类别不均衡和长条目标的漏检。3302 张航拍图里,横向裂缝和纵向裂缝的样本量可能相差数倍;而repair(修补带)这种类别往往样本较少,直接导致 mAP 被稀有的类别拖低。这一章给出三个行之有效的迭代方向。

4.1 先用混淆矩阵定位漏检类别:从结果反推数据缺口

YOLOv8 训练结束后,验证集上会输出confusion_matrix.png。别急着看整体 mAP,先看对角线之外的高频错误落在哪里。常见模式有两种:一是crack被频繁预测成transverse_crack——说明这两个类别在视觉上高度相似,标注边界本身存在模糊地带;二是某个少数类别(比如alligator龟裂)几乎不出现在预测结果里——典型的样本不足或标注不一致。

处理方式分两步。先看类别分布:

# 统计每个类别的目标框数量 cat datasets/RoadCrack/labels/train/*.txt | awk '{print $1}' | sort | uniq -c | sort -rn
from collections import Counter from pathlib import Path counter = Counter() label_root = Path("datasets/RoadCrack/labels/train") for txt in label_root.glob("*.txt"): for line in txt.read_text().strip().splitlines(): cls_id = int(line.split()[0]) counter[cls_id] += 1 total = sum(counter.values()) for cls_id, cnt in sorted(counter.items()): print(f"类别 {cls_id}: {cnt} 个框, 占比 {cnt / total:.1%}")

多数情况下会发现头部类别占 50% 以上,尾部几个类别加起来不到 10%。这时再回看混淆矩阵,确认是不是尾部类别贡献了主要漏检。如果是,优先做的不是加数据,而是检查尾部类别的标注质量——航拍图的标注错误率其实不低,常见问题是遮挡处漏标、裂缝断点处误标为两条。

4.2 类别权重配置与 YOLO 损失函数层面的调整思路

YOLOv8 默认的损失函数是分类损失(BCE)+ 回归损失(CIoU)+ 分布焦点损失(DFL)的组合。它没有内置的类别权重参数,但有两个间接手段可以影响少数类的训练强度。第一个是过采样少数类样本:把alligatorrepair这类占比极低的图片在训练目录里重复几次再启动训练。第二个是从数据增强角度增加少数类出现的频率,比如针对包含尾部类别的图片提高 mosaic 参与度。

如果不想改数据,可以换model=yolov8s-seg.pt用分割头来训练——裂缝这种细长目标的掩码标注比矩形框更贴合真实形状,但前提是你的标注里有 polygon 信息。VOC 格式的 XML 中bndbox只存矩形框,所以这个方案对当前数据集不一定适用。

一个更直接的调整是修改损失函数权重,Ultralytics 在loss.py里通过hyp['cls']hyp['box']控制各项损失的缩放。在ultralytics/cfg/default.yaml里可以覆盖:

# 假设你想加大分类损失的权重 cls: 0.8 # 默认 0.5,提高后模型对类别判别的惩罚更强 box: 7.5 # 默认 7.5,回归损失权重不变

动手前先想清楚:加大cls会压制误分类,但同时会让模型对难样本的预测更保守;如果问题本质是标注噪声,调大 cls 只会让模型在噪声边界上过拟合。所以权重调整应该在数据检查之后做,而不是之前。

4.3 关闭 Mosaic 的时机:航拍大图与小目标的增强博弈

YOLOv8 默认在训练最后 10 个 epoch 会自动关闭 Mosaic 增强,目的是让模型在接近真实分布的输入上精调。但航拍裂缝场景里,Mosaic 从第 0 轮起就可能帮倒忙:四张图拼在一起后,原本就细的裂缝被缩放到原来的 1/4,目标有效像素进一步减少,梯度信号变弱。

常见做法是在训练结束后用关闭 Mosaic 的方式再续跑少量 epoch,即两阶段训练。第一步正常训练 100 轮,第二步加载 best.pt,用关闭增强倍率的方式再训 20~30 轮作为精调。命令行可以这样组合:

yolo detect train \ data=datasets/RoadCrack/data.yaml \ model=outputs/roadcrack/exp_s_1280/weights/best.pt \ epochs=30 \ imgsz=1280 \ batch=8 \ mosaic=0.0 \ close_mosaic=0 \ name=exp_s_1280_refine

mosaic=0.0在主配置里直接关闭拼接增强,close_mosaic=0用于禁用训练管线中“最后 N 轮自动关闭”的逻辑(否则它可能在训练中途重新打开)。这一步通常能带来 2~3 个点的 mAP50 提升,并且会让裂缝框的连续性明显变好。如果你的验证结果显示裂缝三段断框,多试这个方案,大多数情况下比换更大的模型更有效。

下表总结了三种增强策略在裂缝场景下的适用性判断,方便你在第二版实验里快速做选择:

策略适用场景不适用场景
开启 Mosaic(默认)常规目标检测、整体类别均衡细长小目标占比高的航拍裂缝数据集
关闭 Mosaic 精调模型已有一定收敛,追求框连续性训练前 30 轮内
旋转/翻转增强裂缝方向分布多样(横向、纵向、斜向)定向裂缝检测(如只检横向裂缝)

5. 裂缝检测模型的下游应用:大图切片推理与数据集完整性核验

模型训练收敛只是中点,航拍实战中的难点是把模型用在大尺寸正射影像或拼接图上。这章的三个技巧分别对应推理效率、数据资产管理和结果输出。

5.1 大图切片推理:把 5472×3648 的航拍图切成可推理的窗口

常见的航拍原图分辨率动辄数千万像素,直接缩放后输入模型会让裂缝变成一两个像素的线,再强的模型也救不回来。主流解法是滑窗推理——把大图按固定步长切成若干个 1280×1280 的 patch,分别推理后再合并结果。切图时让相邻 patch 保留 20% 的重叠率,避免裂缝恰好横跨切缝被截断:

import cv2 import numpy as np from ultralytics import YOLO model = YOLO("outputs/roadcrack/exp_s_1280_refine/weights/best.pt") img = cv2.imread("drone_shot_001.jpg") H, W = img.shape[:2] patch_size = 1280 overlap = 256 step = patch_size - overlap detections = [] for y in range(0, H, step): for x in range(0, W, step): x2 = min(x + patch_size, W) y2 = min(y + patch_size, H) patch = img[y:y2, x:x2] results = model(patch, imgsz=1280, conf=0.25, verbose=False) for box in results[0].boxes.data.cpu().numpy(): px1, py1, px2, py2, conf, cls_id = box # 把 patch 坐标还原到原图坐标 detections.append((x + px1, y + py1, x + px2, y + py2, float(conf), int(cls_id))) print(f"共检测到 {len(detections)} 个目标")

这里最关键的是坐标还原:patch 的像素坐标加上该 patch 在整张图中的偏移量,才是目标在全图上的真实位置。重叠区域里的同一个目标可能被检测两次,后处理时用非极大值抑制(NMS)按 IoU 合并即可,conf=0.25的阈值可以根据现场误报率多试几档,航拍场景 0.25 到 0.35 之间通常是误报与漏检的甜点区。

5.2 用 7z 校验命令确认数据集完整,避免训练到一半报错

.7z 压缩包在传输和解压时偶发损坏,而训练时的报错不一定直指某个文件损坏。解压前先做完整性校验:

7z t 航拍路面病害检测道路裂缝检测数据集VOC+YOLO格式3302张7类别.7z

7z t会逐个文件计算校验和。全部通过后再用7z x解压。解压后做两层核对:一是文件数量,JPEGImages 下应有 3302 张图片,Annotations 下应有 3302 个 XML;二是图片与 XML 的 basename 一一对应,用以下命令找出来:

ls -1 JPEGImages | sed 's/\.[^.]*$//' | sort > /tmp/imgs.txt ls -1 Annotations | sed 's/\.[^.]*$//' | sort > /tmp/xmls.txt comm -3 /tmp/imgs.txt /tmp/xmls.txt

comm -3输出只在其中一个文件中出现的行,任何输出都说明有文件缺失或命名不一致。这类问题越早发现成本越低,训练跑到第 20 轮才发现 label 对不上图是最坏的剧本。

5.3 结果输出的工程化:裂缝框坐标反算到 WGS84 经纬度

航拍病害检测的最终交付物往往是一张带地理坐标的病害分布表。正射影像如果带 GeoInfo,可以通过 TIFF 的世界文件(.tfw)或内嵌地理标签完成像素坐标到地理坐标的转换。一般做法是读取图片的世界文件,拿到六个仿射变换参数:

A, D, B, E, C, F

其中x_geo = A * x_pixel + B * y_pixel + Cy_geo = D * x_pixel + E * y_pixel + F。把 5.1 里反算出的原图像素坐标再代入这个公式,就能得到每个病害框的经纬度或投影坐标。输出成一个 CSV,交给养护部门直接用 GIS 软件加载:

longitude,latitude,class,confidence,width_m,height_m 116.3912,39.9071,pothole,0.92,0.45,0.38

如果数据来源没有精确的 POS 信息,至少把像素坐标和航高记录到结果文件里,后续做面积估算时航高和相机焦距是换算地面尺寸的必要输入。数据集本身给到 3302 张图,价值在于把模型这半边跑通,而真正能形成闭环的是把检测结果落到地理坐标上——那才是道路养护系统里会被真实调用的数据。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 1:54:15

Linux权限管理详解:从rwx到ACL,彻底搞懂权限模型与排查技巧

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/10 1:54:12

Next.js + LangChain.js:前端工程师的AI工程化实战路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/10 1:52:30

IMM-UKF三维目标跟踪:解决模型不确定性与非线性观测

简介&#xff1a;本资源是一套基于MATLAB实现的三维目标路径预测与跟踪仿真代码&#xff0c;面向控制工程、导航定位及智能感知领域的研究者与高年级本科生&#xff0c;解决非线性、多运动模态下动态目标实时估计精度低的问题。代码融合交互式多模型&#xff08;IMM&#xff09…

作者头像 李华
网站建设 2026/9/10 1:52:09

Malware Analysis Report

Malware Analysis Report 【免费下载链接】agents Multi-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity 项目地址: https://gitcode.com/GitHub_Trending/agents24/agents Executive Summary …

作者头像 李华