1、RTP
RTP全名是Real-time Transport Protocol(实时传输协议)
RTP协议常用于流媒体系统(配合RTCP协议或者RTSP协议)。因为RTP自身具有Time stamp所以在ffmpeg 中被用做一种formate.
每一个RTP数据报都由头部(Header)和负载(Payload)两个部分组成,其中头部前12个字节的含义是固定的,而负载则可以是音频或者视频数据。
RTP(Realtime Transport Protocol),实时传输协议
其专门针对实时流媒体而设计, RTP的基本功能是将几个实时数据流复用到一个UDP分组流中,这 个UDP流可以被发送给一台主机(单播模式),也可以被传送给多台目标主机(多播模式)。因为RTP仅仅封装成常规的UDP,理论上路由器不会对分组有任何特殊对待,但现在高级的路由设备都有针对RTP协议优化选项。RTP协议的时间戳机制,不仅减少了抖动的影响,而且也允许多个数据流相互之间的同步,这样可以很方便地基于I/O事件对视频图像进行字幕添加,网络摄像机往往将音视频编码数据封装成RTP分组。
RTCP(Realtime Transport Control Protocol)实时传输控制协议,其是RTP的姊妹协议。
它处理反馈、同步和用户界面等,但是不传输任何数据。它的主要功能是用来向源端提供有关延迟、抖动、带宽、拥塞和其它网络特性的反馈信息,编码进程可以充分利用这些信息。因此当网络状况较好时,可以提高数据速率(从而达到更好的质量),而当网络状况不好时,它可以减少数据速率。 通过连续的反馈信息,编码算法可以持续地作相应的调整,从而在当前条件下尽可能地提供最佳的质量。
RTSP(Real Time Streaming Protocol)实时流协议。
RTSP协议利用推式服务器(push server)方法,让音视频浏览端,发出一个请求,网络摄像机只是不停地向浏览端推送封装成RTP分组的音视频编码数据,网络摄像机可以用很小的系统开销实现流媒体传输。
HTTP(HyperText Transfer Protocol)超文本传输协议。
网络摄像机通过HTTP协议提供Web访问功能,很方便地将音视频数据经过复杂网络传输,但实时音视频支持很不理想。
UDP(User Datagram Protocol)数据报协议,是最基本的网络数据传输协议。
利用IP协议提供网络无连接服务,常用来封装实时性强的网络音视频数据,即使网络传输过程中发生分组丢失现象,在客户端也不会影响音视频浏览。
TCP(Transmission Control Protocol)传输控制协议,
利用IP协议提供面向连接网络服务,为在不可靠的互联网络上提供一个可靠的端到端字节流而设计。TCP协议往往要在服务端和客户端经过多次“握手”才能建立连接, 因此利用TCP传输实时性较强的音视频流开销较大 ,如果网络不稳定,音视频抖动的现象明显。利用其可靠性常用来传输网络摄像机管理命令,如PTZ,I/O设备控制命令。
2、multi-SVM和RestNet18和MobileNetV2
统计FLOPS
from torchvision.models import resnet18
from thop import profile
import torch
model = resnet18()
input = torch.randn(1, 3, 224, 224)
flops, params = profile(model, inputs=(input, ))
print(flops)
Resnet18 模型参数量 46.8MB resnet.pth
300300 size 1050ti 10.2ms
224224 size 1050ti: 6.7ms
MobileNetV2 模型参数量13.6MB MobileNetV2.pth
224224 size 1050ti: 5.9ms
224224 size 940mx: 9.8ms
IMageNet评估: Top-1 Params FLOPs
RepVGG-A0 72.41 8.3 M 1.4B 更快
ResNet-18 71.16 11.68M 1.8B
例如,利用Pytorch训练分类:
利用已有的数据读取函数
data_loader = torch.utils.data.DataLoader(
torchvision.datasets.ImageFolder('traing_dataset',
transform=torchvision.transforms.Compose([
torchvision.transforms.Resize([28, 28]), # 裁剪图片
torchvision.transforms.Grayscale(1), # 单通道
torchvision.transforms.ToTensor(), # 将图片数据转成tensor格式
torchvision.transforms.Normalize( # 归一化
(0.1307,), (0.3081,))
])),
batch_size=10, shuffle=False) # 10张图片
文件夹读取函数,运用ImageFolder()和DataLoader()
from __future__ import print_function, division
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
train_transform = transforms.Compose([
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
valid_transform=transforms.Compose([
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
train_dataset =torchvision.datasets.ImageFolder(root='maize/train',transform=train_transform)
train_loader =DataLoader(train_dataset,batch_size=1, shuffle=True,num_workers=0)#Batch Size定义:一次训练所选取的样本数。 Batch Size的大小影响模型的优化程度和速度。
valid_dataset =torchvision.datasets.ImageFolder(root='maize/valid',transform=valid_transform)
valid_loader =DataLoader(valid_dataset,batch_size=1, shuffle=True,num_workers=0)
数据整理成如下格式:
另外的数据加载方式:
data_transforms = {
'train': transforms.Compose([
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'valid': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
data_dir = 'maize'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
data_transforms[x])
for x in ['train', 'valid']}
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,
shuffle=True, num_workers=1)
for x in ['train', 'valid']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'valid']}
class_names = image_datasets['train'].classes
3、yolo训练
https://blog.csdn.net/weixin_41010198/article/details/106785253
https://blog.csdn.net/weixin_48994268/article/details/115282688
环境:
1:下载好yolov5文件后,cd到文件路径创建yolov5的环境
2:终端输入conda create -n yolov5 python==3.7,
3:进入环境conda activate yolov5,
4:安装requirements中的环境
pip install -r requirements.txt
数据集:
官方给出的训练数据的传入方式,有两种。
第一种直接将训练文件的路径写入txt文件传入。
第二种直接传入训练文件所在文件夹。
第一种coco数据及格式
我们可以用第二种:
mytrain
├── mycoco
│ ├── images
│ │ ├── train
│ │ └── val
│ └── labels
│ ├── train
│ └── val
└── yolov5
使用代码生产部分结构:
只需要准备好:
mycoco
├── all_images
├── all_xml
├── make_txt.py
└── train_val.py
其中make_txt.py
import os
import random
trainval_percent = 0.1
train_percent = 0.9
xmlfilepath = 'all_images'
txtsavepath = 'ImageSets'
total_xml = os.listdir(xmlfilepath)
num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv) #从所有list中返回tv个数量的项目
train = random.sample(trainval, tr)
if not os.path.exists('ImageSets/'):
os.makedirs('ImageSets/')
ftrainval = open('ImageSets/trainval.txt', 'w')
ftest = open('ImageSets/test.txt', 'w')
ftrain = open('ImageSets/train.txt', 'w')
fval = open('ImageSets/val.txt', 'w')
for i in list:
name = total_xml[i][:-4] + '\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftest.write(name)
else:
fval.write(name)
else:
ftrain.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
其中train_val.py
(将all_xml中xml文件转为txt文件存于all_labels文件夹中)
import xml.etree.ElementTree as ET
import pickle
import os
import shutil
from os import listdir, getcwd
from os.path import join
sets = ['train', 'trainval']
classes = ['car','chemicals vehicle','truck','bus','triangle warning sign','warning sign','warning slogan']
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(image_id):
in_file = open('all_xml/%s.xml' % (image_id))
out_file = open('all_labels/%s.txt' % (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()
print(wd)
for image_set in sets:
if not os.path.exists('all_labels/'):
os.makedirs('all_labels/')
image_ids = open('ImageSets/%s.txt' % (image_set)).read().strip().split()
image_list_file = open('images_%s.txt' % (image_set), 'w')
labels_list_file=open('labels_%s.txt'%(image_set),'w')
for image_id in image_ids:
image_list_file.write('%s.jpg\n' % (image_id))
labels_list_file.write('%s.txt\n'%(image_id))
convert_annotation(image_id) #如果标签已经是txt格式,将此行注释掉,所有的txt存放到all_labels文件夹。
image_list_file.close()
labels_list_file.close()
def copy_file(new_path,path_txt,search_path):#参数1:存放新文件的位置 参数2:为上一步建立好的train,val训练数据的路径txt文件 参数3:为搜索的文件位置
if not os.path.exists(new_path):
os.makedirs(new_path)
with open(path_txt, 'r') as lines:
filenames_to_copy = set(line.rstrip() for line in lines)
# print('filenames_to_copy:',filenames_to_copy)
# print(len(filenames_to_copy))
for root, _, filenames in os.walk(search_path):
# print('root',root)
# print(_)
# print(filenames)
for filename in filenames:
if filename in filenames_to_copy:
shutil.copy(os.path.join(root, filename), new_path)
#按照划分好的训练文件的路径搜索目标,并将其复制到yolo格式下的新路径
copy_file('./images/train/','./images_train.txt','./all_image')
copy_file('./images/val/','./images_trainval.txt','./all_image')
copy_file('./labels/train/','./labels_train.txt','./all_labels')
copy_file('./labels/val/','./labels_trainval.txt','./all_labels')
最后安整的数据结构如下
mytrain
├── mycoco
│ ├── all_images
│ ├── all_labels
│ ├── all_xml
│ ├── ImageSets
│ │ ├── train.txt
│ │ ├── test.txt
│ │ ├── trainval.txt
│ │ └── val.txt
│ ├── images
│ │ ├── train
│ │ └── val
│ ├── labels
│ ├── train
│ └── val
│ ├── images_train.txt
│ ├── images_trainval.txt
│ ├── labels_train.txt
│ ├── labels_trainval.txt
│ ├── make_txt.py
│ └── train_val.py
└── yolov5
制作好的mycoco文件夹yolov5文件夹放同一级,如下:
最后生成训练所需的.ymal配置文件:
# Default dataset location is next to /yolov5:
# /parent_folder
# /mycoco
# /yolov5
# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
train: ../mycoco/images/train/
val: ../mycoco/images/val/
# number of classes
nc: 7
# class names
names: ['car','chemicals vehicle','truck','bus','triangle warning sign','warning sign','warning slogan' ]
最后,最后,修改train.py里面对应的参数
可尝试1280 size
python detect.py --source data/images --weights model.pt --conf 0.25
出现错误:
ImportError: cannot import name 'amp' from 'torch.cuda' (/home/zyt/torch_tensorflow/py3torch/lib/python3.7/site-packages/torch/cuda/__init__.py)
修改 /models/common.py
#from torch.cuda import amp
from apex import amp
出现错误:
utils/plots.py", line 283, in plot_labels
sns.pairplot(x, corner=True, diag_kind='auto', kind='hist', diag_kws=dict(bins=50), plot_kws=dict(pmax=0.9))
TypeError: pairplot() got an unexpected keyword argument 'corner'
正确的seaborn版本
pip3.7 install seaborn==0.11.1
4: 安装LabelImg
https://github.com/tzutalin/labelImg
> sudo apt-get install pyqt5-dev-tools sudo pip3 install -r
> requirements/requirements-linux-python3.txt pip3 install PyQt5 -i
> https://mirrors.aliyun.com/pypi/simple make qt5py3 python3 labelImg.py
> python3 labelImg.py [IMAGE_PATH] [PRE-DEFINED CLASS FILE]
使用方式:
Ctrl + u 加载目录中的所有图像,鼠标点击Open dir同功能
Ctrl + r 更改默认注释目标目录(xml文件保存的地址)
Ctrl + s 保存
Ctrl + d 复制当前标签和矩形框
space 将当前图像标记为已验证
w 创建一个矩形框
d 下一张图片
a 上一张图片
del 删除选定的矩形框
Ctrl++ 放大
Ctrl-- 缩小
↑→↓← 键盘箭头移动选定的矩形框
预定义类别在路径:
labelImg/data/predefined_classes.txt
5: deep sort
6: Re-ID 训练
行人重识别和人脸识别是类似的,刚开始接触的可以认为就是人脸换成行人的识别。
边缘计算可以用简单的HOG提取特征
或者优化特征提取网络,利用ShuffleNetV2-05代替原来的网络进行训练
有GPU情况下,也可直接训练原有的Re-ID模型:
数据集
Market-1501 数据集在清华大学校园中采集,夏天拍摄,在 2015 年构建并公开。它包括由6个摄像头(其中5个高清摄像头和1个低清摄像头)拍摄到的 1501 个行人、32668 个检测到的行人矩形框。每个行人至少由2个摄像头捕获到,并且在一个摄像头中可能具有多张图像。训练集有 751 人,包含 12,936 张图像,平均每个人有 17.2 张训练数据;测试集有 750 人,包含 19,732 张图像,平均每个人有 26.3 张测试数据。3368 张查询图像的行人检测矩形框是人工绘制的,而 gallery 中的行人检测矩形框则是使用DPM检测器检测得到的。该数据集提供的固定数量的训练集和测试集均可以在single-shot或multi-shot测试设置下使用。
行人对齐+重识别网络
6: YOLOP
YOLOP: You Only Look Once for Panoptic Driving
Perception
测试数据集: BDD100K
https://arxiv.org/pdf/2108.11250.pdf
网络结果如下:
YOLOP采用 back,Neck和 head:
Train : BDD100k
Test : BDD100k
速度:TX2 23FPS
thind t470p gpu: python 500ms 0.5s
如果用
Train : BDD100k
Test : BDD100k
如果用
Train : BDD100k
Test : CUlane
7: 多模型融合代码:
检测模型 + 车道线模型:
效果如下:
速度:
thinpad T470p gpu 940mx
车道线50ms + 检测40ms = 90ms