南阳做做网站,烟台网站主关键词,做网站 广州,网站制作的销售对象主干目录#xff1a;
【YOLOV5-6.x 版本讲解】整体项目代码注释导航现在YOLOV5已经更新到6.X版本#xff0c;现在网上很多还停留在5.X的源码注释上#xff0c;因此特开一贴传承开源精神#xff01;5.X版本的可以看其他大佬的帖子本文章主要从6.X版本出发#xff0c;主要解… 主干目录
【YOLOV5-6.x 版本讲解】整体项目代码注释导航现在YOLOV5已经更新到6.X版本现在网上很多还停留在5.X的源码注释上因此特开一贴传承开源精神5.X版本的可以看其他大佬的帖子本文章主要从6.X版本出发主要解决6.X版本的项目注释与代码分析......https://blog.csdn.net/qq_39237205/article/details/125729662
以下内容为本栏目的一部分更多关注以上链接目录查找YOLOV5的更多信息
祝福你朋友早日发表sci 1 数据增强的作用
分割需要在像素级别进行标签标注一些专业领域的图像标注依赖于专业人士的知识素养在数据集规模很小的情况如何提高模型的表现力迁移学习使得具有大量标注数据的源域帮助提升模型的训练效果数据增强 学习到空间的不变形像素级别的不变形特征都有限利用平移缩放旋转改变色调值等方法让模型见过各种类型的数据提高模型在测试数据上的判别力
2 YOLO数据增强的方法
2.1 rectangular
2.1.1 含义
同个batch里做rectangle宽高等比变换 加快训练 对于多余的黑边做到最小实现降低计算量。
2.1.2 图解 2.1.3 代码
# 文件位置utils/datasets.py
# 6、为Rectangular Training作准备即减少大小不同图片处理时对于多余的黑边做到最小实现降低计算量# 这里主要是注意shapes的生成 这一步很重要 因为如果采样矩形训练那么整个batch的形状要一样 就要计算这个符合整个batch的shape# 而且还要对数据集按照高宽比进行排序 这样才能保证同一个batch的图片的形状差不多相同 再选择一个共同的shape代价也比较小if self.rect:# 所有训练图片的shapes self.shapes # wh# 计算高宽比ar s[:, 1] / s[:, 0] # aspect ratioirect ar.argsort() # 根据高宽比排序self.img_files [self.img_files[i] for i in irect] # 获取排序后的img_filesself.label_files [self.label_files[i] for i in irect] # 获取排序后的label_filesself.labels [self.labels[i] for i in irect] # 获取排序后的labelsself.shapes s[irect] # 获取排序后的whar ar[irect] # 获取排序后的wh# 计算每个batch采用的统一尺度 Set training image shapesshapes [[1, 1]] * nbfor i in range(nb):# 同一个batch的图片提取出来ari ar[bi i]mini, maxi ari.min(), ari.max() # 获取第i个batch中最小和最大高宽比if maxi 1:# [H,W]如果高/宽小于1(w h)宽大于高矮胖型(img_size*maxi,img_size)保证原图像尺度不变进行缩放shapes[i] [maxi, 1]elif mini 1:# [H,W]如果高/宽大于1(w h)宽小于高瘦高型(img_size,img_size *1/mini)保证原图像尺度不变进行缩放shapes[i] [1, 1 / mini]# 计算每个batch输入网络的shape值(向上设置为32的整数倍)# 要求每个batch_shapes的高宽都是32的整数倍所以要先除以32取整再乘以32不过img_size如果是32倍数这里就没必要了self.batch_shapes np.ceil(np.array(shapes) * img_size / stride pad).astype(np.int) * stride
2.2 HSV变换
2.2.1 含义 HSV-Hue augmentation (fraction) 色调 HSV-Saturation augmentation (fraction) 饱和度 HSV-Value augmentation (fraction) 曝光度
2.2.2 图解效果 2.2.3 代码
# 调用函数的文件位置文件位置utils/datasets.py
# 色域空间增强Augment colorspaceH色调、S饱和度、V亮度
# 通过一些随机值改变hsv实现数据增强
augment_hsv(img, hgainhyp[hsv_h], sgainhyp[hsv_s], vgainhyp[hsv_v])# 被调用的函数位置utils/augmentations.py
def augment_hsv(im, hgain0.5, sgain0.5, vgain0.5):# HSV color-space augmentationif hgain or sgain or vgain:r np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] 1 # random gainshue, sat, val cv2.split(cv2.cvtColor(im, cv2.COLOR_BGR2HSV))dtype im.dtype # uint8x np.arange(0, 256, dtyper.dtype)lut_hue ((x * r[0]) % 180).astype(dtype)lut_sat np.clip(x * r[1], 0, 255).astype(dtype)lut_val np.clip(x * r[2], 0, 255).astype(dtype)im_hsv cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val)))cv2.cvtColor(im_hsv, cv2.COLOR_HSV2BGR, dstim) # no return needed
2.3 随机旋转、平移、缩放、裁剪错切/非垂直投影 、透视变换从0开始
2.3.1.1 旋转缩放 分析 src为左边图片dst为右边旋转缩放变换后的图片 xy为横纵坐标 M为旋转缩放矩阵 旋转参数主要是M[0,1], M[1, 0]起作用, 且M[0,1], M[1, 0]互为相反数 缩放参数主要是M[0,0], M[1,1]起作用
2.3.1.2 平移 src为左边图片, dst为右边旋转缩放变换后的图片 xy为横纵坐标 M为平移矩阵 x轴平移参数主要是M[0,2]起作用 y轴平移参数主要是M[1,2]起作用
2.3.1.3 错切/非垂直投影 错切的类似于固定图片一边 对另外平行一边施加一个推力形成的变形 src为左边图片, dst为右边错切变换后的图片 xy为横纵坐标 M为错切矩阵 错切参数主要是M[0,1], M[1, 0]起作用
2.3.1.4 透视变换 src为左边图片, dst为右边透视变换后的图片 xy为横纵坐标 M为变换矩阵 变换参数主要是M[2,0], M[2,1]起作用
2.3.2 代码实现
# 调用函数地址utils/datasets.py
# Augment# random_perspective Augment 随机透视变换 [1280, 1280, 3] [640, 640, 3]# 对mosaic整合后的图片进行随机旋转、平移、缩放、裁剪透视变换并resize为输入大小img_size
img4, labels4 random_perspective(img4, labels4, segments4,degreesself.hyp[degrees], # 旋转translateself.hyp[translate], # 平移scaleself.hyp[scale], # 缩放shearself.hyp[shear], # 错切/非垂直投影perspectiveself.hyp[perspective], # 透视变换borderself.mosaic_border) # border to remove# 被调用的函数地址utils/augmentations.py
def random_perspective(im, targets(), segments(), degrees10, translate.1, scale.1, shear10, perspective0.0,border(0, 0)):# torchvision.transforms.RandomAffine(degrees(-10, 10), translate(0.1, 0.1), scale(0.9, 1.1), shear(-10, 10))# targets [cls, xyxy]height im.shape[0] border[0] * 2 # shape(h,w,c)width im.shape[1] border[1] * 2# CenterC np.eye(3)C[0, 2] -im.shape[1] / 2 # x translation (pixels)C[1, 2] -im.shape[0] / 2 # y translation (pixels)# Perspective # 透视变换P np.eye(3)P[2, 0] random.uniform(-perspective, perspective) # x perspective (about y)P[2, 1] random.uniform(-perspective, perspective) # y perspective (about x)# Rotation and Scale 旋转缩放R np.eye(3)a random.uniform(-degrees, degrees)# a random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotationss random.uniform(1 - scale, 1 scale)# s 2 ** random.uniform(-scale, scale)R[:2] cv2.getRotationMatrix2D(anglea, center(0, 0), scales)# Shear 错切/非垂直投影S np.eye(3)S[0, 1] math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg)S[1, 0] math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg)# Translation 平移T np.eye(3)T[0, 2] random.uniform(0.5 - translate, 0.5 translate) * width # x translation (pixels)T[1, 2] random.uniform(0.5 - translate, 0.5 translate) * height # y translation (pixels)# Combined rotation matrix# 将所有变换矩阵连乘得到最终的变换矩阵M T S R P C # order of operations (right to left) is IMPORTANTif (border[0] ! 0) or (border[1] ! 0) or (M ! np.eye(3)).any(): # image changedif perspective:im cv2.warpPerspective(im, M, dsize(width, height), borderValue(114, 114, 114))else: # affineim cv2.warpAffine(im, M[:2], dsize(width, height), borderValue(114, 114, 114))# Visualize# import matplotlib.pyplot as plt# ax plt.subplots(1, 2, figsize(12, 6))[1].ravel()# ax[0].imshow(im[:, :, ::-1]) # base# ax[1].imshow(im2[:, :, ::-1]) # warped# Transform label coordinatesn len(targets)if n:use_segments any(x.any() for x in segments)new np.zeros((n, 4))if use_segments: # warp segmentssegments resample_segments(segments) # upsample# 其中 segment.shape [n, 2], 表示物体轮廓各个坐标点for i, segment in enumerate(segments):xy np.ones((len(segment), 3))xy[:, :2] segmentxy xy M.T # transform 应用旋转矩阵xy xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2] # perspective rescale or affine# clipnew[i] segment2box(xy, width, height)else: # warp boxes 如果是box坐标, 这里targets每行为[x1,y1,x2,y2],n为行数,表示目标边框个数xy np.ones((n * 4, 3))xy[:, :2] targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1xy xy M.T # transform 应用旋转矩阵# 如果透视变换参数perspective不为0 就需要做rescale透视变换参数为0, 则无需做rescale。xy (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]).reshape(n, 8) # perspective rescale or affine# create new boxesx xy[:, [0, 2, 4, 6]]y xy[:, [1, 3, 5, 7]]new np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T# clip 将坐标clip到[0, width],[0,height]区间内new[:, [0, 2]] new[:, [0, 2]].clip(0, width)new[:, [1, 3]] new[:, [1, 3]].clip(0, height)# filter candidates 进一步过滤,留下那些w,h2,宽高比20,变换后面积比之前比0.1的那些xyi box_candidates(box1targets[:, 1:5].T * s, box2new.T, area_thr0.01 if use_segments else 0.10)targets targets[i]targets[:, 1:5] new[i]return im, targets
2.3.3 代码逻辑描述 2.4 翻转 2.5 四图拼接
2.5.1 含义 初始化整个背景图, 大小为(2 × image_size, 2 × image_size, 3) 随机取一个中心点 基于中心点分别将4个图放到左上,右上,左下,右下,此部分可能会由于中心点小于4张图片的宽高 所以拼接的时候可能会进行裁剪重新将打标边框的偏移量计算上
2.5.2 图解 2.5.3 需要裁剪 2.5.4 代码实现 # 代码位置utils/datasets.pydef load_mosaic(self, index):用在LoadImagesAndLabels模块的__getitem__函数 进行mosaic数据增强将四张图片拼接在一张马赛克图像中 loads images in a 4-mosaic:param index: 需要获取的图像索引:return: img4: mosaic和随机透视变换后的一张图片 numpy(640, 640, 3)labels4: img4对应的target [M, clsx1y1x2y2]# labels4: 用于存放拼接图像4张图拼成一张的label信息(不包含segments多边形)# segments4: 用于存放拼接图像4张图拼成一张的label信息(包含segments多边形)labels4, segments4 [], []s self.img_size # 一般的图片大小# 随机初始化拼接图像的中心点坐标 [0, s*2]之间随机取2个数作为拼接图像的中心坐标yc, xc (int(random.uniform(-x, 2 * s x)) for x in self.mosaic_border) # mosaic center x, y# 从dataset中随机寻找额外的三张图像进行拼接 [14, 26, 2, 16] 再随机选三张图片的indexindices [index] random.choices(self.indices, k3) # 3 additional image indicesrandom.shuffle(indices)# 遍历四张图像进行拼接 4张不同大小的图像 1张[1472, 1472, 3]的图像for i, index in enumerate(indices):# load image 每次拿一张图片 并将这张图片resize到self.size(h,w)img, _, (h, w) self.load_image(index)# place img in img4if i 0: # top left 原图[375, 500, 3] load_image-[552, 736, 3] hwc# 创建马赛克图像 [1472, 1472, 3][h, w, c]img4 np.full((s * 2, s * 2, img.shape[2]), 114, dtypenp.uint8) # base image with 4 tiles# 计算马赛克图像中的坐标信息(将图像填充到马赛克图像中) w736 h 552 马赛克图像(x1a,y1a)左上角 (x2a,y2a)右下角x1a, y1a, x2a, y2a max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image)# 计算截取的图像区域信息(以xc,yc为第一张图像的右下角坐标填充到马赛克图像中丢弃越界的区域) 图像(x1b,y1b)左上角 (x2b,y2b)右下角x1b, y1b, x2b, y2b w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image)elif i 1: # top right# 计算马赛克图像中的坐标信息(将图像填充到马赛克图像中)x1a, y1a, x2a, y2a xc, max(yc - h, 0), min(xc w, s * 2), yc# 计算截取的图像区域信息(以xc,yc为第二张图像的左下角坐标填充到马赛克图像中丢弃越界的区域)x1b, y1b, x2b, y2b 0, h - (y2a - y1a), min(w, x2a - x1a), helif i 2: # bottom left# 计算马赛克图像中的坐标信息(将图像填充到马赛克图像中)x1a, y1a, x2a, y2a max(xc - w, 0), yc, xc, min(s * 2, yc h)# 计算截取的图像区域信息(以xc,yc为第三张图像的右上角坐标填充到马赛克图像中丢弃越界的区域)x1b, y1b, x2b, y2b w - (x2a - x1a), 0, w, min(y2a - y1a, h)elif i 3: # bottom right# 计算马赛克图像中的坐标信息(将图像填充到马赛克图像中)x1a, y1a, x2a, y2a xc, yc, min(xc w, s * 2), min(s * 2, yc h)# 计算截取的图像区域信息(以xc,yc为第四张图像的左上角坐标填充到马赛克图像中丢弃越界的区域)x1b, y1b, x2b, y2b 0, 0, min(w, x2a - x1a), min(y2a - y1a, h)# 将截取的图像区域填充到马赛克图像的相应位置 img4[h, w, c]# 将图像img的【(x1b,y1b)左上角 (x2b,y2b)右下角】区域截取出来填充到马赛克图像的【(x1a,y1a)左上角 (x2a,y2a)右下角】区域img4[y1a:y2a, x1a:x2a] img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax]# 计算pad(当前图像边界与马赛克边界的距离越界的情况padw/padh为负值) 用于后面的label映射padw x1a - x1b # 当前图像与马赛克图像在w维度上相差多少padh y1a - y1b # 当前图像与马赛克图像在h维度上相差多少# labels: 获取对应拼接图像的所有正常label信息(如果有segments多边形会被转化为矩形label)# segments: 获取对应拼接图像的所有不正常label信息(包含segments多边形也包含正常gt)# 在新图中更新坐标值labels, segments self.labels[index].copy(), self.segments[index].copy()if labels.size:labels[:, 1:] xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy formatsegments [xyn2xy(x, w, h, padw, padh) for x in segments]labels4.append(labels) # 更新labels4segments4.extend(segments) # 更新segments4# Concat/clip labels4 把labels4[(2, 5), (1, 5), (3, 5), (1, 5)] (7, 5)压缩到一起labels4 np.concatenate(labels4, 0)# 防止越界 label[:, 1:]中的所有元素的值位置信息必须在[0, 2*s]之间,小于0就令其等于0,大于2*s就等于2*s out: 返回for x in (labels4[:, 1:], *segments4):np.clip(x, 0, 2 * s, outx) # clip when using random_perspective()# img4, labels4 replicate(img4, labels4) # replicate
2.6 图像互相融合
2.6.1 含义
是简单地将两张图叠加到一起 通过不同的透明度进行区分。
2.6.2 图解 2.6.3 代码实现
# 调用函数地址utils/datasets.py
if random.random() hyp[mixup]: # hyp[mixup]0 默认为0则关闭 默认为1则100%打开# *load_mosaic(self, random.randint(0, self.n - 1)) 随机从数据集中任选一张图片和本张图片进行mixup数据增强# img: 两张图片融合之后的图片 numpy (640, 640, 3)# labels: 两张图片融合之后的标签label [MN, clsx1y1x2y2]img, labels mixup(img, labels, *self.load_mosaic(random.randint(0, self.n - 1)))# 被调用函数地址utils/augmentations.py
def mixup(im, labels, im2, labels2):# Applies MixUp augmentation https://arxiv.org/pdf/1710.09412.pdfr np.random.beta(32.0, 32.0) # mixup ratio, alphabeta32.0im (im * r im2 * (1 - r)).astype(np.uint8)labels np.concatenate((labels, labels2), 0)return im, labels
2.7 分割填补
2.7.1 含义
分割出图像的目标后 需要计算该目标边框与填补图片中的所有目标边框IOU0.3(实现参数)
2.7.2 图解 2.7.3 代码 # 调用函数地址utils/datasets.py
img4, labels4, segments4 copy_paste(img4, labels4, segments4, pself.hyp[copy_paste])# 被调用函数地址utils/augmentations.py
def copy_paste(im, labels, segments, p0.5):# Implement Copy-Paste augmentation https://arxiv.org/abs/2012.07177, labels as nx5 np.array(cls, xyxy)n len(segments)if p and n:h, w, c im.shape # height, width, channelsim_new np.zeros(im.shape, np.uint8)for j in random.sample(range(n), kround(p * n)):l, s labels[j], segments[j]box w - l[3], l[2], w - l[1], l[4]ioa bbox_ioa(box, labels[:, 1:5]) # intersection over areaif (ioa 0.30).all(): # allow 30% obscuration of existing labelslabels np.concatenate((labels, [[l[0], *box]]), 0)segments.append(np.concatenate((w - s[:, 0:1], s[:, 1:2]), 1))cv2.drawContours(im_new, [segments[j].astype(np.int32)], -1, (255, 255, 255), cv2.FILLED)result cv2.bitwise_and(src1im, src2im_new)result cv2.flip(result, 1) # augment segments (flip left-right)i result 0 # pixels to replace# i[:, :] result.max(2).reshape(h, w, 1) # act over chim[i] result[i] # cv2.imwrite(debug.jpg, im) # debugreturn im, labels, segments