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

相关文章

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分