作者使用的是树莓派4b(64位)
实验室的同学试过跑树莓派5,也是没有问题的。
部分同学训练时出现错误可以按照提示修改版本号。
之前同学们反馈的问题以得到解决,特别感谢 无敌暴龙战士 提供的问题解决方案。
第一步:烧录操作系统
一定要64位的操作系统,不然后面很难运行YOLOv5!!!
第二步:远程登陆树莓派
常见有三种不同的登陆方式:
(ip地址、静态ip设置等后续更新,或网上找资料)
SSH:基于linux系统的命令行
VNC:将树莓派桌面远程共享,类似于QQ的远程协助功能,内容会比较模糊
RDP:在电脑端新开一个树莓派桌面,只传输数据,不传输画面,(如果连接树莓派的屏幕,会发现电脑端的操作在树莓派屏幕上是看不到的)相当于作为一个独立的用户来使用树莓派,画面清晰度高
这里推荐两个软件:
MobaXterm:清晰度较高,集成有上面的3种功能
RealVNC Viewer:画面较为模糊,可以与树莓派传输文件,第四个按钮就是传输文件
第三步:安装opencv
1、安装Python
选择合适的版本,3.9以上
pip install python==3.11.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
2、安装opencv
打开树莓派命令窗口,输入下面的命令,使用清华大学开源软件镜像源
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
3、更新numpy
如果后面训练的时候提示版本号过高或者没有合适的版本号,则按照十二步的版本对应规则进行更改版本,删除版本:把下面的install改成uninstall即可
亲测numpy版本要在2.0以下,不然会报错!
pip install numpy==1.18 -i https://pypi.tuna.tsinghua.edu.cn/simple
4、验证Opencv是否安装成功
打开终端,先输⼊python后,再输⼊import cv2(cv2是opencv在python中的简称),最后再输⼊cv2.__version__,出现对应的版本号,说明python和opencv安装成功。
第四步:检查摄像头是否正常
新建一个py文件,输入以下代码,运行程序,如果出现灰色的摄像头界面,则摄像头正常工作
如果不出现,请查找原因,解决后再进行下面操作。摄像头推荐使用USB免驱摄像头,线长方便操作。
#coding=utf-8
import cv2 #导入opencv视觉库
vc = cv2.VideoCapture(0) #获取视频,若需要调用摄像头,则为vc = cv2.VideoCapture(0)
if vc.isOpened(): #检查视频是否能打开
open, frame = vc.read() #如果能打开,则获取视频的两个参数:open、frame
else:
open = False #不能打开则将open设置为False,即表示不能打开
while open: #当open的值为非0时进入以下循环
ret, frame = vc.read() #先获取参数,frame为是视频本身,即视频的数字化表示
if frame is None: #判断,frame是否为空
break #如果为空,则跳出循环,即没有读取到视频
if ret == True: #如果ret为Ture,则表示可以打开视频
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #调整视频的颜色为灰色
cv2.imshow('video', gray) #显示视频
if cv2.waitKey(1) & 0xFF == ord('q'):
break
vc.release() #释放窗口
cv2.destroyAllWindows() #销毁所有窗口
第五步:采集照片
新建一个文件夹,在文件夹新建一个py文件和一个文件夹,命名为images,在py文件里输入并运行以下代码
按下键盘上的c键开始采集,按下q键结束,注意变化不同的角度来采集,采集的背景要和识别的背景一样,不然识别率会很低。
一般采集200张以上,照片越多,识别准确率越高
采集到的照片会保存到images文件夹里,如果找不到的话去系统的images文件夹里面找,采集完成后使用第二步的软件将图片传输到电脑
import cv2
import uuid
from threading import Thread
import os
import time
count = 0
def image_collect(cap):
global count
while True:
success, img = cap.read()
if success:
file_name=str(uuid.uuid4())+'.jpg'
cv2.imwrite(os.path.join('images',file_name),img)
count=count+1
print("save %d %s"%(count,file_name))
time.sleep(0.4)#采集照片的时间间隔
if __name__=="__main__":
os.makedirs("images",exist_ok=True)
cap=cv2.VideoCapture(0)
cap.set(3,320)#照片的尺寸
cap.set(4,320)
m_thread = Thread(target=image_collect,args=([cap]),daemon=True)
while True:
success,img = cap.read()
if not success:
continue
cv2.imshow("video",img)
key=cv2.waitKey(1) & 0xFF
if key==ord('c'):
m_thread.start()
elif key== ord('q'):
break
cap.release()
采集到的图片会在这里
第六步:整理图片
新建一个文件夹(名字随便取,最好和要识别的东西相关,不能有中文,我这里取tast_chili,红辣椒)
在文件夹里新建文件夹,命名为data
在data里新建两个文件夹train(训练集)和valid(验证集)
在两个文件夹里分别新建两个文件夹,images和labels,注意不要打错单词了
将采集到的图片存入images里,训练集:验证集=9:1
第七步:使⽤labelimg⼯具进⾏标记
labelimg软件链接:https://pan.baidu.com/s/154B1Yt-UL6wWyin8Pt1Y0g?pwd=jf0f
安装出现问题可能是缺少某些文件,一般都能直接使用
分别标记训练集和验证集
快捷键 : W标注 A上⼀张 D下⼀张
标记完后会得到txt文件,classes是分类,其他是和对应图片的同名文件
第八步:下载模型
官方网站https://github.com/ppogg/YOLOv5-Lite
我的网盘链接:https://pan.baidu.com/s/14_Hi6OGvfZBmPUuASe333w?pwd=bgqe
解压后按照图片的位置放置(和data同一级路径)
第九步:训练前准备
准备yaml文件
复制coco128.yaml文件,粘贴并改名为mydata.yaml
打开mydata.yaml,修改路径(如图所示)
下载v5lite-e.pt和v5lite-s.pt
链接:https://pan.baidu.com/s/16PFtRAJR4cTe3OxdTqs1Kw?pwd=kr2h
解压到YOLOv5-Lite-master文件夹里,并把小写的l改成大写的L
v5Lite-s.pt运行起来更加快
打开train.py
更改detect.py
修改模型文件
nc改成类型数量
修改requitment.txt,换成下面的内容,部分同学出错的原因就在这里,numpy的版本号要小于2.0
# pip install -r requirements.txt
# base ----------------------------------------
matplotlib>=3.2.2
numpy==1.18
opencv-python>=4.1.2
Pillow
PyYAML>=5.3.1
scipy>=1.4.1
torch>=1.8.0
torchvision>=0.9.0
tqdm>=4.41.0
# logging -------------------------------------
tensorboard>=2.4.1
# wandb
# plotting ------------------------------------
seaborn>=0.11.0
pandas
# export --------------------------------------
coremltools>=4.1
onnx>=1.9.1
scikit-learn # for coreml quantization
# extras --------------------------------------
thop # FLOPS computation
pycocotools>=2.0 # COCO mAP
第十步:注册矩池云或者在本地训练
本地训练需注意显卡(GPU) 必须是英伟达的,不然不能在本地训练
本地训练直接跳过租用电脑部分,本地训练需要注意下面的问题
下载矩池云网盘
上传文件
上传整个文件
第十一步:开始训练
租用GPU
复制ssh命令
打开windowns命令提示符窗口(命令窗口),win+r,输入cmd
复制ssh命令, 右键粘贴,回车,输入yes,回车
复制密码,右键粘贴密码(密码不显示) ,登陆成功
ls:查看当前目录
cd打开文件夹
cd ..放回上一级
一步一步找到文件的位置,就在YOLOv5-Lite-master里面
安装依赖
pip install -r requirements.txt
python 运行train.py文件
python train.py
如果发现没有找到Dataset,返回第九步,修改模型文件,注意是-s不是-e
正常情况下,开始训练,等到训练完成,一般十多分钟这样。
将best.pt文件复制到YOLOv5-Lite-master文件夹下(在网盘那里移动)
转化为onnx文件
python export.py --weights best.pt --concat
转化成功
打开矩池云网盘,将整个文件夹下载到本地
在runs文件夹里可以看到训练的效果
第十二步:启动树莓派
安装pytorch和pytorchvision
YOLOv5的底层由pytorch实现的,因此你要运⾏YOLOv5就必须安装pytorch。 64位的树莓派才能安装pytorch。
安装pytorch时不要安装最新版,不要安装最新版,不要安装最新版。可能会出现与其他东西不兼容的情况。
安装pytorch的版本要与pytorchvision版本相同。
对应关系(不对应不能安装和运行)
将版本修改为你要安装的版本,注意版本不能太低
pip install torch==2.0.0 torchvision==0.15.0 -i https://pypi.douban.com/simple
如果上述方法不能安装成功,则到链接内自行下载,再传输到树莓派上
注意
1、后缀为aarch64.whl
2、版本要和树莓派上的python一致,如python 3.11,则找中间有cp311的
3、查询Python版本
python -V
4、安装文件,先导航到文件目录,再安装
install +文件名
链接:https://download.pytorch.org/whl/torch_stable.html
安装依赖
导航到requirements.txt所在的文件
安装onnx
pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/simple
安装onnxruntime
pip install onnxruntime -i https://pypi.tuna.tsinghua.edu.cn/simple
输入命令,安装依赖,重复安装几次
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
第十三步:开始识别
在bast.onnx的同一级目录下新建run_YOLOv5.py文件
编写一下代码
import cv2
import numpy as np
import onnxruntime as ort
import time
def plot_one_box(x, img, color=None, label=None, line_thickness=None):
"""
description: Plots one bounding box on image img,
this function comes from YoLov5 project.
param:
x: a box likes [x1,y1,x2,y2]
img: a opencv image object
color: color to draw rectangle, such as (0,255,0)
label: str
line_thickness: int
return:
no return
"""
tl = (
line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1
) # line/font thickness
color = color or [random.randint(0, 255) for _ in range(3)]
c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)
if label:
tf = max(tl - 1, 1) # font thickness
t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]
c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled
cv2.putText(
img,
label,
(c1[0], c1[1] - 2),
0,
tl / 3,
[225, 255, 255],
thickness=tf,
lineType=cv2.LINE_AA,
)
def _make_grid( nx, ny):
xv, yv = np.meshgrid(np.arange(ny), np.arange(nx))
return np.stack((xv, yv), 2).reshape((-1, 2)).astype(np.float32)
def cal_outputs(outs,nl,na,model_w,model_h,anchor_grid,stride):
row_ind = 0
grid = [np.zeros(1)] * nl
for i in range(nl):
h, w = int(model_w/ stride[i]), int(model_h / stride[i])
length = int(na * h * w)
if grid[i].shape[2:4] != (h, w):
grid[i] = _make_grid(w, h)
outs[row_ind:row_ind + length, 0:2] = (outs[row_ind:row_ind + length, 0:2] * 2. - 0.5 + np.tile(
grid[i], (na, 1))) * int(stride[i])
outs[row_ind:row_ind + length, 2:4] = (outs[row_ind:row_ind + length, 2:4] * 2) ** 2 * np.repeat(
anchor_grid[i], h * w, axis=0)
row_ind += length
return outs
def post_process_opencv(outputs,model_h,model_w,img_h,img_w,thred_nms,thred_cond):
conf = outputs[:,4].tolist()
c_x = outputs[:,0]/model_w*img_w
c_y = outputs[:,1]/model_h*img_h
w = outputs[:,2]/model_w*img_w
h = outputs[:,3]/model_h*img_h
p_cls = outputs[:,5:]
if len(p_cls.shape)==1:
p_cls = np.expand_dims(p_cls,1)
cls_id = np.argmax(p_cls,axis=1)
p_x1 = np.expand_dims(c_x-w/2,-1)
p_y1 = np.expand_dims(c_y-h/2,-1)
p_x2 = np.expand_dims(c_x+w/2,-1)
p_y2 = np.expand_dims(c_y+h/2,-1)
areas = np.concatenate((p_x1,p_y1,p_x2,p_y2),axis=-1)
areas = areas.tolist()
ids = cv2.dnn.NMSBoxes(areas,conf,thred_cond,thred_nms)
if len(ids)>0:
return np.array(areas)[ids],np.array(conf)[ids],cls_id[ids]
else:
return [],[],[]
def infer_img(img0,net,model_h,model_w,nl,na,stride,anchor_grid,thred_nms=0.4,thred_cond=0.5):
# 图像预处理
img = cv2.resize(img0, [model_w,model_h], interpolation=cv2.INTER_AREA)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = img.astype(np.float32) / 255.0
blob = np.expand_dims(np.transpose(img, (2, 0, 1)), axis=0)
# 模型推理
outs = net.run(None, {net.get_inputs()[0].name: blob})[0].squeeze(axis=0)
# 输出坐标矫正
outs = cal_outputs(outs,nl,na,model_w,model_h,anchor_grid,stride)
# 检测框计算
img_h,img_w,_ = np.shape(img0)
boxes,confs,ids = post_process_opencv(outs,model_h,model_w,img_h,img_w,thred_nms,thred_cond)
return boxes,confs,ids
if __name__ == "__main__":
# 模型加载
model_pb_path = "best.onnx"
so = ort.SessionOptions()
net = ort.InferenceSession(model_pb_path, so)
# 标签字典
dic_labels= {0:'drug',
1:'glue',
2:'prime'}
# 模型参数
model_h = 320
model_w = 320
nl = 3
na = 3
stride=[8.,16.,32.]
anchors = [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]]
anchor_grid = np.asarray(anchors, dtype=np.float32).reshape(nl, -1, 2)
video = 0
cap = cv2.VideoCapture(video)
flag_det = False
while True:
success, img0 = cap.read()
if success:
if flag_det:
t1 = time.time()
det_boxes,scores,ids = infer_img(img0,net,model_h,model_w,nl,na,stride,anchor_grid,thred_nms=0.4,thred_cond=0.5)
t2 = time.time()
for box,score,id in zip(det_boxes,scores,ids):
label = '%s:%.2f'%(dic_labels[id],score)
plot_one_box(box.astype(np.int16), img0, color=(255,0,0), label=label, line_thickness=None)
str_FPS = "FPS: %.2f"%(1./(t2-t1))
cv2.putText(img0,str_FPS,(50,50),cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),3)
cv2.imshow("video",img0)
key=cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key & 0xFF == ord('s'):
flag_det = not flag_det
print(flag_det)
cap.release()
改成对应的内容
运行,开始识别
按s开始识别,按q结束识别
识别效果如图所示,一般能跑到5帧以上,图片为重新训练的模型,不是上面标注的小辣椒