基于EdgeBoard飞桨开发套件和PicoDet部署夜间场景检测模型
基于EdgeBoard飞桨开发套件和PicoDet部署夜间场景检测模型,视频流读取数据进行实时监测,可用于夜间安防,警示等场景。
基于EdgeBoard飞浆开发套件和PicoDet部署夜间场景检测模型
在夜间微弱的灯光下,摄像头拍摄的画质非常差,基于夜间场景的识别模型训练有助于夜间安防。本项目基于ExDark数据集、PicoDet、EdgeBoard飞桨开发套件和PyQt5进行夜间场景特定物品检测模型的训练和部署。
材料准备
- ExDark数据集
- Aistudio在线运行环境
- EdgeBoard飞桨开发套件(一个板子,可以用本地CPU代替~)
- 摄像头(USB摄像头,尽可能便宜即可)
代码
训练PicoDet模型
基础环境准备
! unzip -oq data/data129450/ExDark.zip
# 克隆PaddleDetection仓库
import os
if not os.path.exists('PaddleDetection'):
!git clone https://github.com/PaddlePaddle/PaddleDetection.git
# 安装其他依赖
%cd PaddleDetection
! pip install -r requirements.txt
# 编译安装paddledet
! python setup.py install
# 测试一下PaddleDet环境有没有准备好
! python ppdet/modeling/tests/test_architectures.py
调整数据格式
将数据格式调整为voc格式,并且准备paddledet需要的文件
正所谓是闻名不如见面吗,不熟悉voc格式的小伙伴可以通过以下语句查看一个voc格式的示例~
%cd ~
! wget https://paddlemodels.bj.bcebos.com/object_detection/roadsign_voc.tar
! tar -xvf /home/aistudio/roadsign_voc.tar
# ExDark转voc
%cd ~
# thanks to https://blog.csdn.net/hu694028833/article/details/81089959
import xml.dom.minidom as minidom
import cv2
def convert2xml(img_dir,annotation_dir,save_dir):
img = cv2.imread(img_dir)
h,w,c = img.shape
dom = minidom.getDOMImplementation().createDocument(None,'annotations',None)
root = dom.documentElement
element = dom.createElement('filename')
element.appendChild(dom.createTextNode(img_dir.split('/')[-1]))
root.appendChild(element)
element = dom.createElement('size')
element_c = dom.createElement('width')
element_c.appendChild(dom.createTextNode(str(w)))
element.appendChild(element_c)
element_c = dom.createElement('height')
element_c.appendChild(dom.createTextNode(str(h)))
element.appendChild(element_c)
element_c = dom.createElement('depth')
element_c.appendChild(dom.createTextNode(str(c)))
element.appendChild(element_c)
root.appendChild(element)
with open(annotation_dir) as f:
for line in f.readlines():
if '% bbGt' in line:
continue
else:
element = dom.createElement('object')
name = line.split(' ')[0]
xmin = int(line.split(' ')[1])
ymin = int(line.split(' ')[2])
xlen = int(line.split(' ')[3])
ylen = int(line.split(' ')[4])
element_c = dom.createElement('name')
element_c.appendChild(dom.createTextNode(name))
element.appendChild(element_c)
element_c = dom.createElement('bndbox')
element.appendChild(element_c)
element_cc = dom.createElement('xmin')
element_cc.appendChild(dom.createTextNode(str(xmin)))
element_c.appendChild(element_cc)
element_cc = dom.createElement('ymin')
element_cc.appendChild(dom.createTextNode(str(ymin)))
element_c.appendChild(element_cc)
element_cc = dom.createElement('xmax')
element_cc.appendChild(dom.createTextNode(str(xmin+xlen)))
element_c.appendChild(element_cc)
element_cc = dom.createElement('ymax')
element_cc.appendChild(dom.createTextNode(str(ymin+ylen)))
element_c.appendChild(element_cc)
root.appendChild(element)
with open(save_dir, 'w', encoding='utf-8') as f:
dom.writexml(f, addindent='\t', newl='\n',encoding='utf-8')
convert2xml('ExDark/images/Bicycle/2015_00001.png','ExDark/Annnotations/Bicycle/2015_00001.png.txt','test.xml')
/home/aistudio
# thanks to https://www.runoob.com/python/os-walk.html
# 用一个train.txt记录数据
%cd ~
import os
! mkdir -p ExDark/annotations
with open('train.txt','w') as f:
for root, dirs, files in os.walk("ExDark/images", topdown=False):
for name in files:
img_dir = os.path.join(root, name)
if 'ipynb_checkpoints' in img_dir:
continue
annotation_dir = img_dir.replace('images','Annnotations')+'.txt'
save_dir = 'ExDark/annotations/'+img_dir.split('/')[-1]+'.xml'
try:
convert2xml(img_dir,annotation_dir,save_dir)
except:
continue
f.write(img_dir+' '+save_dir+'\n')
# 准备标签文件
%cd ~
with open('label_list.txt','w') as f:
for item in os.listdir("ExDark/images"):
f.write(item+'\n')
/home/aistudio
准备yml文件
在PaddleDetection/configs/picodet/目录下准备一个名为myPicodetXsVoc.yml的文件,内容为
_BASE_: [
'../datasets/voc.yml',
'../runtime.yml',
'_base_/picodet_v2.yml',
'_base_/optimizer_300e.yml',
'_base_/picodet_320_reader.yml',
]
pretrain_weights: https://paddledet.bj.bcebos.com/models/pretrained/LCNet_x0_35_pretrained.pdparams
weights: output/picodet_xs_320_coco/best_model
find_unused_parameters: True
use_ema: true
epoch: 8
snapshot_epoch: 2
LCNet:
scale: 0.35
feature_maps: [3, 4, 5]
LCPAN:
out_channels: 96
PicoHeadV2:
conv_feat:
name: PicoFeat
feat_in: 96
feat_out: 96
num_convs: 2
num_fpn_stride: 4
norm_type: bn
share_cls_reg: True
use_se: True
feat_in_chan: 96
TrainReader:
batch_size: 64
LearningRate:
base_lr: 0.32
schedulers:
- !CosineDecay
max_epochs: 300
- !LinearWarmup
start_factor: 0.1
steps: 300
将PaddleDetection/configs/datasets/voc.yml修改为如下内容
metric: VOC
map_type: 11point
num_classes: 12
TrainDataset:
!VOCDataSet
dataset_dir: /home/aistudio
anno_path: /home/aistudio/train.txt
label_list: /home/aistudio/label_list.txt
data_fields: ['image', 'gt_bbox', 'gt_class', 'difficult']
EvalDataset:
!VOCDataSet
dataset_dir: /home/aistudio
anno_path: /home/aistudio/train.txt
label_list: /home/aistudio/label_list.txt
data_fields: ['image', 'gt_bbox', 'gt_class', 'difficult']
TestDataset:
!ImageFolder
anno_path: /home/aistudio/label_list.txt
训练
10 epoch 24 min
%cd ~/PaddleDetection
! export CUDA_VISIBLE_DEVICES=0 #windows和Mac下不需要执行该命令
! python tools/train.py -c configs/picodet/myPicodetXsVoc.yml
预测
预测一下看看结果吧,如果啥也没检测到就修改threshold,毕竟是黑暗场景~调低一点就能看到了。
结果展示:
# 预测代码
%cd ~/PaddleDetection
! export CUDA_VISIBLE_DEVICES=0 #windows和Mac下不需要执行该命令
! python tools/infer.py -c configs/picodet/myPicodetXsVoc.yml \
--infer_img=/home/aistudio/ExDark/images/Bicycle/2015_00001.png \
--output_dir=infer_output/ \
--draw_threshold=0.5 \
-o weights=output/myPicodetXsVoc/model_final \
--use_vdl=False
/home/aistudio/PaddleDetection
W0910 18:38:48.325160 14436 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 11.2
W0910 18:38:48.328585 14436 gpu_resources.cc:91] device: 0, cuDNN Version: 8.2.
[09/10 18:38:48] ppdet.utils.checkpoint INFO: Finish loading model weights: output/myPicodetXsVoc/model_final.pdparams
100%|█████████████████████████████████████████████| 1/1 [00:01<00:00, 1.99s/it]
[09/10 18:38:50] ppdet.engine INFO: Detection bbox results save in infer_output/2015_00001.png
模型导出
%cd ~/PaddleDetection
! python tools/export_model.py -c configs/picodet/myPicodetXsVoc.yml \
--output_dir=./inference_model \
-o weights=output/myPicodetXsVoc/model_final \
TestReader.inputs_def.image_shape=[3,320,320]
/home/aistudio/PaddleDetection
[09/06 20:38:43] ppdet.utils.checkpoint INFO: Finish loading model weights: output/myPicodetXsVoc/model_final.pdparams
[09/06 20:38:43] ppdet.engine INFO: Export inference config file to ./inference_model/myPicodetXsVoc/infer_cfg.yml
[09/06 20:38:48] ppdet.engine INFO: Export model and saved in ./inference_model/myPicodetXsVoc
部署
模型转化
Fork项目EdgeBoard飞桨开发套件,根据项目内说明,执行即可。
需要注意以下两点:
- EdgeBoard飞桨开发套件中除章节“模型推理”外,均可以在Aistudio上执行
- 如果Fork上述项目,在执行过程中不顺利,可以尝试在Terminal中运行。
部署
转化后的模型为一个tar文件。
将转化后的.tar文件放在EdgeBoard指定路径下,并修改对应Config信息即可(具体参考EdgeBoard飞桨开发套件)。
具体的EB推理代码如下(由于使用了pyqt5和摄像头需要在本地运行):
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Thanks to
zetcode.com
https://blog.csdn.net/u014453898/article/details/88083173
https://github.com/maicss/PyQt-Chinese-tutorial
https://maicss.gitbooks.io/pyqt5/content/
https://blog.csdn.net/m0_37811342/article/details/108741505
"""
import sys
import cv2
import numpy as np
import math
import time
import collections
import os
import sys
from PyQt5.QtWidgets import QWidget, QDesktopWidget, QApplication, QPushButton, QFileDialog, QLabel, QTextEdit, \
QGridLayout, QFrame, QColorDialog
from PyQt5.QtCore import QTimer, QUrl
from PyQt5.QtGui import QColor, QImage, QPixmap
"""Demo for ppnc runtime on board"""
import json
# add python path of ppnc/python to sys.path
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
sys.path.insert(0, parent_path + '/python')
from ppnc import PPNCPredictor
def parse_config(config_file):
"""parse config"""
with open(config_file, "r") as f:
config = json.load(f)
return config
def preprocess(img, input_size=(320, 320)):
"""parse image
Args:
img_path (str): path
input_size (tuple, optional): h x w. Defaults to (320, 320).
"""
input = {}
# img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
scale_factor = [input_size[0] / img.shape[0], input_size[1] / img.shape[1]]
factor = np.array(scale_factor, dtype=np.float32)
input['scale_factor'] = factor.reshape((1, 2))
img = cv2.resize(img, input_size, interpolation=2)
mean = np.array([0.485, 0.456, 0.406])[np.newaxis, np.newaxis, :]
std = np.array([0.229, 0.224, 0.225])[np.newaxis, np.newaxis, :]
img = img / 255
img -= mean
img /= std
img = img.astype(np.float32, copy=False)
img = img.transpose((2, 0, 1))
img = img[np.newaxis, :]
input['image'] = img
return input
def draw_box(img, res, threshold=0.35):
"""draw box
Args:
img_path (str): image path
res (numpy): output
threshold (float, optional): . Defaults to 0.2.
"""
# img = cv2.imread(img_path)
label_list = ['Boat','People','bottle','Chair','Table','Cat','Dog','Motorbike','Bicycle','Cup','Car','Bus']
for i in res:
label = int(i[0])
score = i[1]
if score < threshold:
continue
print("Something exists! It is ", end="")
print(label_list[label])
xmin, ymin, xmax, ymax = i[2:]
cv2.rectangle(img, (int(xmin), int(ymin)),
(int(xmax), int(ymax)), (0, 255, 0))
return img
class Example(QWidget):
def __init__(self,config):
super().__init__()
self.config = config
self.img_width, self.img_height = [120 * x for x in [4, 3]]
self.initCamera()
self.initUI()
self.initModel()
def initCamera(self):
# 开启视频通道
self.camera_id = 0 # 为0时表示视频流来自摄像头
self.camera = cv2.VideoCapture() # 视频流
self.camera.open(self.camera_id)
# 通过定时器读取数据
self.flush_clock = QTimer() # 定义定时器,用于控制显示视频的帧率
self.flush_clock.start(60) # 定时器开始计时30ms,结果是每过30ms从摄像头中取一帧显示
self.flush_clock.timeout.connect(self.show_frame) # 若定时器结束,show_frame()
def initModel(self):
# Step 2: initialize ppnc predictor
self.predictor = PPNCPredictor(self.config)
self.predictor.load()
def initUI(self):
grid = QGridLayout()
self.setLayout(grid)
self.Img_Box = QLabel() # 定义显示视频的Label
self.Img_Box.setFixedSize(self.img_width, self.img_height)
grid.addWidget(self.Img_Box, 0, 0, 20, 20)
self.setWindowTitle('test')
self.show()
def show_frame(self):
# self.player.play()
_, img = self.camera.read() # 从视频流中读取
# print(img.shape)
try:
feeds = preprocess(img)
self.predictor.set_inputs(feeds)
self.predictor.run()
res = self.predictor.get_output(0)
img = draw_box(img, res)
except:
print('infer error')
img = cv2.resize(img, (self.img_width, self.img_height)) # 把读到的帧的大小重新设置为 640x480
showImage = QImage(img, img.shape[1], img.shape[0], QImage.Format_RGB888)
self.Img_Box.setPixmap(QPixmap.fromImage(showImage))
if __name__ == '__main__':
# Step 1: parse config file
assert len(sys.argv) >= 3, "config and image file must be provided"
config_file = sys.argv[1]
image_file = sys.argv[2]
config = parse_config(config_file)
app = QApplication(sys.argv)
ex = Example(config)
sys.exit(app.exec_())
最后简单展示一下部署效果:
检测环境 | 检测结果 |
---|---|
检测环境看着可能比较亮,但实际上很暗,除了屏幕和开发板的指示灯外,没有太多光源。可以看到确实能够检测到水杯的出现~
请点击此处查看本环境基本用法.
Please click here for more detailed instructions.
此文章为搬运
原项目链接
更多推荐
所有评论(0)