DataWhale AI夏令营 2024大运河杯-数据开发应用创新赛-task3

本文主要是介绍DataWhale AI夏令营 2024大运河杯-数据开发应用创新赛-task3,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

DataWhale AI夏令营 2024大运河杯-数据开发应用创新赛

  • 数据增强
  • 数据收集
  • 打标签

多的不说少的不唠,之前说过初赛基本就是比谁的数据好了,因为原始数据的质量太低了想跑到0.25都很难所以需要使用一些数据增强策略以及收集一些新的数据集。

数据增强

计算机视觉中有一个应用比较广泛的包,来进行数据增强transforms,其中包含了一些图像增强的常见策略比如调整大小、裁剪、归一化、随机反转等等。如果大家想从事计算机视觉方面的工作可以去了解一下,这里我不过多赘述。
这里提供一份使用transforms进行数据增强的代码。

# -*- coding: utf-8 -*-
"""
Created on 2023-04-01 9:08
@author: Fan yi ming
Func: 对于目标检测的数据增强[YOLO](特点是数据增强后标签也要更改)
review:常用的数据增强方式;1.翻转:左右和上下翻转,随机翻转2.随机裁剪,图像缩放3.改变色调4.添加噪声
注意: boxes的标签和坐标一个是int,一个是float,存放的时候要注意处理方式。
参考:https://github.com/REN-HT/Data-Augmentation/blob/main/data_augmentation.py
"""
import torch
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFileImageFile.LOAD_TRUNCATED_IMAGES = True
from torchvision import transforms
import numpy as np
import matplotlib.pyplot as plt
import os
import randomrandom.seed(0)class DataAugmentationOnDetection:def __init__(self):super(DataAugmentationOnDetection, self).__init__()# 以下的几个参数类型中,image的类型全部如下类型# 参数类型: image:Image.open(path)def resize_keep_ratio(self, image, boxes, target_size):"""参数类型: image:Image.open(path), boxes:Tensor, target_size:int功能:将图像缩放到size尺寸,调整相应的boxes,同时保持长宽比(最长的边是target size"""old_size = image.size[0:2]  # 原始图像大小# 取最小的缩放比例ratio = min(float(target_size) / (old_size[i]) for i in range(len(old_size)))  # 计算原始图像宽高与目标图像大小的比例,并取其中的较小值new_size = tuple([int(i * ratio) for i in old_size])  # 根据上边求得的比例计算在保持比例前提下得到的图像大小# boxes 不用变化,因为是等比例变化return image.resize(new_size, Image.BILINEAR), boxesdef resizeDown_keep_ratio(self, image, boxes, target_size):""" 与上面的函数功能类似,但它只降低图片的尺寸,不会扩大图片尺寸"""old_size = image.size[0:2]  # 原始图像大小# 取最小的缩放比例ratio = min(float(target_size) / (old_size[i]) for i in range(len(old_size)))  # 计算原始图像宽高与目标图像大小的比例,并取其中的较小值ratio = min(ratio, 1)new_size = tuple([int(i * ratio) for i in old_size])  # 根据上边求得的比例计算在保持比例前提下得到的图像大小# boxes 不用变化,因为是等比例变化return image.resize(new_size, Image.BILINEAR), boxesdef resize(self, img, boxes, size):# ---------------------------------------------------------# 类型为 img=Image.open(path),boxes:Tensor,size:int# 功能为:将图像长和宽缩放到指定值size,并且相应调整boxes# ---------------------------------------------------------return img.resize((size, size), Image.BILINEAR), boxesdef random_flip_horizon(self, img, boxes, h_rate=1):# -------------------------------------# 随机水平翻转# -------------------------------------if np.random.random() < h_rate:transform = transforms.RandomHorizontalFlip(p=1)img = transform(img)if len(boxes) > 0:x = 1 - boxes[:, 1]boxes[:, 1] = xreturn img, boxesdef random_flip_vertical(self, img, boxes, v_rate=1):# 随机垂直翻转if np.random.random() < v_rate:transform = transforms.RandomVerticalFlip(p=1)img = transform(img)if len(boxes) > 0:y = 1 - boxes[:, 2]boxes[:, 2] = yreturn img, boxesdef center_crop(self, img, boxes, target_size=None):# -------------------------------------# 中心裁剪 ,裁剪成 (size, size) 的正方形, 仅限图形,w,h# 这里用比例是很难算的,转成x1,y1, x2, y2格式来计算# -------------------------------------w, h = img.sizesize = min(w, h)if len(boxes) > 0:# 转换到xyxy格式label = boxes[:, 0].reshape([-1, 1])x_, y_, w_, h_ = boxes[:, 1], boxes[:, 2], boxes[:, 3], boxes[:, 4]x1 = (w * x_ - 0.5 * w * w_).reshape([-1, 1])y1 = (h * y_ - 0.5 * h * h_).reshape([-1, 1])x2 = (w * x_ + 0.5 * w * w_).reshape([-1, 1])y2 = (h * y_ + 0.5 * h * h_).reshape([-1, 1])boxes_xyxy = torch.cat([x1, y1, x2, y2], dim=1)# 边框转换if w > h:boxes_xyxy[:, [0, 2]] = boxes_xyxy[:, [0, 2]] - (w - h) / 2else:boxes_xyxy[:, [1, 3]] = boxes_xyxy[:, [1, 3]] - (h - w) / 2in_boundary = [i for i in range(boxes_xyxy.shape[0])]for i in range(boxes_xyxy.shape[0]):# 判断x是否超出界限if (boxes_xyxy[i, 0] < 0 and boxes_xyxy[i, 2] < 0) or (boxes_xyxy[i, 0] > size and boxes_xyxy[i, 2] > size):in_boundary.remove(i)# 判断y是否超出界限elif (boxes_xyxy[i, 1] < 0 and boxes_xyxy[i, 3] < 0) or (boxes_xyxy[i, 1] > size and boxes_xyxy[i, 3] > size):in_boundary.append(i)boxes_xyxy = boxes_xyxy[in_boundary]boxes = boxes_xyxy.clamp(min=0, max=size).reshape([-1, 4])  # 压缩到固定范围label = label[in_boundary]# 转换到YOLO格式x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]xc = ((x1 + x2) / (2 * size)).reshape([-1, 1])yc = ((y1 + y2) / (2 * size)).reshape([-1, 1])wc = ((x2 - x1) / size).reshape([-1, 1])hc = ((y2 - y1) / size).reshape([-1, 1])boxes = torch.cat([xc, yc, wc, hc], dim=1)# 图像转换transform = transforms.CenterCrop(size)img = transform(img)if target_size:img = img.resize((target_size, target_size), Image.BILINEAR)if len(boxes) > 0:return img, torch.cat([label.reshape([-1, 1]), boxes], dim=1)else:return img, boxes# ------------------------------------------------------# 以下img皆为Tensor类型# ------------------------------------------------------def random_bright(self, img, u=120, p=1):# -------------------------------------# 随机亮度变换# -------------------------------------if np.random.random() < p:alpha = np.random.uniform(-u, u) / 255img += alphaimg = img.clamp(min=0.0, max=1.0)return imgdef random_contrast(self, img, lower=0.5, upper=1.5, p=1):# -------------------------------------# 随机增强对比度# -------------------------------------if np.random.random() < p:alpha = np.random.uniform(lower, upper)img *= alphaimg = img.clamp(min=0, max=1.0)return imgdef random_saturation(self, img, lower=0.5, upper=1.5, p=1):# 随机饱和度变换,针对彩色三通道图像,中间通道乘以一个值if np.random.random() < p:alpha = np.random.uniform(lower, upper)img[1] = img[1] * alphaimg[1] = img[1].clamp(min=0, max=1.0)return imgdef add_gasuss_noise(self, img, mean=0, std=0.1):noise = torch.normal(mean, std, img.shape)img += noiseimg = img.clamp(min=0, max=1.0)return imgdef add_salt_noise(self, img):noise = torch.rand(img.shape)alpha = np.random.random() / 5 + 0.7img[noise[:, :, :] > alpha] = 1.0return imgdef add_pepper_noise(self, img):noise = torch.rand(img.shape)alpha = np.random.random() / 5 + 0.7img[noise[:, :, :] > alpha] = 0return imgdef plot_pics(img, boxes):# 显示图像和候选框,img是Image.Open()类型, boxes是Tensor类型plt.imshow(img)label_colors = [(213, 110, 89)]w, h = img.sizefor i in range(boxes.shape[0]):box = boxes[i, 1:]xc, yc, wc, hc = boxx = w * xc - 0.5 * w * wcy = h * yc - 0.5 * h * hcbox_w, box_h = w * wc, h * hcplt.gca().add_patch(plt.Rectangle(xy=(x, y), width=box_w, height=box_h,edgecolor=[c / 255 for c in label_colors[0]],fill=False, linewidth=2))plt.show()def get_image_list(image_path):# 根据图片文件,查找所有图片并返回列表files_list = []for root, sub_dirs, files in os.walk(image_path):for special_file in files:special_file = special_file[0: len(special_file)]files_list.append(special_file)return files_listdef get_label_file(label_path, image_name):# 根据图片信息,查找对应的labelfname = os.path.join(label_path, image_name[0: len(image_name) - 4] + ".txt")data2 = []if not os.path.exists(fname):return data2if os.path.getsize(fname) == 0:return data2else:with open(fname, 'r', encoding='utf-8') as infile:# 读取并转换标签for line in infile:data_line = line.strip("\n").split()data2.append([float(i) for i in data_line])return data2def save_Yolo(img, boxes, save_path, prefix, image_name):# img: 需要时Image类型的数据, prefix 前缀# 将结果保存到save path指示的路径中if not os.path.exists(save_path) or \not os.path.exists(os.path.join(save_path, "images")):os.makedirs(os.path.join(save_path, "images"))os.makedirs(os.path.join(save_path, "labels"))try:img.save(os.path.join(save_path, "images", prefix + image_name))with open(os.path.join(save_path, "labels", prefix + image_name[0:len(image_name) - 4] + ".txt"), 'w',encoding="utf-8") as f:if len(boxes) > 0:  # 判断是否为空# 写入新的label到文件中for data in boxes:str_in = ""for i, a in enumerate(data):if i == 0:str_in += str(int(a))else:str_in += " " + str(float(a))f.write(str_in + '\n')except:print("ERROR: ", image_name, " is bad.")def runAugumentation(image_path, label_path, save_path):image_list = get_image_list(image_path)for image_name in image_list:print("dealing: " + image_name)img = Image.open(os.path.join(image_path, image_name))boxes = get_label_file(label_path, image_name)boxes = torch.tensor(boxes)# 下面是执行的数据增强功能,可自行选择# Image类型的参数DAD = DataAugmentationOnDetection()""" 尺寸变换   """# 缩小尺寸# t_img, t_boxes = DAD.resizeDown_keep_ratio(img, boxes, 1024)# save_Yolo(t_img, boxes, save_path, prefix="rs_", image_name=image_name)# 水平旋转t_img, t_boxes = DAD.random_flip_horizon(img, boxes.clone())save_Yolo(t_img, t_boxes, save_path, prefix="fh_", image_name=image_name)# 竖直旋转t_img, t_boxes = DAD.random_flip_vertical(img, boxes.clone())save_Yolo(t_img, t_boxes, save_path, prefix="fv_", image_name=image_name)# center_cropt_img, t_boxes = DAD.center_crop(img, boxes.clone(), 1024)save_Yolo(t_img, t_boxes, save_path, prefix="cc_", image_name=image_name)""" 图像变换,用tensor类型"""to_tensor = transforms.ToTensor()to_image = transforms.ToPILImage()img = to_tensor(img)# random_brightt_img, t_boxes = DAD.random_bright(img.clone()), boxessave_Yolo(to_image(t_img), boxes, save_path, prefix="rb_", image_name=image_name)# random_contrast 对比度变化t_img, t_boxes = DAD.random_contrast(img.clone()), boxessave_Yolo(to_image(t_img), boxes, save_path, prefix="rc_", image_name=image_name)# random_saturation 饱和度变化t_img, t_boxes = DAD.random_saturation(img.clone()), boxessave_Yolo(to_image(t_img), boxes, save_path, prefix="rs_", image_name=image_name)# 高斯噪声t_img, t_boxes = DAD.add_gasuss_noise(img.clone()), boxessave_Yolo(to_image(t_img), boxes, save_path, prefix="gn_", image_name=image_name)# add_salt_noiset_img, t_boxes = DAD.add_salt_noise(img.clone()), boxessave_Yolo(to_image(t_img), boxes, save_path, prefix="sn_", image_name=image_name)# add_pepper_noiset_img, t_boxes = DAD.add_pepper_noise(img.clone()), boxessave_Yolo(to_image(t_img), boxes, save_path, prefix="pn_", image_name=image_name)print("end:     " + image_name)if __name__ == '__main__':# 图像和标签文件夹image_path = "./yolo-dataset-lwb/val"label_path = "./yolo-dataset-lwb/val_txt"save_path = "./yolo-dataset-lwb/save_val"  # 结果保存位置路径,可以是一个不存在的文件夹# 运行runAugumentation(image_path, label_path, save_path)

因为YOLOV8为我们集成好了很多的数据增强策略了已经。
以下是YOLOV8在训练中已经使用的一些策略,大家也可以调参使用。

参数范围功能
hsv_h默认0.015,可调范围是0.0~1.0调整图像的色调,引入颜色可变性。
hsv_s默认0.7,可调范围是0.0~1.0调整图像的饱和度。
translate默认0.1,可调范围是0.0~1.0平移一小部分图像。
scale默认0.5,可调范围是大于等于0.0都可以缩放图像。
fliplr默认为0.5,可调范围是0.0~1.0以指定的概率将图像从左向右翻转,左右镜像。
mosaic默认为1.0,可调范围是0.0~1.0将四个训练图像组合为一个。
auto_augment默认为randaugment,可调范围是(randaugment、autoaugment和augmix)面向分类任务,自动应用预定义的增强策略。
erasing默认为0.4,可调范围是0.0~0.9在分类训练过程中随机擦除图像的一部分。
crop_fraction默认为1.0,可调范围是0.1~1.0将分类图像裁剪到其大小的一小部分。

以下是YOLOV8未使用的一些增强策略

参数范围功能
degrees范围是-180~+180在指定的度数范围内随机旋转图像。
shear范围是-180~+180以指定的角度剪切图像。
perspective范围是0.0~0.001将随机透视变换应用于图像。
flipud范围是0.0~1.0以指定的概率将图像倒置。
bgr范围是0.0~1.0以指定的概率将图像通道从RGB翻转到BGR。
mixup范围是0.0~1.0混合两个图像及其标签,创建合成图像。
copy_paste范围是0.0~1.0将对象从一个图像中复制并粘贴到另一个图像上。

这里是一篇关于YOLOV8各个参数功能详细介绍的大佬原文添加链接描述建议像详细了解参数功能的可以去看一下。
参数的使用方法如下(直接在train中使用即可):

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"import warnings
warnings.filterwarnings('ignore')from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model.train(data="yolo-dataset/yolo.yaml", epochs=2, imgsz=1080, batch=16, copy_paste=0.2, mixup=0.5)

数据收集

然后大家可以观察一下官方大大给出的数据集,其实大多视频都是同一个场景或者标签有错误,所以如果想卷的话还是要自己动手收集数据打标签,这里我也给大家推荐几个数据集。
这里是一个飞桨提供的一个垃圾桶的数据集大家可以去找一些适合本次大赛的图片添加到训练集中垃圾桶溢满数据集。
这个是极市在2022年的一个比赛的数据集,里面的图片看例图和本次本赛还是很贴近的,但是这个目前极市官方是不公开数据的,不过这个比赛当视很火,应该可以在网上找到资源机动车违停识别。

打标签

感觉写到上面有点水笔记,再加个打标签吧,虽然能参加比赛的佬基本都会。
首先先创建一个打标签的环境

conda create -n label python=3.8

激活环境

conda activate label

安装labelme

pip install labelme

等待安装完成使用在终端输入labelme启动labelme

labelme

启动后界面如下
在这里插入图片描述
点击打开目录选择你数据集所在的文件夹即可,接着选择‘文件-更改输出路径’,这里建议图片和标签不要放在一起,因为labelme标注后的数据不是yolo的格式需要进一步的转化才能使用。
这里提供一个转标签的python文件

# # trans_labelme_to_yolo.py
import cv2
import os
import json
import shutil
import numpy as np
from pathlib import Path
from glob import glob# id2cls = {0: 'clothing'}
# cls2id = {'clothing': 0}
id2cls = {0: '非机动车违停', 1: '机动车违停', 2: '垃圾桶满溢', 3:'违法经营'}
cls2id = {'非机动车违停': 0, '机动车违停': 1, '垃圾桶满溢': 2, '违法经营': 3}# 支持中文路径
def cv_imread(filePath):cv_img = cv2.imdecode(np.fromfile(filePath, dtype=np.uint8), flags=cv2.IMREAD_COLOR)return cv_imgdef labelme2yolo_single(img_path, label_file):anno = json.load(open(label_file, "r", encoding="utf-8"))shapes = anno['shapes']w0, h0 = anno['imageWidth'], anno['imageHeight']image_path = os.path.basename(img_path + anno['imagePath'])labels = []for s in shapes:pts = s['points']x1, y1 = pts[0]x2, y2 = pts[1]x = (x1 + x2) / 2 / w0y = (y1 + y2) / 2 / h0w = abs(x2 - x1) / w0h = abs(y2 - y1) / h0cid = cls2id[s['label']]labels.append([cid, x, y, w, h])return np.array(labels), image_pathdef labelme2yolo(img_path, labelme_label_dir, save_dir='res/'):labelme_label_dir = str(Path(labelme_label_dir)) + '/'save_dir = str(Path(save_dir))yolo_label_dir = save_dir + '/'if not os.path.exists(yolo_label_dir):os.makedirs(yolo_label_dir)json_files = glob(labelme_label_dir + '*.json')for ijf, jf in enumerate(json_files):print(ijf + 1, '/', len(json_files), jf)filename = os.path.basename(jf).rsplit('.', 1)[0]labels, image_path = labelme2yolo_single(img_path, jf)if len(labels) > 0:# 在这里我们对np.savetxt的调用做了修改np.savetxt(yolo_label_dir + filename + '.txt', labels, fmt='%d %0.16f %0.16f %0.16f %0.16f')# shutil.copy(labelme_label_dir + image_path, yolo_image_dir + image_path)print('Completed!')if __name__ == '__main__':img_path = './yolo-dataset-lwb/val'  # 数据集图片的路径json_dir = './yolo-dataset-lwb/val_json'  # json标签的路径save_dir = './yolo-dataset-lwb/val_txt'  # 保存的txt标签的路径labelme2yolo(img_path, json_dir, save_dir)

这篇关于DataWhale AI夏令营 2024大运河杯-数据开发应用创新赛-task3的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1124779

相关文章

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

Redis事务与数据持久化方式

《Redis事务与数据持久化方式》该文档主要介绍了Redis事务和持久化机制,事务通过将多个命令打包执行,而持久化则通过快照(RDB)和追加式文件(AOF)两种方式将内存数据保存到磁盘,以防止数据丢失... 目录一、Redis 事务1.1 事务本质1.2 数据库事务与redis事务1.2.1 数据库事务1.

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

Oracle Expdp按条件导出指定表数据的方法实例

《OracleExpdp按条件导出指定表数据的方法实例》:本文主要介绍Oracle的expdp数据泵方式导出特定机构和时间范围的数据,并通过parfile文件进行条件限制和配置,文中通过代码介绍... 目录1.场景描述 2.方案分析3.实验验证 3.1 parfile文件3.2 expdp命令导出4.总结

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

更改docker默认数据目录的方法步骤

《更改docker默认数据目录的方法步骤》本文主要介绍了更改docker默认数据目录的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1.查看docker是否存在并停止该服务2.挂载镜像并安装rsync便于备份3.取消挂载备份和迁

不删数据还能合并磁盘? 让电脑C盘D盘合并并保留数据的技巧

《不删数据还能合并磁盘?让电脑C盘D盘合并并保留数据的技巧》在Windows操作系统中,合并C盘和D盘是一个相对复杂的任务,尤其是当你不希望删除其中的数据时,幸运的是,有几种方法可以实现这一目标且在... 在电脑生产时,制造商常为C盘分配较小的磁盘空间,以确保软件在运行过程中不会出现磁盘空间不足的问题。但在

java中VO PO DTO POJO BO DO对象的应用场景及使用方式

《java中VOPODTOPOJOBODO对象的应用场景及使用方式》文章介绍了Java开发中常用的几种对象类型及其应用场景,包括VO、PO、DTO、POJO、BO和DO等,并通过示例说明了它... 目录Java中VO PO DTO POJO BO DO对象的应用VO (View Object) - 视图对象