if torch.onnx.is_in_onnx_export(): for i in range(self.nl): # 分別對三個輸出層處理 x[i] = self.m[i](x[i]) # conv bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85) x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() y = x[i].sigmoid() z.append(y.view(bs, -1, self.no)) return torch.cat(z, 1)
在export.py裡,自定義了一個匯出onnx檔案的函數,程式碼片段如下
def my_export_onnx(model, im, file, opset, train, dynamic, simplify, prefix=colorstr('ONNX:')): print('anchors:', model.yaml['anchors']) # wtxt = open('class.names', 'w') #for name in model.names: # wtxt.write(name+'\n') # wtxt.close() # YOLOv5 ONNX export print(im.shape) if not dynamic: f = os.path.splitext(file)[0] + '.onnx' torch.onnx.export(model, im, f, verbose=False, opset_version=12, input_names=['images'], output_names=['output']) else: f = os.path.splitext(file)[0] + '_dynamic.onnx' torch.onnx.export(model, im, f, verbose=False, opset_version=12, input_names=['images'], output_names=['output'], dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'}, # shape(1,3,640,640) 'output': {0: 'batch', 1: 'anchors'} # shape(1,25200,85) }) try: import cv2 net = cv2.dnn.readNet(f) except: exit(f'export {f} failed') exit(f'export {f} sucess')
在官方定義的export_onnx函數裡插入呼叫這個函數,程式碼截圖如下:
python export.py --weights=yolov5s.pt --include=onnx --imgsz=640 python export.py --weights=yolov5s6.pt --include=onnx --imgsz=1280
就能成功生成.onnx檔案,並且opencv的dnn模組能讀取onnx檔案做推理。這兩處修改都是淺表的修改,對輸入輸出層這塊進行了一些修改,但是確實是起到了相應的作用。
<annotation verified="yes"> <folder>hsrc</folder> <filename>100000001</filename> <path>/Users/haoyou/Library/Mobile Documents/com~apple~CloudDocs/OneDrive/hsrc/100000001.bmp</path> <source> <database>Unknown</database> </source> <size> <width>1166</width> <height>753</height> <depth>3</depth> </size> <segmented>0</segmented> <object> <type>bndbox</type> <name>ship</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>178</xmin> <ymin>246</ymin> <xmax>974</xmax> <ymax>504</ymax> </bndbox> </object> <object> <type>robndbox</type> <name>ship</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <robndbox> <cx>580.7887</cx> <cy>343.2913</cy> <w>775.0449</w> <h>170.2159</h> <angle>2.889813</angle> </robndbox> </object> </annotation>
using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Xml; using System.Xml.Serialization; namespace ConsoleApp1 { [XmlRoot("annotation")] public class AnnotationHead { public string folder; public string filename; public string path; public Source source; public Size size; public string segmented; } public class Size { public string width; public string height; public string depth; } public class Source { public string database; } [XmlRoot("object")] public class @object { public string type; public string name; public string pose; public string truncated; public string difficult; public robndClass robndbox; } public class robndClass { public float cx; public float cy; public float w; public float h; public float angle; } public class Test { public static void Main() { //輸出規則 XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = " "; settings.NewLineChars = "\r\n"; settings.Encoding = Encoding.UTF8; settings.OmitXmlDeclaration = true; // 不生成宣告頭 XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces(); namespaces.Add(string.Empty, string.Empty); //輸出物件 FileStream stream = new FileStream("part1.xml", FileMode.Create); /////////////////////////Part1/////////////////////////////////// AnnotationHead an = new AnnotationHead(); an.folder = "sandbox"; an.filename = "2022-10-29 15-19-25"; an.path = "F:/sandbox/2022-10-29 15-19-25.png"; Source source = new Source(); source.database = "Unknown"; an.source = source; Size size = new Size(); size.width = "1873"; size.height = "935"; size.depth = "3"; an.size = size; an.segmented = "0"; //實施輸出 XmlWriter xmlWriter = XmlWriter.Create(stream, settings); XmlSerializer serializer = new XmlSerializer(typeof(AnnotationHead)); serializer.Serialize(xmlWriter, an, namespaces); //目標銷燬 xmlWriter.Close(); stream.Close(); /////////////////////////Part2/////////////////////////////////// stream = new FileStream("part2.xml", FileMode.Create); //定義方法 robndClass il = new robndClass(); il.cx = (float)1484.1; il.cy = (float)521.7274; il.w = (float)40.1731; il.h = (float)194.3416; il.angle = (float)0.18; @object o = new @object(); o.type = "robndbox"; o.name = "ship"; o.pose = "Unspecified"; o.truncated = "0"; o.difficult = "0"; o.robndbox = il; List<@object> objectList = new List<@object>(); objectList.Add(o); objectList.Add(o); objectList.Add(o); serializer = new XmlSerializer(typeof(List<@object>)); XmlWriter xmlWriter2 = XmlWriter.Create(stream, settings); serializer.Serialize(xmlWriter2, objectList, namespaces); xmlWriter2.Close(); stream.Close(); ///////////////////////////merge////////////////////////////////////////// StreamReader sr = new StreamReader("part1.xml"); string strPart1 = sr.ReadToEnd(); strPart1 = strPart1.Substring(0, strPart1.Length - 13); sr.Close(); sr = new StreamReader("part2.xml"); string strPart2 = sr.ReadToEnd(); strPart2 = strPart2.Substring(15, strPart2.Length - 31); sr.Close(); string strOut = strPart1 + strPart2 + "</annotation>"; ////////////////////////////輸出/////////////////////////////////////// using (StreamWriter sw = new StreamWriter("result.xml")) { sw.Write(strOut); } } } }
public static void Main() { AnnotationHead an = new AnnotationHead(); an.folder = "sandbox"; an.filename = "2022-10-29 15-19-25"; an.path = "F:/sandbox/2022-10-29 15-19-25.png"; Source source = new Source(); source.database = "Unknown"; an.source = source; Size size = new Size(); size.width = "18443"; size.height = "935"; size.depth = "3"; an.size = size; an.segmented = "0"; robndClass il = new robndClass(); il.cx = (float)1484.1; il.cy = (float)521.7274; il.w = (float)40.1731; il.h = (float)194.3416; il.angle = (float)0.18; @object o = new @object(); o.type = "robndbox"; o.name = "ship"; o.pose = "Unspecified"; o.truncated = "0"; o.difficult = "0"; o.robndbox = il; List<@object> objectList = new List<@object>(); objectList.Add(o); objectList.Add(o); objectList.Add(o); objectList.Add(o); objectList.Add(o); AnnotationClass ac = new AnnotationClass(an,objectList,"r2.xml"); ac.action(); } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.IO; using System.Xml.Serialization; namespace ConsoleApp1 { [XmlRoot("annotation")] public class AnnotationHead { public string folder; public string filename; public string path; public Source source; public Size size; public string segmented; } public class Size { public string width; public string height; public string depth; } public class Source { public string database; } [XmlRoot("object")] public class @object { public string type; public string name; public string pose; public string truncated; public string difficult; public robndClass robndbox; } public class robndClass { public float cx; public float cy; public float w; public float h; public float angle; } class AnnotationClass { private string strOutName;//輸出檔名稱 private AnnotationHead an; private List<@object> objectList; //建構函式 public AnnotationClass(AnnotationHead annotatonHead, List<@object> olist, string strName = "result.xml") { an = annotatonHead; strOutName = strName; objectList = olist; } public void action() { //輸出規則 XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = " "; settings.NewLineChars = "\r\n"; settings.Encoding = Encoding.UTF8; settings.OmitXmlDeclaration = true; // 不生成宣告頭 XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces(); namespaces.Add(string.Empty, string.Empty); //輸出物件 FileStream stream = new FileStream("part1.xml", FileMode.Create); /////////////////////////Part1/////////////////////////////////// //實施輸出 XmlWriter xmlWriter = XmlWriter.Create(stream, settings); XmlSerializer serializer = new XmlSerializer(typeof(AnnotationHead)); serializer.Serialize(xmlWriter, an, namespaces); //目標銷燬 xmlWriter.Close(); stream.Close(); /////////////////////////Part2/////////////////////////////////// stream = new FileStream("part2.xml", FileMode.Create); //定義方法 serializer = new XmlSerializer(typeof(List<@object>)); XmlWriter xmlWriter2 = XmlWriter.Create(stream, settings); serializer.Serialize(xmlWriter2, objectList, namespaces); xmlWriter2.Close(); stream.Close(); ///////////////////////////merge////////////////////////////////////////// StreamReader sr = new StreamReader("part1.xml"); string strPart1 = sr.ReadToEnd(); strPart1 = strPart1.Substring(0, strPart1.Length - 13); sr.Close(); sr = new StreamReader("part2.xml"); string strPart2 = sr.ReadToEnd(); strPart2 = strPart2.Substring(15, strPart2.Length - 31); sr.Close(); string strOut = strPart1 + strPart2 + "</annotation>"; ////////////////////////////輸出/////////////////////////////////////// using (StreamWriter sw = new StreamWriter(strOutName)) { sw.Write(strOut); } } } }
BboxToolkit/tools
路徑下的split_configs/dota1_0/ss_train.json
檔案。根據需求更改引數。更改BboxToolkit/BboxToolkit/datasets/misc.py
檔案中的dota1_0中的類別現在有xywhθ標註的資料集,要轉換成dota標註的格式
使用如下程式碼,路徑需要自己修改:
import math import shutil import os import numpy as np import xml.etree.ElementTree as et dataset_dir = r'D:\dataset\sar\RSDD\RSDD-SAR\JPEGImages' ana_dir = r'D:\dataset\sar\RSDD\RSDD-SAR\Annotations' save_dir = r'D:\dataset\sar\RSDD\dota' data_type = 'test' train_img_dir = r'D:\dataset\sar\RSDD\RSDD-SAR\ImageSets\test.txt' f1 = open(train_img_dir, 'r') train_img = f1.readlines() def rota(center_x1, center_y1, x, y, w, h, a): # 旋轉中心點,旋轉中心點,框的w,h,旋轉角 # a = (math.pi * a) / 180 # 角度轉弧度 x1, y1 = x - w / 2, y - h / 2 # 旋轉前左上 x2, y2 = x + w / 2, y - h / 2 # 旋轉前右上 x3, y3 = x + w / 2, y + h / 2 # 旋轉前右下 x4, y4 = x - w / 2, y + h / 2 # 旋轉前左下 px1 = (x1 - center_x1) * math.cos(a) - (y1 - center_y1) * math.sin(a) + center_x1 # 旋轉後左上 py1 = (x1 - center_x1) * math.sin(a) + (y1 - center_y1) * math.cos(a) + center_y1 px2 = (x2 - center_x1) * math.cos(a) - (y2 - center_y1) * math.sin(a) + center_x1 # 旋轉後右上 py2 = (x2 - center_x1) * math.sin(a) + (y2 - center_y1) * math.cos(a) + center_y1 px3 = (x3 - center_x1) * math.cos(a) - (y3 - center_y1) * math.sin(a) + center_x1 # 旋轉後右下 py3 = (x3 - center_x1) * math.sin(a) + (y3 - center_y1) * math.cos(a) + center_y1 px4 = (x4 - center_x1) * math.cos(a) - (y4 - center_y1) * math.sin(a) + center_x1 # 旋轉後左下 py4 = (x4 - center_x1) * math.sin(a) + (y4 - center_y1) * math.cos(a) + center_y1 return px1, py1, px2, py2, px3, py3, px4, py4 # 旋轉後的四個點,左上,右上,右下,左下 for img in train_img: shutil.copy(os.path.join(dataset_dir, img[:-1] + '.jpg'), os.path.join(save_dir, data_type, 'images', img[:-1] + '.jpg')) xml_file = open(os.path.join(ana_dir, img[:-1] + '.xml'), encoding='utf-8') tree = et.parse(xml_file) root = tree.getroot() with open(os.path.join(save_dir, data_type, 'labelTxt', img[:-1] + '.txt'), 'w') as f: f.write('imagesource:GoogleEarth\ngsd:NaN\n') for obj in root.iter('object'): cls = obj.find('name').text box = obj.find('robndbox') x_c = box.find('cx').text y_c = box.find('cy').text h = box.find('h').text w = box.find('w').text theta = box.find('angle').text box = list(map(np.float16, [x_c, y_c, h, w, theta])) box = rota(box[0], box[1], *box) box = list(map(int, box)) box = list(map(str, box)) f.write(' '.join(box)) f.write(' ' + cls + ' 0\n')