# object-detection **Repository Path**: whu-esdc/object-detection ## Basic Information - **Project Name**: object-detection - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-03-25 - **Last Updated**: 2025-03-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 目标识别 目标识别是一种基于定位和分类的任务,目标识别任务的主要目标是寻找图片中目标的位置并且判断该目标是什么物体。 本项目的目标识别任务包括了识别**红绿灯**、**禁行路标**、**限速路标**、**停车路标**等,目标识别的网络采用YOLO系列,基于darknet项目进行的。 # 模型选择 用于目标识别的模型采用YOLO系列进行 # 1、数据集制作 ## 数据集采集 数据集包括红绿灯、禁行标志、限速标志、停车标志等,需要将拍摄的图像按照文件夹进行如下分类,便于后续处理 ```bash . └─dataset-traffic ├─parking ├─person ├─stop ├─trafficLight └─... ``` ## 数据集标注 数据集的标注采用 LabelImg 对图像中的目标进行标注。 LabelImg 是图形图像注释工具。它是用 Python 编写的,并将 Qt 用于其图形界面。批注以 **PASCAL VOC** 格式(ImageNet 使用的格式)另存为 `.xml` 文件。此外,它还支持 YOLO 格式。 ### labelImg 安装 - Github 上的 [labelImg 源码](https://github.com/tzutalin/labelImg) 编译 (Python 3+pyQt5) ```bash sudo apt-get install pyqt5-dev-tools sudo pip3 install -r requirements/requirements-linux-python3.txt make qt5py3 # python3 labelImg.py python3 labelImg.py [IMAGE_PATH] [PRE-DEFINED CLASS FILE] ``` - pip安装 (推荐) ```bash pip install labelImg # start labelImg ``` ### labelImg 使用 在 Ubuntu 下启动后的界面如下(Windows 版本可能略有差异) ![start](img/labelImg-start.png) - 打开文件 : 标注单张图像(不推荐使用) - **打开目录** : 打开数据集存放的目录,目录下应该是图像的位置 - **改变存放目录**: 标注文件 `.xml` 存放的目录 - 下一个图片: - 上一个图像: - **验证图像**: 验证标记无误,用于全部数据集标记完成后的检查工作 - **保存**: 保存标记结果,快捷键 `Ctrl+s` - **数据集格式**: `PascalVOC` 和 `YOLO` 可选,一般选择 `PascalVOC` 即可,需要 `YOLO` 可以之后进行转换 点击 `创建区块` 创建一个 矩形框,画出范围 ![rect](img/labelImg-rect-1.png) 每个类别都有对应的颜色加以区分 ![rect](img/labelImg-rect-3.png) 完成一张图片的标注后,点击 `下一个图片` 标签文件内容如下,包含了文件信息``、``、``,图片尺寸``,目标位置`` ```xml parking parking-00000.jpg 1066 800 3 parking Unspecified 0 0 420 880 16 633 ``` ## 数据集转换 数据集需要转换成VOC的格式,**VOC2012** 数据集描述如下(这里仅针对目标识别任务): - **Annotations**: 存放了数据`.xml`格式存储的标签,里面包含了每张图片的`bounding box`信息,主要用于**目标识别**。 - **ImageSets**: ImageSets中的Segmentation目录下存放了用于识别的train, val, trainval数据集的路径。 - **JPEGImages**: 这里存放的是图片。 VOC2012中ImageSets目录下需要将全部文件的路径进行写入,包括训练集图片数据`train.txt`、验证集图片数据`val.txt`,内容就是图片的路径 ``` G:\Project\dataset-traffic\VOC2012\JPEGImages\parking-0000.jpg ``` 因此需要对JPEGImages下的图片进行分割,按照一定比例划分数据集和验证集(一般使用8:2、9:1) 但是用于训练的数据集标签需要为`.txt`文件,对于上面的xml,其转换之后的xml为 ```txt 0 0.61041 0.4060185 0.431944 0.771296 ``` 因此需要编写脚本将xml格式中的路径转换成yolo所需要的txt文件,这里提供一个python脚本 ```python import xml.etree.ElementTree as ET import pickle import os from os import listdir, getcwd from os.path import join sets=[('2012', 'train'), ('2012', 'val'), ('2007', 'train'), ('2007', 'val'), ('2007', 'test')] classes = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"] def convert(size, box): dw = 1./size[0] dh = 1./size[1] x = (box[0] + box[1])/2.0 y = (box[2] + box[3])/2.0 w = box[1] - box[0] h = box[3] - box[2] x = x*dw w = w*dw y = y*dh h = h*dh return (x,y,w,h) def convert_annotation(year, image_id): # 转换这一张图片的坐标表示方式(格式),即读取xml文件的内容,计算后存放在txt文件中。 in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id)) out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w') tree=ET.parse(in_file) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) for obj in root.iter('object'): difficult = obj.find('difficult').text cls = obj.find('name').text if cls not in classes or int(difficult) == 1: continue cls_id = classes.index(cls) xmlbox = obj.find('bndbox') b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text)) bb = convert((w,h), b) out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') wd = getcwd() for year, image_set in sets: if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)): os.makedirs('VOCdevkit/VOC%s/labels/'%(year)) # 新建一个 label 文件夹,用于存放yolo格式的标签文件:000001.txt image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split() # 读取txt文件中 存放的图片的 id:000001 list_file = open('%s_%s.txt'%(year, image_set), 'w') # 新建一个 txt文件,用于存放 图片的绝对路径:/media/common/yzn_file/DataSetsH/VOC/VOCdevkit/VOC2007/JPEGImages/000001.jpg for image_id in image_ids: list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id)) # 向 txt 文件中写入 一张图片的绝对路径 convert_annotation(year, image_id) # 转换这一张图片的坐标表示方式(格式) list_file.close() ``` # 2、训练模型 ### 模型的获取与编译 在darknet上对模型进行训练,项目可以从GitHub上获取:[https://github.com/AlexeyAB/darknet](https://github.com/AlexeyAB/darknet),darknet的编译可以参考官方的安装手册::https://pjreddie.com/darknet/install/](https://pjreddie.com/darknet/install/) 该项目强烈推荐在Ubuntu操作系统下进行,并且将darknet项目编译成**GPU版本**,加快编译速度 这里提供一个在Ubuntu下的编译方式 #### Requirements - **Ubuntu**环境下 - **CMake** >= 3.12 - **CUDA** >= 10.0 - **OpenCV** >= 2.4 - **cuDNN** >= 7.0 - **GPU** with CC >= 3.0: https://en.wikipedia.org/wiki/CUDA#GPUs_supported - **GCC** or **Clang** on Linux #### 编译 GPU 版本 ##### 添加CUDA环境变量 需要安装CUDA和cudnn,并且如下配置环境(我们采用CUDA10.1,可以使用更高的版本) ```bash # 配置环境变量 vim ~/.bashrc ``` 添加以下内容 ```bash # ------ CUDA 10.1 ------ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda-10.1/lib64 export PATH=$PATH:/usr/local/cuda-10.1/bin export CUDA_HOME=$CUDA_HOME:/usr/local/cuda-10.1 ``` 执行命令使其生效 ```bash source ~/.bashrc ``` ##### Makefile编译方式 修改makefile文件,修改 在 [Makefile](./Makefile) 文件中(大约 1~9 行) 将下列变量的值改为 `1` ```makefile GPU=1 # 编译 GPU 版本 CUDNN=1 # 与 CUDA 联合 OPENCV=1 # 与 OpenCV 联合编译 LIBSO=1 # 编译动态链接库 .so ``` - nvcc 路径 在 [Makefile](./Makefile) 文件中(大约 7 行) ```bash NVCC=nvcc # 改成你自己电脑里的CUDA路径 NVCC=/usr/local/cuda-10.1/bin/nvcc ``` 在 [Makefile](./Makefile) 文件中(大约 117 行) ```bash COMMON+= -DGPU -I/usr/local/cuda/include/ # 改成你自己电脑里的CUDA路径 COMMON+= -DGPU -I/usr/local/cuda-10.1/include/ ``` 在 [Makefile](./Makefile) 文件中(大约 120 行) ```bash LDFLAGS+= -L/usr/local/cuda/lib -lcuda -lcudart -lcublas -lcurand # 改成你自己电脑里的CUDA路径 LDFLAGS+= -L/usr/local/cuda-10.1/lib -lcuda -lcudart -lcublas -lcurand ``` 在 [Makefile](./Makefile) 文件中(大约 122 行) ```bash LDFLAGS+= -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand # 改成你自己电脑里的CUDA路径 LDFLAGS+= -L/usr/local/cuda-10.1/lib64 -lcuda -lcudart -lcublas -lcurand ``` 在 [Makefile](./Makefile) 文件中(大约 129~130 行) ```bash CFLAGS+= -DCUDNN -I/usr/local/cuda/include LDFLAGS+= -L/usr/local/cuda/lib -lcudnn # 改成你自己电脑里的cudnn路径 CFLAGS+= -DCUDNN -I/usr/local/cuda-10.1/include LDFLAGS+= -L/usr/local/cuda-10.1/lib -lcudnn ``` 修改完 Makefile之后,在当前目录下进行编译 ```bash make ``` 编译完成后,测试程序 ```bash $ ./darknet usage: ./darknet ``` ### 模型的训练 darknet的训练也再官方文档内:[https://pjreddie.com/darknet/yolo/](https://pjreddie.com/darknet/yolo/) ```bash # 下载编译darknet git clone https://github.com/pjreddie/darknet cd darknet make # 下载权重文件 wget https://pjreddie.com/media/files/yolov4-tiny.weights ``` #### 训练需要修改文件 由于配置文件目录`conf`下内容较多,建议在根目录下建立`conf`目录,并把需要的文件从`cfg`中复制到`conf`目录,包括 - 模型配置文件`cfg/yolov4-tiny.cfg` 复制到`conf`目录中,下面的文件修改我们就默认在`conf`目录下进行。 ##### 模型配置文件`conf/yolov4-tiny.cfg` - 修改训练`batch` ```bash [net] # 测试模型 #batch=1 #subdivisions=1 # 训练模型 batch=64 subdivisions=16 ``` - 修改训练`filter`参数 [filters=255] 为 `filters=(classes + 5)x3`,大概有2~3出,建议搜索`[yolo]`修改,`filter`在`[yolo]`上的`[convolutional]`内 ```bash [convolutional] size=1 stride=1 pad=1 # 修改filter=(classes + 5)x3 filters=30 activation=linear [yolo] mask = 3,4,5 anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 # 这里需要修改为你自己类的数量 classes=5 num=6 jitter=.3 scale_x_y = 1.05 ... ``` ##### 配置数据集文件`conf/voc.data` 新建`conf/voc.data`,写入以下内容 ```bash classes=5 train=/home/ubuntu/datasets/dataset-traffic/VOC2012/ImageSets/Main/train.txt valid=/home/ubuntu/datasets/dataset-traffic/VOC2012/ImageSets/Main/val.txt names=conf/voc.names backup=backup ``` 修改类别数`classes`,训练集和验证集的txt路径`train`、`valid`、标签文件`names`、模型保存文件夹`backup` 新建`conf/voc.names`,写入数据集的种类名称 ```bash parking stop person speedLimit trafficLight ``` - 训练`yolov4-tiny`模型 ```bash # cfg/voc.data 是数据集文件 # cfg/yolov4.cfg 是网络的配置文件 # darknet-preweights/yolov4-tiny.weights 是提前下载好的预训练模型 ./build_release/darknet detector train -map \ conf/voc.data \ conf/yolov4-tiny.cfg \ darknet-preweights/yolov4-tiny.weights ``` 训练的模型可以在`backup/`中看到 ### 模型的测试 ```bash ./build_release/darknet detector test \ conf/voc.data \ conf/yolov4-tiny.cfg \ backup/yolov4_best.weights \ <需要识别的图片路径> \ -thresh 0.2 ``` # 3、部署模型 将模型部署到神经计算棒NCS2上进行推理,参考: https://github.com/TNTWEN/OpenVINO-YOLOV4