news 2026/9/28 15:42:54

中草药YOLO目标检测:数据集划分、标注与可视化避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
中草药YOLO目标检测:数据集划分、标注与可视化避坑指南

简介:面向目标检测与YOLO模型训练的中草药图像数据集,适合初学者或研究者快速上手YOLOv5。数据按YOLOv5文件夹结构保存,标注为类别加中心点坐标与宽高的相对坐标,共8个类别(如Cardamom、Cumin、Neem等),并划分训练、验证、测试集:训练集约2600张,验证集约190张,测试集约100张,可直接用于训练与评估。资源共2000个文件,主体为1999个txt标注文件与1个Python可视化脚本,压缩包约209.51MB;txt对应图片标注,脚本可随机读取图片绘制边界框并保存,无需修改即可运行。目前已有1000余人学习下载。配套提供类别class文件,目录清晰,省去自行清洗划分时间,适合作为中草药目标检测起步数据或YOLO练习。

1. 中草药目标检测,先别急着训练:数据集才是第一道坎

做中草药图像目标检测,绝大多数人上手第一件事就是找模型、调参、跑训练,结果折腾半天发现 AP 值惨不忍睹,回头查数据才发现标注错位、类别索引混乱、训练集和验证集互相“串门”。真正的瓶颈不在 YOLO 的网络结构,而在喂给 YOLO 的数据集本身。这个项目标题其实给了完整的答案:一份划分好的中草药图像数据集、一个类别 class 文件、一套数据可视化脚本。它要解决的不是“怎么把模型训出来”,而是“怎么把数据准备成 YOLO 真正能吃的样子,并且在训练之前就把烂数据揪出来”。适合正在用 YOLOv5/v8 做中草药识别、刚拿到一批药材照片不知道怎么组织成数据集、或者训练出来 AP 忽高忽低找不到原因的从业者。

2. 把中草药照片变成 YOLO 能吃的格式:目录结构与坐标换算

2.1 YOLO 标签的四字段含义与坐标归一化计算

YOLO 系列(v5/v8 都一样)不认常见的 x1y1x2y2 绝对像素坐标,而是要求归一化后的中心点坐标加宽高。每一行对应一个目标实例,结构是:class_id x_center y_center width height。class_id 是类别索引,从 0 开始,对应 class 文件里的行号;x_center 和 y_center 是目标中心点相对图片宽高的比例;width 和 height 是目标框宽高相对图片宽高的比例,全部归一化到 0~1 之间。

为什么要归一化?因为中草药数据集的照片分辨率差异极大——微距特写可能是 6000×4000,手机随手拍是 1920×1080,如果不归一化,模型预处理时就要为每种分辨率重新缩放,而归一化之后模型完全不关心输入图片的绝对像素值。一个具体的例子:一张 1920×1080 的甘草叶片照片,人工标注框左上角在 (960, 540)、右下角在 (1440, 810),中心就是 (1200, 675),框宽 480、高 270,归一化后得到:

0 0.625 0.625 0.25 0.25

换算公式本身很简单,从绝对坐标到归一化坐标:

x_center = (x1 + x2) / 2 / image_width y_center = (y1 + y2) / 2 / image_height width = (x2 - x1) / image_width height = (y2 - y1) / image_height

反向换回像素坐标,在可视化脚本里会用到:

x1 = int((x_center - width / 2) * image_width) y1 = int((y_center - height / 2) * image_height) x2 = int((x_center + width / 2) * image_width) y2 = int((y_center + height / 2) * image_height)

这块的坑主要在三点:一是直接用整数坐标算中心点,会造成 1~2 像素的误差,对中草药里大量小目标(枸杞干果、金银花单朵)是能感知到的;二是忘了除以图片宽高,标签里出现大于 1 的值,训练时边框计算直接乱套;三是坐标顺序写反,把 x_center 写成了 y_center,可视化时所有框全部方向错乱。我一般会在新建数据集时先写一个扫描脚本,检查所有标签文件的数值范围:合法的 x_center、y_center、width、height 必须在 0 到 1 之间,越界的直接打印路径,人工确认后再继续。

2.2 划分好的数据集:images 与 labels 双目录结构与文件命名对齐

一个规范的、划分好的中草药 YOLO 数据集,目录结构通常长这样:

chinese_herb_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── classes.txt └── data.yaml

这种 images/labels 双目录结构是 YOLO 系列的默认约定,不是个人习惯。训练时 YOLO 会根据 data.yaml 里指定的图片路径,自动在同级目录下找 labels 目录,图片在 images/train 里,标签就默认在 labels/train 里,不能自己乱放。

data.yaml 是划分配置的入口,YOLOv8 加载数据集时读的就是它:

train: ./chinese_herb_dataset/images/train val: ./chinese_herb_dataset/images/val test: ./chinese_herb_dataset/images/test nc: 5 names: ['gancao', 'gouqi', 'jinyinhua', 'dangshen', 'huangqi']

这里有个高频坑:train 路径写成相对路径时,一旦训练脚本里改动过工作目录,路径解析就会失败,直接报 FileNotFoundError。我习惯在 data.yaml 里写绝对路径,换机器时多改几个字符串,但排错时间省下来远高于这点麻烦。

文件命名有一条硬规则:图片和标签的主文件名必须完全一致,只是扩展名不同。比如 images/train/gancao_001.jpg 对应 labels/train/gancao_001.txt。如果标注工具导出时命名规则不一致,YOLO 训练不会报错,只会静默忽略那张没有标签的图,你的训练数据量会在不知不觉中缩水。这是个很阴的问题,因为很多人看数据没报错就以为没问题,直到训练完才发现某类别的 AP 起不来。

“划分好的数据集”从代码上看就是一次 shuffle 加三分。下面这个脚本把一个目录下的图片和对应标注按 8:1:1 分成训练、验证、测试三份:

import os import random import shutil random.seed(2024) # 固定随机种子,保证划分结果可复现 src_images = "raw_images" # 原始图片目录 src_labels = "raw_labels" # 原始标签目录(YOLO格式) dst_root = "chinese_herb_dataset" train_ratio, val_ratio = 0.8, 0.1 image_files = [f for f in os.listdir(src_images) if f.lower().endswith(('.jpg', '.png', '.jpeg'))] random.shuffle(image_files) n = len(image_files) n_train = int(n * train_ratio) n_val = int(n * val_ratio) splits = { "train": image_files[:n_train], "val": image_files[n_train:n_train + n_val], "test": image_files[n_train + n_val:] } for split_name, files in splits.items(): os.makedirs(os.path.join(dst_root, "images", split_name), exist_ok=True) os.makedirs(os.path.join(dst_root, "labels", split_name), exist_ok=True) for fname in files: stem = os.path.splitext(fname)[0] src_img = os.path.join(src_images, fname) src_lbl = os.path.join(src_labels, stem + ".txt") shutil.copy(src_img, os.path.join(dst_root, "images", split_name, fname)) if os.path.exists(src_lbl): shutil.copy(src_lbl, os.path.join(dst_root, "labels", split_name, stem + ".txt")) else: print(f"[警告] {fname} 缺少对应标签文件")

逻辑说明:先读全部图片文件名,固定随机种子后 shuffle,避免每次运行得到不同划分;再按比例切出三个文件列表;最后逐个把图片和同名标签复制到目标目录。缺失标签时打印警告但不中断运行,方便回头统计漏标情况。

参数说明:train_ratio=0.8、val_ratio=0.1,测试集自动取剩余的 0.1。如果总样本数小于 300,建议改成 0.7/0.15/0.15,因为验证集太小会导致 mAP 波动很大,同一份代码跑两遍结果差异明显。另外注意这里用的是shutil.copy,也就是复制而不是移动文件——保留原始目录这个习惯非常重要。后续要是发现划分有问题,随时可以重新切,不用后悔。

3. 类别 class 文件与数据集划分比例:参数怎么设才不翻车

3.1 class 文件一行一个类名:顺序决定训练索引,别乱排

classes.txt 就是标题里说的“类别 class 文件”,每行一个类别名。比如:

gancao gouqi jinyinhua dangshen huangqi

关键规则是:每一行的行号就是训练时这个类别对应的整数索引,第一行是 0,第二行是 1,依此类推。标签文件里每行开头的数字就是这个索引。说得直接点,classes.txt 的排列顺序直接决定了所有标签文件中数字的语义。

这意味着什么?如果你中途改了 classes.txt 的顺序,比如把 jinyinhua 从第三行提到第一行,那么所有标注成 2 的标签在训练时都会变成 gancao,整个模型的类别输出彻底错位。典型翻车场景是:数据集做到一半发现少了一个类别,随手往末尾补一行,或者为了看着整齐按拼音排序了一下,结果所有标签索引全部作废。

一个保守但有效的习惯:class 文件从建立第一天就定死,后期新增类别只往末尾追加,绝对不去动已有行的顺序。另外,classes.txt 里的类别名尽量用拼音或英文,不要用中文。不是说 YOLO 不支持中文类别名,而是后续可视化脚本、评估脚本对中文的编码处理不一致,同一个名字在 Windows 命令行和 Linux 终端下显示完全不同,排查起来非常费劲。

如果你用 YOLOv8,也可以不在单独文件里写类别,直接在 data.yaml 的 names 字段定义:

names: 0: gancao 1: gouqi 2: jinyinhua 3: dangshen 4: huangqi

但单独交付 classes.txt 有一个不可替代的好处:标注工具(LabelImg、CVAT、labelme)可以直接加载这个文件作为预定义类别列表,标注员不需要手动输入类别名,从根源上避免类别拼写不一致。而且很多开源目标检测项目只认 classes.txt、不认 data.yaml,两个文件都准备好,兼容性最好。

3.2 训练/验证/测试划分:按比例随机还是按采集批次分

第 2 章的划分脚本是纯随机 shuffle,适合单一批次采集、光照和背景差异不大的场景。但中草药数据集有个特点:图片往往来自多个批次。比如一批在晴天户外拍,光照充足;一批在室内补光灯下拍,背景是黑板;一批用手机随手拍,分辨率低、画面模糊。如果纯随机划分,同一株药材的不同角度照片可能同时出现在训练集和验证集里,评估结果虚高——模型不是在泛化,而是在“背答案”。

更稳的划分方式是按采集批次分组。假设你的原始数据按批次文件夹组织,每个文件夹内部是一个拍摄批次,那划分策略就变成了选哪些批次进训练集、哪些批次进验证集:

import os import shutil batch_root = "herb_batches" # 子文件夹代表不同采集批次 dst_root = "chinese_herb_dataset" train_batches = ["batch_01", "batch_02", "batch_03", "batch_04"] val_batches = ["batch_05"] test_batches = ["batch_06"] for split_name, batches in [("train", train_batches), ("val", val_batches), ("test", test_batches)]: os.makedirs(os.path.join(dst_root, "images", split_name), exist_ok=True) os.makedirs(os.path.join(dst_root, "labels", split_name), exist_ok=True) for batch in batches: batch_img_dir = os.path.join(batch_root, batch, "images") batch_lbl_dir = os.path.join(batch_root, batch, "labels") for fname in os.listdir(batch_img_dir): stem = os.path.splitext(fname)[0] src_img = os.path.join(batch_img_dir, fname) src_lbl = os.path.join(batch_lbl_dir, stem + ".txt") dst_img = os.path.join(dst_root, "images", split_name, fname) dst_lbl = os.path.join(dst_root, "labels", split_name, stem + ".txt") shutil.copy(src_img, dst_img) if os.path.exists(src_lbl): shutil.copy(src_lbl, dst_lbl) else: print(f"[警告] {batch}/{fname} 缺少标签")

逻辑说明:脚本不做任何随机打乱,直接把指定的批次文件夹整体复制到对应的划分目录。每次运行结果完全一致,可复现性比随机划分好很多。因为代码里不会产生随机数,也就不存在设不设 seed 的问题。

参数说明:train_batches、val_batches、test_batches 的分组完全凭业务判断。我的经验是把光照最刁钻(强逆光、弱光)和背景最杂乱(地面、树叶缝隙)的批次放到验证集和测试集,训练集只保留条件相对正常的批次。原因是让模型先学会把类别的共性特征抓住,再去面对恶劣条件,训练损失曲线会平滑很多;反过来如果训练集全是恶劣光照,模型会花大量迭代去学光照不变性,而不是学药材本身的纹理和形状特征。

如果你只是想快速验证流程通不通,随机划分就够了;等流程跑通,再按批次重新划分一次做正式训练。这个先后顺序不冲突,用随机划分出的模型 mAP 只能作为参考,不能作为最终结论。

4. 数据可视化脚本:把每张图的标注画出来,一眼看出问题

4.1 用 OpenCV 把 YOLO 标签画回原图:脚本逻辑与参数说明

光看数字标签发现不了问题,必须把标注框可视化到原图上。这段脚本是我拿到任何新数据集时必跑的第一段代码,它读入图片和同名的 YOLO 标签,反向换算坐标后用 OpenCV 绘制矩形框和类别名称,输出到 vis_output 目录:

import cv2 import os VIS_DIR = "vis_output" IMG_DIR = "chinese_herb_dataset/images/train" LBL_DIR = "chinese_herb_dataset/labels/train" class_names = ["gancao", "gouqi", "jinyinhua", "dangshen", "huangqi"] os.makedirs(VIS_DIR, exist_ok=True) green = (0, 255, 0) # BGR 颜色,绿色框 red = (0, 0, 255) # BGR 颜色,红色文字 for img_name in os.listdir(IMG_DIR): if not img_name.lower().endswith(('.jpg', '.png', '.jpeg')): continue stem = os.path.splitext(img_name)[0] img_path = os.path.join(IMG_DIR, img_name) lbl_path = os.path.join(LBL_DIR, stem + ".txt") img = cv2.imread(img_path) if img is None: print(f"[跳过] 图片无法读取: {img_path}") continue h, w = img.shape[:2] if not os.path.exists(lbl_path): print(f"[警告] 无标签文件: {lbl_path}") continue with open(lbl_path, "r") as f: for line in f: parts = line.strip().split() if len(parts) != 5: print(f"[警告] 非法标签行 {lbl_path}: {line.strip()}") continue cls_id = int(parts[0]) x_center = float(parts[1]) y_center = float(parts[2]) bw = float(parts[3]) bh = float(parts[4]) x1 = int((x_center - bw / 2) * w) y1 = int((y_center - bh / 2) * h) x2 = int((x_center + bw / 2) * w) y2 = int((y_center + bh / 2) * h) x1 = max(0, x1); y1 = max(0, y1) x2 = min(w - 1, x2); y2 = min(h - 1, y2) cv2.rectangle(img, (x1, y1), (x2, y2), green, 2) label_text = class_names[cls_id] if cls_id < len(class_names) else f"cls_{cls_id}" cv2.putText(img, label_text, (x1, max(y1 - 5, 15)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, red, 2) cv2.imwrite(os.path.join(VIS_DIR, img_name), img) print("全部可视化完成,输出目录:", VIS_DIR)

逻辑说明:脚本遍历 IMG_DIR 下所有图片,对每张图执行读图、读标签、按行解析、反向归一化、画框、写字、输出。反向坐标换算必须放在画框之前,因为 YOLO 标签里是 0 到 1 的浮点数,OpenCV 必须在像素坐标系上画图。边界裁剪用 max/min 函数把坐标限制在图片范围内,防止标注框超出图像区域导致 cv2.rectangle 崩溃。len(parts) != 5的校验用来拦截空行、多余空格、tab 混用等脏行。

参数说明:颜色是 BGR 顺序,不是 RGB,green=(0, 255, 0) 表示纯绿,你要是把 RGB 的绿色直接传进去,画出来是蓝色。max(y1 - 5, 15)防止类别文字画到图片上边缘之外被截断。字体大小 0.6、线宽 2 适用于 1000 到 3000 像素分辨率的图片,更大分辨率需要按比例放大,后面单独说。

提示:如果你发现某个类别的框在可视化结果里总是明显偏大,先检查这个类别的标注规范是不是和其他类别不一致,比如把整株药材当成一个框、而不是按叶片或果实分别框选。这种情况在多人协作标注时很常见,属于“标注粒度不一致”,不是脚本问题。

4.2 可视化图里常见的三类异常:错框、漏标、类别串位

跑完可视化后,不要急着关掉输出目录,按类别翻一遍图,重点看三类异常。

错框最容易发现:框把背景圈进去了,或者只框住了药材的一半。中草药是非刚性目标,枸杞枝条是弯曲的,金银花一簇有好几朵,矩形框天然无法完美贴合,标注时要做取舍。我的原则是框宁可大一点,也不要漏掉药材边缘,因为 YOLO 靠中心点和回归框定位,中心点偏了远比框大一点影响大。

漏标就是图片里明显有一朵金银花或一颗枸杞干果,但可视化图上没有对应的框。只能回到标注工具里补标,没有捷径。但有个排查技巧:把漏标图按拍摄批次分组,如果集中在某个批次,八成是标注员后半程疲劳了;如果分散在各批次,可能是标注规范没讲清楚,大家对“什么算一个目标”的理解不一致。

类别串位是指框的位置正确,但旁边的文字对不上,比如框里明明是枸杞却写着 gancao。先检查脚本里的 class_names 和 classes.txt 的顺序是否一致,多数是脚本顺序写错了;脚本没问题,那就是标注时选错了类别,需要单独改标签文件里那一行的类别索引。这里要特别提醒:改标签索引之前先备份,改错了还有后悔药,改完了再跑一遍可视化确认,别改个寂寞。

5. 中草药数据集避坑:从标注到划分的五个常见问题

5.1 现象:训练时报错“Label class X exceeds nc=Y”

训练 YOLO 时控制台直接报一个Label class 5 exceeds nc=5,训练中断。

原因:标签文件里出现了索引为 5 的类别,但 data.yaml 里配置的 nc=5,合法索引是 0 到 4。这通常是标注工具的类别列表和 classes.txt 不一致,标注时多选了一个类别;或者某次清理时删掉了 classes.txt 里的一行,却没有去同步已经标好的标签。

解决:先写一个脚本遍历全部标签文件,统计出现过的类别索引集合,和 range(nc) 比对。发现越界索引时,定位到具体标签文件,人工核对是标注错还是样本不该保留,再决定改索引还是删文件。绝对不要批量把 5 改成 4,那会把两种不同的药材混成同一个类别,后续模型怎么训都分不开。

5.2 现象:可视化脚本运行到一半报“assertion failed”

cv2.rectangle 报assertion failed (width > 0 && height > 0),脚本中断在某一张图片上。

原因:某个标签文件里 width 或 height 为 0,或者反向换算后 x2 <= x1、y2 <= y1。这通常是标注工具对极小目标误操作,或者有人手动编辑了标签文件,把坐标改成了同一个值。中草药里小目标特别多——枸杞干果在整张照片里可能只有二三十像素,容易出现这种精度问题。

解决:在可视化脚本里增加面积过滤,反向换算后如果宽度或高度小于等于 0,跳过这个框并打印警告。同时建议在数据预处理阶段就删除这类无效行,因为零面积框的 loss 计算没有意义,留着只会让训练过程产生 NaN。

5.3 现象:训练集 mAP 很高,但验证集 mAP 塌方

训练集 mAP 超过 90%,验证集 mAP 只有 50% 多,差距大得离谱。

原因:大概率是划分策略错了。纯随机 shuffle 时,同一采集批次的同源图片被分到训练集和验证集,验证集 mAP 虚高;反过来如果验证集塌方,通常是某个较难的批次被整体放进了验证集,而训练集完全没见过这种光照和背景,模型的泛化能力在验证集上被真实地暴露出来。

解决:先按采集批次重做划分,让验证集覆盖尽可能多样的条件。如果重划分后还是低,就去检查验证集的可视化图,确认标注框质量和类别分布。排除掉数据问题之后,才轮得上去调模型参数。很多人一上来就调学习率、改网络结构,结果根子在数据划分上,白忙一场。

5.4 现象:数据可视化图上看不清小目标标注

可视化输出图上,枸杞干果的框线太细看不清,多个框重叠之后根本分不清对应关系。

原因:画框线宽固定为 2 像素、字号固定为 0.6,而图片分辨率可能高达 4000×3000,小目标框只有几十像素,整图缩略显示时框线几乎不可见。这不算数据集坏掉,是可视化参数不适配高分辨率图片。

解决:让线宽跟着图片尺寸走,一行代码的事:cv2.rectangle(..., max(2, round(min(h, w) // 500)), ...)。字号同理按max(0.6, min(h, w) / 2000)调整。输出图保存一份缩略版,按 1200px 宽度等比缩放,方便快速扫全图。如果看完一轮还是觉得不清楚,按类别分目录输出,一次只看一个类别的标注分布。

5.5 现象:同一种药材在 class 文件里出现两种写法

统计类别分布时,发现实际类别数比预期多,比如 “gouqi” 和 “gouqi_gan” 其实是同一种枸杞,被当成了两个类。

原因:多人协作标注时,标注工具没有加载预定义的 classes.txt,标注员各自按自己的习惯手动输入类别名。这在团队项目里几乎一定会发生,越是对命名不熟悉的药材越容易出问题。

解决:先从标注工具端强制加载统一的 classes.txt,禁止自由输入。已经标完的数据,用脚本扫描全部标签文件,统计出现的类别索引集合,把多余索引统一成标准类的合法索引。做这个操作前先整体备份 labels 目录,改错了可以快速回滚,别在原始数据上反复横跳。

6. 最后一道防线:训练前跑一个数据体检脚本

数据集的体检脚本,是我每次训练前必跑的最后一段代码。它不画图,只统计四个关键数字:每类的样本数、每张图的平均标注框数、标注框的宽高分布、图片分辨率分布。这四个数字基本决定了 YOLO 训练会不会在早期就出幺蛾子。

import os from collections import Counter IMG_DIR = "chinese_herb_dataset/images/train" LBL_DIR = "chinese_herb_dataset/labels/train" class_names = ["gancao", "gouqi", "jinyinhua", "dangshen", "huangqi"] cls_counter = Counter() box_per_img = [] for img_name in os.listdir(IMG_DIR): stem = os.path.splitext(img_name)[0] lbl_path = os.path.join(LBL_DIR, stem + ".txt") if not os.path.exists(lbl_path): continue with open(lbl_path) as f: lines = f.readlines() box_per_img.append(len(lines)) for line in lines: parts = line.strip().split() if len(parts) == 5: cls_counter[int(parts[0])] += 1 print("类别分布:", dict(cls_counter)) if box_per_img: print("平均每图框数:", sum(box_per_img) / len(box_per_img)) print("最大单图框数:", max(box_per_img))

逻辑说明:cls_counter 统计每个类别出现的总次数,直接暴露类别失衡。box_per_img 按图统计框数,能发现异常图——比如某张图有 200 个框而平均只有 5 个,说明这张图把整片药材都框了一遍,模型容易学偏。最后把统计结果打印出来,和自己建数据集时的预期对比。

参数说明:阈值全凭经验。我的个人标准是:单类别框数少于 300,这个类别的 AP 基本不用指望;平均每图框数超过 20,说明要么目标太密集、要么标注粒度太粗,需要重新审视标注策略;最大单图框数超过平均值的 5 倍,需要把那几张图单独拿出来人工核对。

体检跑完再决定要不要训练。这个习惯帮我躲过了大量白训的坑——很多训练完才暴露的脏数据问题,在训练前跑一遍体检就能拦住一大半。希望这些经验对正在准备中草药数据集的你有实实在在的帮助。

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

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

STM32接OV5640摄像头:MIPI与DVP接口选型及HAL库调试实战

做嵌入式这几年&#xff0c;凡是碰到“摄像头采集”需求的项目&#xff0c;十个有八个最后都会绕到OV5640这颗 sensor 上。原因很简单&#xff1a;便宜、好买、资料多、输出格式全&#xff0c;从720p到1080p、从RAW到YUV再到JPEG&#xff0c;一颗芯片全包了。但正因为用的人多&…

作者头像 李华
网站建设 2026/9/28 15:39:57

AI生成CAD图纸的工程落地断层与约束翻译方法

1. 这不是技术不行&#xff0c;是工程逻辑断层了“AI CAD”这四个字&#xff0c;过去两年在工业软件圈里像被反复摇晃的汽水瓶——一打开就喷&#xff0c;全是泡沫。你刷到过多少次“5分钟用大模型生成完整机械装配图”的Demo&#xff1f;点进去&#xff0c;视频里鼠标轻点&am…

作者头像 李华
网站建设 2026/9/28 15:38:53

本地图库语义搜索:从向量化原理到FAISS检索的完整落地实践

1. 项目概述与核心需求拆解1.1 从“记得文件名”到“记住画面”&#xff0c;本地搜图这件事彻底换了玩法不知道你有没有经历过这种场景&#xff1a;硬盘里囤了好几年的照片&#xff0c;从手机导出的、相机备份的、朋友传来的&#xff0c;七零八落散在好几个文件夹里。某天写稿、…

作者头像 李华
网站建设 2026/9/28 15:38:32

基于CNN与NSL-KDD的网络入侵检测实战:从预处理到模型训练

简介&#xff1a;这份Python毕业设计项目围绕基于CNN卷积神经网络的网络入侵检测展开&#xff0c;源码与全部配套数据一并打包&#xff0c;属于经导师指导的高分毕业设计&#xff08;评审98分&#xff09;&#xff0c;适合计算机相关专业学生完成课程设计、期末大作业或毕业设计…

作者头像 李华
网站建设 2026/9/28 15:38:30

OpenCV车牌识别实战:从图像预处理到SVM字符分类完整链路

简介&#xff1a;本资源是一套基于Python与OpenCV实现的完整车牌识别系统源码及配套数据集&#xff0c;面向计算机视觉初学者、图像处理课程实践者及智能交通方向项目开发者&#xff0c;解决真实场景下车牌定位、字符分割与识别等核心问题。压缩包共30个文件&#xff0c;包含16…

作者头像 李华
网站建设 2026/9/28 15:38:29

VOC转YOLO数据格式转换全指南:从XML解析到归一化坐标

简介&#xff1a;本资源是专为YOLO目标检测模型训练优化的车辆&#xff08;car&#xff09;类别精简数据集&#xff0c;面向计算机视觉初学者、算法工程师及智能交通系统开发者&#xff0c;解决车辆检测模型训练数据构建与验证难题。数据集基于PASCAL VOC 2012训练验证集筛选重…

作者头像 李华