[保姆式教程]使用目標檢測模型YOLO V8 OBB進行旋轉目標的檢測:訓練自己的數據集(基于衛星和無人機的農業大棚數據集)

????????最近需要做基于衛星和無人機的農業大棚的旋轉目標檢測,基于YOLO V8 OBB的原因是因為嘗試的第二個模型就是YOLO V8,后面會基于YOLO V9模型做農業大棚的旋轉目標檢測。YOLO V9目前還不能進行旋轉目標的檢測,需要修改代碼

? ? ? ? PS:歡迎大家分享農業大棚數據集,數據制作太花時間了......下面是我制作的農業大棚圖像

?一、下載代碼配置環境

GitHub - ultralytics/ultralytics: NEW - YOLOv8 🚀 in PyTorch > ONNX > OpenVINO > CoreML > TFLite

? ? ? ? 下載解壓縮源碼之后,激活環境進入根目錄配置環境(我已經換源):

pip install pyproject.dependencies

????????我的換源方法是到用戶文件夾(C:\Users\Administrator)下創建一個pip文件夾,然后在pip文件夾里創建一個txt文件,在txt文件里面寫入下面的內容,然后把txt文件后綴改成ini

[global]
index-url = http://pypi.mirrors.ustc.edu.cn/simple
[install]
use-mirrors =true
mirrors =http://pypi.mirrors.ustc.edu.cn/simple/
trusted-host =pypi.mirrors.ustc.edu.cn

二、數據集準備

? ? ? ? 流程:數據集標注——>XML——>DOTA_XML——>DOTA_TXT——>劃分數據集(train和val)——>YOLO格式TXT

(1)LabelImg2標注數據集生成XML標注文件

????????在LabelImg2上標注好數據,LabelImg2標注是五點式,即旋轉框的中心x,y坐標、旋轉框的長度和寬度、旋轉角度

(2)XML標注文件轉DOTA格式標簽文件(TXT)

????????下面將五點式XML文件轉換為八點式XML文件,再將八點式XML文件轉換為YOLO可訓練的TXT格式

?提示:DOTA數據集的TXT格式

x1,y1,x2,y2,x3,<y3,x4,y4,class_index,difficult
# 示例
307 308 330 299 422 541 398 550 dog 0

? ? ? ?OBB檢測方法里面旋轉框的表示方法有好幾種,YOLO V8 OBB使用的是(通過坐標在 0 和 1 之間歸一化的四個角點來指定邊界框):

class_index, x1, y1, x2, y2, x3, y3, x4, y4(需要做歸一化)
# 示例
0 0.332813 0.164062 0.403125 0.15 0.45 0.373437 0.379688 0.389062

注意事項:

? ? ? ? 【1】運行代碼之前將cls_list = ['dog'] ?# 修改為自己的標簽,不修改也不會報錯,只是轉換后的TXT中將沒有任何數據

? ? ? ? 【2】查看ultralytics/data/converter.py腳本中的代碼,圖片數據格式是png還是jpg。如果你的圖像格式與代碼中要求的圖像格式不符就無法生成TXT標簽(PS:我是將jpg轉png再運行代碼的)

? ? ? ? ?(2024.05.22更新)當然也可以直接修改ultralytics/data/converter.py腳本中的代碼,將

if image_path.suffix != ".png":

????????修改為

if image_path.suffix != [".png", ".jpg", ".jpeg"]:

? ? ? ? 修改之后就不用擔心圖像格式了,png、jpg、jpeg中的任何一種都可以

# 文件名稱   :roxml_to_dota.py
# 功能描述   :把rolabelimg標注的xml文件轉換成dota能識別的xml文件,
#             再轉換成dota格式的txt文件
#            把旋轉框 cx,cy,w,h,angle,或者矩形框cx,cy,w,h,轉換成四點坐標x1,y1,x2,y2,x3,y3,x4,y4
import os
import xml.etree.ElementTree as ET
import mathcls_list = ['dog']  # 修改為自己的標簽def edit_xml(xml_file, dotaxml_file):"""修改xml文件:param xml_file:xml文件的路徑:return:"""# dxml_file = open(xml_file,encoding='gbk')# tree = ET.parse(dxml_file).getroot()tree = ET.parse(xml_file)objs = tree.findall('object')for ix, obj in enumerate(objs):x0 = ET.Element("x0")  # 創建節點y0 = ET.Element("y0")x1 = ET.Element("x1")y1 = ET.Element("y1")x2 = ET.Element("x2")y2 = ET.Element("y2")x3 = ET.Element("x3")y3 = ET.Element("y3")# obj_type = obj.find('bndbox')# type = obj_type.text# print(xml_file)if (obj.find('robndbox') == None):obj_bnd = obj.find('bndbox')obj_xmin = obj_bnd.find('xmin')obj_ymin = obj_bnd.find('ymin')obj_xmax = obj_bnd.find('xmax')obj_ymax = obj_bnd.find('ymax')# 以防有負值坐標xmin = max(float(obj_xmin.text), 0)ymin = max(float(obj_ymin.text), 0)xmax = max(float(obj_xmax.text), 0)ymax = max(float(obj_ymax.text), 0)obj_bnd.remove(obj_xmin)  # 刪除節點obj_bnd.remove(obj_ymin)obj_bnd.remove(obj_xmax)obj_bnd.remove(obj_ymax)x0.text = str(xmin)y0.text = str(ymax)x1.text = str(xmax)y1.text = str(ymax)x2.text = str(xmax)y2.text = str(ymin)x3.text = str(xmin)y3.text = str(ymin)else:obj_bnd = obj.find('robndbox')obj_bnd.tag = 'bndbox'  # 修改節點名obj_cx = obj_bnd.find('cx')obj_cy = obj_bnd.find('cy')obj_w = obj_bnd.find('w')obj_h = obj_bnd.find('h')obj_angle = obj_bnd.find('angle')cx = float(obj_cx.text)cy = float(obj_cy.text)w = float(obj_w.text)h = float(obj_h.text)angle = float(obj_angle.text)obj_bnd.remove(obj_cx)  # 刪除節點obj_bnd.remove(obj_cy)obj_bnd.remove(obj_w)obj_bnd.remove(obj_h)obj_bnd.remove(obj_angle)x0.text, y0.text = rotatePoint(cx, cy, cx - w / 2, cy - h / 2, -angle)x1.text, y1.text = rotatePoint(cx, cy, cx + w / 2, cy - h / 2, -angle)x2.text, y2.text = rotatePoint(cx, cy, cx + w / 2, cy + h / 2, -angle)x3.text, y3.text = rotatePoint(cx, cy, cx - w / 2, cy + h / 2, -angle)# obj.remove(obj_type)  # 刪除節點obj_bnd.append(x0)  # 新增節點obj_bnd.append(y0)obj_bnd.append(x1)obj_bnd.append(y1)obj_bnd.append(x2)obj_bnd.append(y2)obj_bnd.append(x3)obj_bnd.append(y3)tree.write(dotaxml_file, method='xml', encoding='utf-8')  # 更新xml文件# 轉換成四點坐標
def rotatePoint(xc, yc, xp, yp, theta):xoff = xp - xc;yoff = yp - yc;cosTheta = math.cos(theta)sinTheta = math.sin(theta)pResx = cosTheta * xoff + sinTheta * yoffpResy = - sinTheta * xoff + cosTheta * yoffreturn str(int(xc + pResx)), str(int(yc + pResy))def totxt(xml_path, out_path):# 想要生成的txt文件保存的路徑,這里可以自己修改files = os.listdir(xml_path)i = 0for file in files:tree = ET.parse(xml_path + os.sep + file)root = tree.getroot()name = file.split('.')[0]output = out_path + '\\' + name + '.txt'file = open(output, 'w')i = i + 1objs = tree.findall('object')for obj in objs:cls = obj.find('name').textbox = obj.find('bndbox')x0 = int(float(box.find('x0').text))y0 = int(float(box.find('y0').text))x1 = int(float(box.find('x1').text))y1 = int(float(box.find('y1').text))x2 = int(float(box.find('x2').text))y2 = int(float(box.find('y2').text))x3 = int(float(box.find('x3').text))y3 = int(float(box.find('y3').text))if x0 < 0:x0 = 0if x1 < 0:x1 = 0if x2 < 0:x2 = 0if x3 < 0:x3 = 0if y0 < 0:y0 = 0if y1 < 0:y1 = 0if y2 < 0:y2 = 0if y3 < 0:y3 = 0for cls_index, cls_name in enumerate(cls_list):if cls == cls_name:file.write("{} {} {} {} {} {} {} {} {} {}\n".format(x0, y0, x1, y1, x2, y2, x3, y3, cls, cls_index))file.close()# print(output)print(i)if __name__ == '__main__':# -----**** 第一步:把xml文件統一轉換成旋轉框的xml文件 ****-----roxml_path = r'D:\data\yolov8_obb\origin_xml'  # labelimg2標注生成的原始xml文件路徑dotaxml_path = r'D:\data\yolov8_obb\dota_xml'  # 轉換后dota能識別的xml文件路徑,路徑需存在,不然報錯out_path = r'D:\data\yolov8_obb\dota_txt'  # 轉換后dota格式的txt文件路徑,路徑需存在,不然報錯filelist = os.listdir(roxml_path)for file in filelist:edit_xml(os.path.join(roxml_path, file), os.path.join(dotaxml_path, file))# -----**** 第二步:把旋轉框xml文件轉換成txt格式 ****-----totxt(dotaxml_path, out_path)

????????轉換后的TXT格式的標簽文件(此時的標簽還不是OBB數據集的格式,還需要再轉換):

?(3)劃分數據集

????????接下來劃分數據集:使用下面的代碼劃分數據集

import os
import random
import shutilrandom.seed(42)"""
該腳本用于將給定的數據集分割成訓練集和測試集。
數據集應包含圖像和對應的標注文件。
腳本會按照90%訓練集和10%測試集的比例進行分割,并將圖像和標注文件分別復制到相應的文件夾中。
"""# 設置數據集文件夾路徑和輸出文件夾路徑
data_folder = 'data_mouse_ro'
img_folder = 'data_mouse_ro/dataset/images'
label_folder = 'data_mouse_ro/dataset/labels'# 計算每個子集的大小
# 總文件數乘以0.9得到訓練集大小,其余為測試集大小
total_files = len(os.listdir(os.path.join(data_folder, 'img')))
train_size = int(total_files * 0.9)
test_size = int(total_files - train_size)# 獲取所有圖像文件的文件名列表,并進行隨機打亂
image_files = os.listdir(os.path.join(data_folder, 'img'))
random.shuffle(image_files)# 復制圖像和標注文件到相應的子集文件夾中
# 枚舉每個圖像文件,根據索引決定復制到訓練集還是測試集文件夾
for i, image_file in enumerate(image_files):base_file_name = os.path.splitext(image_file)[0]  # 獲取文件名(不包括擴展名)image_path = os.path.join(data_folder, 'img', image_file)label_path = os.path.join(data_folder, 'dotatxt', base_file_name + '.txt')# 根據索引判斷文件應復制到訓練集還是測試集if i < train_size:shutil.copy(image_path, os.path.join(img_folder, 'train'))  # 復制圖像到訓練集shutil.copy(label_path, os.path.join(label_folder, 'train_original'))  # 復制標注到訓練集else:shutil.copy(image_path, os.path.join(img_folder, 'val'))  # 復制圖像到測試集shutil.copy(label_path, os.path.join(label_folder, 'val_original'))  # 復制標注到測試集

? ? ? ? 運行代碼前文件夾結構如下(所有圖像放在img文件夾下,所有txt放在dotatxt文件夾下)

????????運行代碼后dataset中的train和val文件夾就已經有了劃分好的圖像,labels中的train_original和val_original有對應的train和val標簽

(4)DOTA格式標簽文件轉換為YOLO V8訓練所需的YOLO格式

? ? ? ? 【1】在項目代碼根目錄下面創建下面的文件夾結構,然后將劃分好的圖像和標簽文件放到相應的文件夾中?

? ? ? ? 【2】由于官方源碼轉換代碼用的是VOC數據集,所以這里我們需要修改ultralytics/data/converter.py中的類別名,改成自己的數據集類別名。修改ultralytics/data/converter.py中的代碼

? ? ? ? 【3】運行下面的代碼,將DOTA格式的標簽文件轉換為OBB數據集格式,其中的參數根據自己的情況設置

import syssys.path.append('F:\object_detection\yolov8_obb_version2\yolov8')from ultralytics.data.converter import convert_dota_to_yolo_obbconvert_dota_to_yolo_obb('F:\object_detection\yolov8_obb_version2\yolov8\data')

????????運行提示:

? ? ? ? 轉換后的OBB數據集格式的標簽會保存在labels\train和labels\val中(訓練需要使用的就是這兩個文件夾,train_original和val_original用不到)

? ? ? ? ?轉換后的OBB數據集格式的標簽文件中的內容

三、模型配置

(1)新建模型配置文件my-data8-obb.yaml

????????在yolov8\ultralytics\cfg\datasets路徑下,新建my-data8-obb.yaml文件(復制粘貼其中某一個yaml文件改個名字),寫入如下代碼,其中參數根據自己的情況設置

path: F:\object_detection\yolov8_obb_version2\yolov8\data # dataset root dir
train: images/train # train images (relative to 'path') 4 images
val: images/val # val images (relative to 'path') 4 images# Classes for DOTA 1.0
names:0: dog

(2)修改模型配置文件yolov8-obb.yaml

????????在yolov8\ultralytics\cfg\models\v8路徑下,修改yolov8-obb.yaml文件,將nc參數修改為自己的數據集類別數

四、訓練

(1)根據自己的實際情況修改yolov8\ultralytics\cfg\default.yaml文件中的訓練參數

????????如果自己的數據集類別只有一種,就將single-cls參數設置為True

(2)運行下面的代碼即可開始訓練

????????如果你使用的權重是“yolov8n-obb.pt”,只需要把下面代碼中的配置文件yolov8x-obb.yaml改成yolov8n-obb.yaml,依此類推

from ultralytics import YOLOdef main():model = YOLO('ultralytics/cfg/models/v8/yolov8x-obb.yaml').load('pt/yolov8x-obb.pt')  # build from YAML and transfer weightsmodel.train(data='ultralytics/cfg/datasets/my-data8-obb.yaml', epochs=5, imgsz=640, batch=16, workers=4)if __name__ == '__main__':main()

????????訓練過程及結果(5個Epoch)

五、驗證

? ? ? ? 在根目錄下創建一個名為eval.py的腳本,寫入下面的代碼,其中的參數根據自己的情況設置

from ultralytics import YOLOdef main():model = YOLO(r'runs/obb/train/weights/best.pt')model.val(data='ultralytics/cfg/datasets/my-data8-obb.yaml', imgsz=640, batch=4, workers=4)if __name__ == '__main__':main()

? ? ? ? 運行代碼的結果:

? ? ? ? ?下面是驗證保存的圖像(標簽為dog是因為在使用lableimg2制作標簽的時候懶得改了,采用了軟件默認的dog)

六、推理

????????在根目錄下創建一個名為predict.py的腳本,寫入下面的代碼,其中的參數根據自己的情況設置

from ultralytics import YOLOmodel = YOLO('runs/obb/train/weights/best.pt')
results = model('predict_images/2024_0018.jpg', save=True)
print(results[0].obb.xywhr[:, -1] * 180 / 3.14159265358979323846)

? ? ? ? 運行代碼的結果

????????推理保存的圖像(標簽為dog是因為在使用lableimg2制作標簽的時候懶得改了,采用了軟件默認的dog)

? ? ? ? 目前就做了這些工作,在數據集數量和質量方面還存在不足,在接下來會解決這部分的問題

????????這只是一個篇分享經驗的文章,難免有錯誤或者遺漏的地方,歡迎交流指正

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

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

相關文章

【研發日記】Matlab/Simulink技能解鎖(九)——基于嵌入式處理器仿真

文章目錄 前言 基于嵌入式處理器仿真 使用方式 第一步&#xff0c;硬件連接 第二步&#xff0c;配置硬件資源 第三步&#xff0c;配置XCP協議 第四步&#xff0c;加載Contrl Model 第五步&#xff0c;運行仿真 第六步&#xff0c;仿真報告 分析和應用 總結 參考資料 前言…

無線技術整合到主動噪聲控制(ANC)增強噪聲降低性能

主動噪聲控制&#xff08;ANC&#xff09;已成為一種廣泛使用的降噪技術。基本原理是通過產生與外界噪音相等的反向聲波&#xff0c;將噪音中和&#xff0c;從而達到降噪的效果。ANC系統通常包括以下幾個部分&#xff1a;參考麥克風、處理芯片、揚聲器和誤差麥克風。參考麥克風…

家政保潔服務小程序怎么做?家政公司快速搭建專屬小程序

在數字化時代背景下&#xff0c;家政保潔服務行業也迎來了線上轉型的新機遇。家政保潔服務小程序&#xff0c;作為一種新型的線上服務平臺&#xff0c;不僅能夠提升家政公司的服務效率&#xff0c;還能為顧客提供更加便捷的預約上門服務體驗。那么家政保潔服務小程序怎么做呢&a…

AI與量子計算:科技新時代的雙重飛躍

在科技的浪潮中,每一次技術革新都如同一次深海潛行,探尋著未知的奧秘。近年來,人工智能(AI)和量子計算兩大領域的發展尤為引人注目,它們不僅代表了科技的未來趨勢,更是人類社會進步的強大動力。本文將深入探討這兩項技術的最新進展、潛在影響以及它們之間的潛在聯系。 …

2024年3月小程序類目調整匯總公告

各位小程序開發者&#xff1a; 為進一步加強平臺的規范管理&#xff0c;優化開發者類目選擇體驗&#xff0c;現對以下類目進行調整&#xff0c;請各位開發者知悉。 類目調整 #【文娛-小說】 現資質要求 &#xff08;3選1&#xff09;&#xff1a; 1、提供《互聯網出版許可…

從零開始搭建一個SpringBoot項目

目錄 Spring BootSpring Boot 項目開發環境1、快速創建SpringBoot項目2、pom.xml 添加 Meavn 依賴3、配置application.yml4、驗證數據庫是否連接成功5、配置 Druid 數據源 Spring Boot 整合 MyBatis1、準備依賴2、application-dev.yml 配置3、啟動類添加Mapper接口掃描器4、設置…

BWVS 靶場測試

一、PHP弱類型 is_numeric() 輸入&#xff1a;127.0.0.1/BWVS/bug/php/code.php # 1、源代碼分析 如果num不是數字&#xff0c;那么就輸出num&#xff0c;同時如果num1&#xff0c;就輸出flag。即num要是字符串又要是數字 # 2、函數分析&#xff1a; is_numeric()函數&…

使用Nginx的Mirror模塊的指南

Nginx 是一個廣泛使用的 web 服務器和反向代理服務器&#xff0c;性能出色且易于配置。Nginx 提供了各種模塊來擴展其功能&#xff0c;其中一個有用的模塊是 mirror 模塊。本文將詳細介紹 Nginx 的 mirror 模塊&#xff0c;包括其用途、使用場景、注意事項以及示例代碼。 1. m…

《最新出爐》系列入門篇-Python+Playwright自動化測試-40-錄制生成腳本

宏哥微信粉絲群&#xff1a;https://bbs.csdn.net/topics/618423372 有興趣的可以掃碼加入 1.簡介 各種自動化框架都會有腳本錄制功能&#xff0c; playwright這么牛叉當然也不例外。很早之前的selenium、Jmeter工具&#xff0c;發展到每種瀏覽器都有對應的錄制插件。今天我們…

牛客NC392 參加會議的最大數目【中等 貪心+小頂堆 Java/Go/PHP 力扣1353】

題目 題目鏈接&#xff1a; https://www.nowcoder.com/practice/4d3151698e33454f98bce1284e553651 https://leetcode.cn/problems/maximum-number-of-events-that-can-be-attended/description/ 思路 貪心優先級隊列Java代碼 import java.util.*;public class Solution {/**…

java面試高級篇(JVM、Mysql、Redis、Kafka)

文章目錄 面試專題-java高級篇1. JVM有做過jvm的調優嗎?常用的jvm參數調優有哪些?如果jvm持續一段時間頻繁的發生Young GC (輕GC) 可能原因有哪些? 2. Mysql2.1. 基本功(見為知筆記)2.2. 什么是索引2.3. 索引的優劣勢2.4. MySQL的索引結構2.4.1. B-Tree索引2.4.2. BTree索引…

外賣系統源碼開發全攻略:外賣小程序與后臺管理系統的設計與實現

今天&#xff0c;小編將詳細介紹外賣系統源碼的開發全攻略&#xff0c;從需求分析到設計與實現&#xff0c;為開發者提供全面指導。 一、需求分析 1.用戶需求 用戶是外賣系統的核心&#xff0c;需滿足以下基本需求&#xff1a; -瀏覽菜單并下單 -實時追蹤訂單 -多種支付方…

每日一題——博弈論(枚舉與暴力)

博弈論 題目描述 運行代碼 #include<iostream> #include<vector> using namespace std; int main(){int n;cin >> n;vector<int> d(n,0);for(int i 0;i < n;i){cin >> d[i];}vector<int> in(1000,0);for(int k 1;k<3;k){for(int…

ESP32燒錄AT固件并進行MQTT通訊

首先下載AT固件 發布的固件 - ESP32 - — ESP-AT 用戶指南 latest 文檔 下載燒錄工具 下載指導 - ESP32 - — ESP-AT 用戶指南 latest 文檔 燒錄后注意usb的串口是不能發AT指令的 需要用16和17腳 用AT指令確認OK后連WIFI ATCWMODE1 //設置客戶端模式 ATCWLAP …

mysql誤刪后使用binlog恢復數據

1 預期效果 使用 binlog 恢復數據的預期效果是將誤刪的數據還原到誤刪之前的狀態&#xff0c;以減少或消除數據丟失的影響。通過正確解析和執行 binlog 中的操作記錄&#xff0c;可以重新執行誤刪操作之后的插入、更新或刪除操作&#xff0c;從而恢復被誤刪的數據。 數據恢復&…

Cocos Creator 編輯器的數據綁定詳解

Cocos Creator 是一款由 Cocos 平臺推出的游戲開發工具&#xff0c;它集成了圖形化編輯器、腳本引擎和資源管理器等功能&#xff0c;方便開發者快速地創建游戲。其中&#xff0c;數據綁定是 Cocos Creator 編輯器中非常重要的一個功能&#xff0c;它可以幫助開發者實現頁面元素…

三生隨記——山洞之謎

第一章&#xff1a;初識山洞 在遠離人煙的深山之中&#xff0c;隱藏著一個鮮為人知的山洞。這個山洞名叫幽洞&#xff0c;它的名字在當地人的口中帶著一股說不出的詭異和神秘。據說&#xff0c;幽洞深不見底&#xff0c;里面充滿了未知的恐懼和危險。然而&#xff0c;對于好奇心…

Go微服務: Grpc服務注冊在Consul的示例(非Go-Micro)

概述 現在&#xff0c;我們使用consul客戶端的api來把GRPC服務實現注冊到consul上&#xff0c;非Go-Micro的形式其實&#xff0c;consul官方提供了對應的接口調用來實現&#xff0c;golang中的consul/api包對其進行了封裝我們使用consul/api來進行展示 目錄結構 gitee.com/g…

springboot+mysql在線考試系統-計算機畢業設計源碼82584

摘 要 信息化社會內需要與之針對性的信息獲取途徑&#xff0c;但是途徑的擴展基本上為人們所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人們經常能夠獲得不同類型信息&#xff0c;這也是技術最為難以攻克的課題。針對在線考試等問題&#xff0c;對如何通過計算…

Websocket助手

功能介紹 WS助手是WebSocket調試的開發工具&#xff0c;該客戶端工具可以幫助開發人員快速連接到測試/生產環境&#xff0c;它可以幫助您監視和分析 Websocket 消息&#xff0c;并在開發過程中解決問題&#xff1b;可以模擬客戶端實現與服務器的數據交互&#xff0c;并完成批量…