[AI]從零開始的YOLO數據集增強教程

一、前言

? ? ? ? 不知道大家在訓練YOLO時有沒有遇到過這樣的情況,明明數據集已經準備了很多了,但是YOLO還是不認識某個物品,或者置信度低。那么有沒有辦法讓我們不制作新數據集的情況下讓代碼幫我們生成新的數據集來訓練模型呢?當然有,并且現在最主流的辦法就是將原本的圖像進行翻轉,改變亮度,以及添加噪聲等。經過了這些步驟,就增加了我們數據集的多樣性,相當于增加了YOLO的樣本數量,這樣,YOLO模型就能夠認識更多樣的對象,從而實現數據集增強。那么本次教程,就來教大家如何使用簡單的處理代碼實現對YOLO數據集的增強!

二、需要準備什么?

? ? ? ? 既然需要對YOLO的訓練數據集進行增強,這里需要大已經安裝好YOLO環境并且對YOLO的訓練非常熟悉。如果你還沒有安裝好YOLO的推理環境可以直接看下面的教程:

YOLO環境搭建:[AI]小白向的YOLO安裝教程-CSDN博客

如果你還不會訓練YOLO模型可以看下面的教程:

YOLO模型訓練:[AI]YOLO如何訓練對象檢測模型(詳細)_yolo模型-CSDN博客

當部署好YOLO環境并且對YOLO推理非常熟悉以后就可以進行下面的步驟了。

三、YOLO數據集增強

? ? ? ? 這里我們需要對數據集進行增強,首先我們需要一個已經制作好的數據集,這里數據集的數量不用太多,我這里就準備了200張已經框好的數據集,用于識別花卉的碳黑病:

準備好對應的數據集,我們創新一個名為“Augment.py”的文件,然后把下方的代碼粘貼進這個py文件中,如圖所示:

# -*- coding: utf-8 -*-import torch
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
from torchvision import transforms
import numpy as np
import matplotlib.pyplot as plt
import os
import random
random.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 = r"./train/images"label_path = r"./train/labels"save_path = r"./save"    # 結果保存位置路徑,可以是一個不存在的文件夾# 運行runAugumentation(image_path, label_path, save_path)

粘貼完成以后,如圖所示:

在上方的代碼中,我們找到“if __name__ == '__main__':”的位置,在使用代碼前,需要對這里的路徑進行一些簡單的修改。來到上述位置后,我們可以看到如圖所示的代碼:

這里在配置之前有一個前提,那就是我們的數據集已經制作好了。我的數據集結構如圖所示:

如上圖可以看到,我們的“Augment.py”與train目錄在同一級,在train目錄中有images目錄與labels目錄:

這就是非常常見的YOLO目錄結構,這里就不多說了。

根據代碼中的變量,我們可知,第一個“image_path”需要傳入我們的數據集的圖片路徑,后面的“label_path”需要傳入我們數據集中標簽的路徑。最后一個“save_path”就是我們保存新生成的數據集與標簽的路徑。修改好上面的內容以后,我們直接保存即可。我們進入YOLO的虛擬環境,然后直接運行這個py文件即可:

python .\Augment.py

運行以后,我們就可以看到代碼開始幫我們處理數據集了:

在我們設置的保存路徑中,代碼已經保存了幫我們生成的數據集:

等程序執行完成以后,我們可以看到對應的文件夾中有1800個文件,相當于現在我們使用代碼增強出來的數據集是我們原本數據集的9倍。這些數據集已經涵蓋了大部分的情況:

在labels文件夾中也生成了對應的標簽:

至此,我們使用YOLO增強數據集就完成了。

四、結語

? ? ? ? 在本次教程中,我們通過對YOLO數據集的增強,實現了數據集多樣性的擴展,極大的減少了人工框選的成本以及樣本拍攝的數量,那么最后,感謝大家的觀看!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/85100.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/85100.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/85100.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

軟件工程的相關名詞解釋

目錄 1. 軟件生命周期2.開源軟件3.軟件工程4.模塊化原則5.信息隱藏原則6.雙向追蹤7.原型8.軟件需求9.需求工程10.邊界類11.軟件實現&#xff08;的任務&#xff09;12.軟件缺陷13.回歸測試14.軟件β版15.軟件部署16.糾正性維護17.改善性維護18.適應性維護19.軟件邏輯老化 1. 軟…

2025.06.17【BUG】|多樣品VCF文件合并技巧及注意事項(以bcftools為例)

文章目錄 [toc]一、合并VCF的常用命令1.1 合并多個bgzip壓縮的VCF文件1.2 使用文件列表合并 二、合并前的準備與注意事項2.1 文件格式要求2.2 樣本名唯一性2.3 檢查文件模式匹配 三、常見報錯與解決方法3.1 報錯&#xff1a;Error: Duplicate sample names (sample1), use --fo…

包含30個APP客戶端UI界面的psd適用于旅游酒店項目

包含30個APP客戶端UI界面的psd適用于旅游酒店項目 此資源包含30個完全可編輯的psd界面組成。內容包括歡迎頁、登錄、注冊、首頁、搜索、側邊菜單、用戶中心、個人介紹、用戶空間、產品詳細信息、酒店預定、天氣情況等各種常用界面&#xff0c;您可以將其用于旅游酒店類的APP應用…

ArrayList源碼分析

目錄 ArrayList簡介 ArrayList和vector的區別&#xff08;了解即可&#xff09; ArrayList添加null值 ArrayList和LinkedList區別 ArrayList核心源碼解讀 ArrayList擴容機制分析 一步一分析ArrayList擴容機制 hugeCapacity()方法 System.arraycopy() Arrays.copyOf()方法 …

NX二次開發C#---通過Face找Edges,再通過Edges找Curve

文章介紹了一個名為AskFaceEdge的靜態方法&#xff0c;用于處理3D建模中的邊緣曲線生成。該方法通過NX Open API調用&#xff0c;主要功能是獲取指定面的邊緣并生成相應的曲線。方法接收兩個參數&#xff1a;faceTag&#xff08;面標簽&#xff09;和curveLoop&#xff08;曲線…

設計模式筆記_創建型_工廠模式

1. 工廠模式簡介 工廠模式是一種創建型設計模式&#xff0c;主要用于創建對象實例。 它通過定義一個接口或抽象類來創建對象&#xff0c;而不是直接實例化具體類&#xff0c;從而將對象的創建過程與使用過程分離。 工廠模式通常分為兩種類型&#xff1a; 簡單工廠模式&#x…

2025.6.16總結

工作&#xff1a;今天閉環了個遺留問題。在做專項評估時寫得太簡單&#xff0c;這讓測試經理質疑你的測試質量。如果換位思考&#xff0c;你是測試經理&#xff0c;你該怎么去把握風險和保證產品的質量&#xff0c;就知道寫得太簡單&#xff0c;沒有可信度。 找開發看了下后臺…

記錄:安裝VMware、Ubuntu、ROS2

安裝了VMware&#xff0c;就能夠在Windows系統裝安裝Ubuntu&#xff0c;使用Linux系統。安裝了Ubuntu&#xff0c;就能在里面安裝ROS2&#xff0c;之后寫代碼控制機器人兒。 安裝VMware 我安裝的是16 pro【具體是vmware16.2.4】&#xff0c;下載網站&#xff1a;VMware Works…

將后端數據轉換為docx文件

使用docx npm install docx 按照注釋處理數據并轉換為對應的bolb數據流 <template><Button type"primary" click"handleDocxCreate">{{buttonTitle || "報告生成"}}</Button> </template><script> import {Doc…

數據結構排序算法合集

快排 private static void quickSort(int[] ret) { quick(ret,0,ret.length-1); } private static void quick(int[] ret, int left, int right) { if(left>right) 記一下這里是大于等于 return; int pivot partition(ret,left,right); quick(ret…

【算法筆記】紅黑樹插入操作

紅黑樹插入與調整詳解 一、紅黑樹的五大性質 紅黑樹是一種自平衡的二叉搜索樹&#xff08;BST&#xff09;&#xff0c;其核心特性如下&#xff1a; 顏色屬性&#xff1a;每個節點非紅即黑根屬性&#xff1a;根節點必須為黑色葉子屬性&#xff1a;所有的 NIL 葉子節點都是黑…

認知計算革命:從算法創新到產業落地的AI專業核心應用全景

??一、自動化機器學習&#xff08;AutoML&#xff09;?? ??技術機理與產業實踐深度剖析?? ??神經網絡架構搜索&#xff08;NAS&#xff09;?? 強化學習方案&#xff1a;Google Brain的NASNet采用策略梯度優化卷積單元進化算法方案&#xff1a;DeepMind的AmeobaNe…

篇章十 論壇系統——業務開發——板塊和帖子

目錄 1.板塊 1.1 思路 1.2 實現邏輯 1.3 參數要求 1.4 實現步驟 1.Mapper.xml 2.Mapper.java 3.Service接口 4.Service實現 5.單元測試 6.Controller 7.測試API 8.前后端交互 2.帖子 1.1思路?編輯 1.2 參數要求 ?編輯 1.3 實現步驟 1.Mapper.xml 2.Mapper…

React Native 上線前的準備與企業實戰經驗總結

上線前的準備與企業實戰經驗總結 關鍵要點 熱更新簡化部署&#xff1a;CodePush 和 Expo OTA 允許快速推送 JavaScript 和資源更新&#xff0c;繞過應用商店審核&#xff0c;適合修復 Bug 或小規模功能迭代。監控與分析提升質量&#xff1a;Sentry 提供實時錯誤跟蹤&#xff…

【AI時代速通QT】第一節:C++ Qt 簡介與環境安裝

目錄 前言 一、為什么是 Qt&#xff1f;—— C 開發者的必備技能 二、Qt 的核心魅力&#xff1a;不止于跨平臺 2.1 優雅之一&#xff1a;代碼隔離&#xff0c;清晰明了 2.2 優雅之二&#xff1a;信號與槽&#xff08;Signal & Slot&#xff09;機制 2.3 優雅之三&…

pandas學習筆記

前言 總結才是知識&#xff0c;作者習慣不好&#xff0c;不會總結&#xff0c;導致函數一旦不使用就會忘記怎么使用&#xff0c;特此寫了本文&#xff0c;用于給自己一個復習的資料. 提示&#xff1a;如果你是小白&#xff0c;每個代碼請自己敲打。 一 pandas的介紹 Pandas is…

算法題(力扣每日一題)—改變一個整數能得到的最大差值

給你一個整數 num 。你可以對它進行以下步驟共計 兩次&#xff1a; 選擇一個數字 x (0 < x < 9). 選擇另一個數字 y (0 < y < 9) 。 數字 y 可以等于 x 。 將 num中所有出現 x 的數位都用 y 替換。 令兩次對 num 的操作得到的結果分別為 a 和 b 。 請你返回 a 和 b…

Kubernetes筆記

1.簡介 Kubernetes的本質是一組服務器集群&#xff0c;它可以在集群的每個節點上運行特定的程序&#xff0c;來對節點中的容器進行管理。目的是實現資源管理的自動化&#xff0c;主要提供了如下的主要功能&#xff1a; 自我修復&#xff1a;一旦某一個容器崩潰&#xff0c;能夠…

Flutter——數據庫Drift開發詳細教程(八)

目錄 自定義 SQL 類型定義類型使用自定義類型在 Dart 中在 SQL 中 方言意識支持的 SQLite 擴展json1fts5地緣壟斷 自定義 SQL 類型 Drift 的核心庫主要以 SQLite3 為目標平臺編寫。這體現在Drift 開箱即用的SQL 類型上——這些類型由 SQLite3 支持&#xff0c;并新增了一些由 …

安卓遠控工具 CRaxsRat v7.6 安裝與使用教程(僅供合法測試學習)

在當今的信息安全領域&#xff0c;移動設備已成為重點關注對象。本文將介紹一款用于遠程管理與教學研究的工具 —— CRaxsRat v7.6&#xff0c;并詳細講解其安裝與使用流程。本教程僅供網絡安全愛好者在合法授權環境下學習使用&#xff0c;嚴禁任何非法用途。 &#x1f50d; 一…