【YOLOV5-6.x讲解】数据增强方式介绍+代码实现

 主干目录:

【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 colorspace:H色调、S饱和度、V亮度
# 通过一些随机值改变hsv,实现数据增强
augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v'])# 被调用的函数位置:utils/augmentations.py
def augment_hsv(im, hgain=0.5, sgain=0.5, vgain=0.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, dtype=r.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, dst=im)  # 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,degrees=self.hyp['degrees'], # 旋转translate=self.hyp['translate'], # 平移scale=self.hyp['scale'], # 缩放shear=self.hyp['shear'], # 错切/非垂直投影perspective=self.hyp['perspective'], # 透视变换border=self.mosaic_border)  # border to remove# 被调用的函数地址:utils/augmentations.py
def random_perspective(im, targets=(), segments=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.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(angle=a, center=(0, 0), scale=s)# 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,h>2,宽高比<20,变换后面积比之前比>0.1的那些xyi = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.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, cls+x1y1x2y2]"""# 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, k=3)  # 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, dtype=np.uint8)  # base image with 4 tiles# 计算马赛克图像中的坐标信息(将图像填充到马赛克图像中)   w=736  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, out=x)  # 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 [M+N, cls+x1y1x2y2]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, alpha=beta=32.0im = (im * r + im2 * (1 - r)).astype(np.uint8)labels = np.concatenate((labels, labels2), 0)return im, labels

2.7 分割填补

2.7.1 含义

分割出图像的目标后, 需要计算该目标边框与填补图片中的所有目标边框IOU<0.3(实现参数)

2.7.2 图解

2.7.3 代码

# 调用函数地址:utils/datasets.py
img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste'])# 被调用函数地址:utils/augmentations.py
def copy_paste(im, labels, segments, p=0.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), k=round(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(src1=im, src2=im_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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/469088.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android Input子系统-含实例源码

Android Input子系统-含实例源码 1 Input子系统作用 Android很多外设都是用到输入输出设备&#xff0c;比如touchscreen&#xff0c;键盘&#xff0c;音量键等&#xff0c;输入 设备对应Android 框架是Android input子系统&#xff0c;像我们定制类比较多的&#xff0c;很多 需…

【数据集显示标注】VOC文件结构+数据集标注可视化+代码实现

一、效果图&#xff1a; 显示&#xff1a;代码常见报错》正文开始↓ 一、Pascal VOC数据集介绍 Pascal VOC网址&#xff1a;http://host.robots.ox.ac.uk/pascal/VOC/ 训练/验证数据集下载&#xff08;2G&#xff09;&#xff1a;host.robots.ox.ac.uk/pascal/VOC/voc2012/VO…

tinyxml2遍历所有节点_Python实现二叉树的遍历

Outline&#xff1a;二叉树概念二叉树遍历&#xff08;前序、中序、后序、宽度优先遍历&#xff09;的迭代实现和递归实现&#xff1b;二叉树的深度&#xff0c;二叉树到leaf的所有路径。树&#xff08;Tree&#xff09;是一种抽象数据类型&#xff08;ADT&#xff09;&#xf…

如何监控NVIDIA Jetson的的运行状态和使用情况

一、NVIDIA Jetson介绍 NVIDIA Jetson是NVIDIA为新一代自主机器设计的嵌入式系统&#xff0c;是一个AI平台&#xff0c;所提供的性能和能效可提高自主机器软件的运行速度。每个系统都是一个完备的模块化系统&#xff0c;具备CPU、GPU、PMIC、DRAM和闪存。Jetson具备可扩展性&a…

atm取款机的简单程序代码_LeNet:一个简单的卷积神经网络PyTorch实现

前两篇文章分别介绍了卷积层和池化层&#xff0c;卷积和池化是卷积神经网络必备的两大基础。本文我们将介绍一个早期用来识别手写数字图像的卷积神经网络&#xff1a;LeNet[1]。LeNet名字来源于论文的第一作者Yann LeCun。1989年&#xff0c;LeNet使用卷积神经网络和梯度下降法…

【数据集转换】VOC数据集转COCO数据集·代码实现+操作步骤

在自己的数据集上实验时&#xff0c;往往需要将VOC数据集转化为coco数据集&#xff0c;因为这种需求所以才记录这篇文章&#xff0c;代码出处未知&#xff0c;感谢开源。 在远程服务器上测试目标检测算法需要用到测试集&#xff0c;最常用的是coco2014/2017和voc07/12数据集。 …

idea spring tomcat启动失败_技术篇 | 实用IDEA插件和工具系列

前 言本章主要分享一些工作中常用的IDEA插件(Maven Helper、Lombok、Mybatis Log Plugin、RestfulToolkit、JRebel And XRebel)和实用工具arthas。01Maven Helper作用&#xff1a;能清晰的查看当项目的Maven依赖版本、依赖关系、依赖冲突等情况。使用步骤&#xff1a;①安装后,…

【数据集可视化】VOC数据集标注可视化+代码实现

二、VOC可视化数据集 1、作用 在做目标检测时&#xff0c;首先要检查标注数据。一方面是要了解标注的情况&#xff0c;另一方面是检查数据集的标注和格式是否正确&#xff0c;只有正确的情况下才能进行下一步的训练。 2、代码实现 import os # import sys import cv2 import…

串口UART串行总线协议

串口UART 串行端口是异步的&#xff08;不传输时钟相关数据&#xff09;&#xff0c;两个设备在使用串口通信时&#xff0c;必须先约定一个数据传输速率&#xff0c;并且这两个设备各自的时钟频率必须与这个速率保持相近&#xff0c;某一方的时钟频率相差很大都会导致数据传输…

基于Springboot外卖系统01:技术构成+功能模块介绍

外卖系统是专门为餐饮企业&#xff08;餐厅、饭店&#xff09;定制的一款软件产品&#xff0c;包括 系统管理后台 和 移动端应用 两部分。其中系统管理后台主要提供给餐饮企业内部员工使用&#xff0c;可以对餐厅的分类、菜品、套餐、订单、员工等进行管理维护。移动端应用主要…

HTML5本地图片裁剪并上传

最近做了一个项目&#xff0c;这个项目中需要实现的一个功能是&#xff1a;用户自定义头像&#xff08;用户在本地选择一张图片&#xff0c;在本地将图片裁剪成满足系统要求尺寸的大小&#xff09;。这个功能的需求是&#xff1a;头像最初剪切为一个正方形。如果选择的图片小于…

嵌入式就应该这样学!!

嵌入式就应该这样学&#xff01;&#xff01; 1、Linux内核 Linux 内核定时器 Linux进程上下文和中断上下文内核空间和用户空间 Linux内核链表 Linux 内核模块编译 Linux内核使用Gdb调试 Linux动态打印kernel日志 Linux的中断可以嵌套吗 Linux内核定时器 Linux 驱动之Ioctl Lin…

基于Springboot外卖系统02:数据库搭建+Maven仓库搭建

1 数据库环境搭建 1.1 创建数据库 可以通过以下两种方式中的任意一种, 来创建项目的数据库: 1).图形界面 注意: 本项目数据库的字符串, 选择 utf8mb4 2).命令行 1.2 数据库表导入 项目的数据库创建好了之后, 可以直接将 资料/数据模型/db_reggie.sql 直接导入到数据库中, …

margin 负边距应用

margin-right:负值&#xff0c;在没有设置DOM元素宽度的前提下&#xff0c;DOM元素宽度变宽。 1 <!DOCTYPE html>2 <html lang"zh-CN">3 4 <head>5 <meta charset"UTF-8">6 <meta http-equiv"X-UA-Co…

基于Springboot外卖系统03:pom.xml导入依赖+数据库配置文件+Boot启动类+静态资源映射

1).在pom.xml中导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache…

写给过得很辛苦很迷茫的你~一定要看啊

#前面的话 我是一个农村的孩子&#xff0c;我家很穷&#xff0c;小时候过得非常苦&#xff0c;每次开学是我最害怕的时候&#xff0c;我害怕我爸妈拿不出学费&#xff0c;我害怕我爸妈会让我辍学在家帮忙干活&#xff0c;每次跟我妈吵架的时候&#xff0c;当我妈跟我说不让我读…

flatpickr功能强大的日期时间选择器插件

flatpickr日期时间选择器支持移动手机&#xff0c;提供多种内置的主题效果&#xff0c;并且提供对中文的支持。它的特点还有&#xff1a; 使用SVG作为界面的图标。 兼容jQuery。 支持对各种日期格式的解析。 轻量级&#xff0c;高性能&#xff0c;压缩后的版本仅6K大小。 对…

基于Springboot外卖系统04:后台系统用户登录+登出功能

登录业务流程 ① 在登录页面输入用户名和密码 ② 调用后台接口进行验证 ③ 通过验证之后&#xff0c;根据后台的响应状态跳转到项目主页 2. 登录业务的相关技术点 http 是无状态的通过 cookie 在客户端记录状态通过 session 在服务器端记录状态通过 token 方式维持状态如果前端…

排序算法时间复杂度、空间复杂度、稳定性比较

排序算法分类 排序算法比较表格填空 排序算法平均时间复杂度最坏时间复杂度空间复杂度是否稳定冒泡排序:————-::—–::—–::—–:选择排序:————-::—–::—–::—–:直接插入排序:————-::—–::—–::—–:归并排序:————-::—–::—–::—–:快速排序:———…

基于Springboot外卖系统05:用户非登陆状态的页面拦截器实现

1. 完善登录功能 1.1 问题分析 用户访问接口验证&#xff0c;如果用户没有登录&#xff0c;则不让他访问除登录外的任何接口。 1.前端登录&#xff0c;后端创建session&#xff0c;返给前端 2.前端访问其他接口&#xff0c;失效或不存在&#xff0c;则返回失效提示&#xff…