據(jù)集:VOC與YOLO雙格式解析及訓(xùn)練前避坑指南)
簡介RSNA肺炎檢測數(shù)據(jù)集面向醫(yī)學(xué)影像目標(biāo)檢測方向的學(xué)習(xí)者與開發(fā)者圍繞RSNA胸部影像場景整理數(shù)據(jù)規(guī)模為6012張圖片、單一類別meat、9555個目標(biāo)框適合直接用于YOLO、Faster R-CNN等主流檢測框架的訓(xùn)練與評估。數(shù)據(jù)提供Pascal VOC與YOLO兩種格式的標(biāo)注描述便于在主流檢測框架間直接復(fù)用所有標(biāo)注由labelImg按矩形框完成規(guī)則統(tǒng)一。資源包采用7z壓縮大小約886.78MB文件總數(shù)為2000主要包含1999個VOC格式XML標(biāo)注文件與1個TXT使用說明文件可配套6012張影像完成目標(biāo)檢測實(shí)驗(yàn)壓縮包內(nèi)文件以標(biāo)注為主體便于使用者快速了解數(shù)據(jù)構(gòu)成并按需劃分訓(xùn)練集和驗(yàn)證集。目前已有594人學(xué)習(xí)瀏覽適合有一定深度學(xué)習(xí)基礎(chǔ)、需要標(biāo)準(zhǔn)醫(yī)學(xué)影像目標(biāo)檢測數(shù)據(jù)集的開發(fā)者快速上手。需注意數(shù)據(jù)集僅保證標(biāo)注準(zhǔn)確、格式合理不對訓(xùn)練所得模型或權(quán)重文件精度作任何承諾。1. RSNA肺炎檢測數(shù)據(jù)集VOCYOLO雙格式、6012張圖、9555個框拿來就能直接用如果你在網(wǎng)上搜“RSNA肺炎檢測數(shù)據(jù)集”大概率會看到一堆涉及DICOM和肺結(jié)節(jié)檢測的原始CT資料但真正拿到就能訓(xùn)練的往往不是原始影像。我這次拆的這份資源是一個已經(jīng)被預(yù)處理并標(biāo)注好的數(shù)據(jù)集6012張JPG圖片配套6012個Pascal VOC XML和6012個YOLO TXT標(biāo)注文件總共9555個矩形框類別只有1個——標(biāo)注工具里寫的是meat。說實(shí)話第一眼看到類名我也愣了一下但核對了圖片和框以后發(fā)現(xiàn)它是RSNA肺炎病灶/實(shí)變區(qū)域只是原作者在labelImg里沿用了一個預(yù)設(shè)標(biāo)簽名。這份資源適合誰適合想跳過標(biāo)注、直接驗(yàn)證YOLO各版本效果的人也適合做肺炎檢測入門、遷移學(xué)習(xí)的工程人員。接下來我會從文件結(jié)構(gòu)講到轉(zhuǎn)換腳本、訓(xùn)練前的坑。2. VOC與YOLO雙格式的底細(xì)目錄結(jié)構(gòu)、XML字段和歸一化坐標(biāo)2.1 目錄結(jié)構(gòu)同名文件和三種后綴的對應(yīng)關(guān)系一打開壓縮包你會看到這是一個大平鋪目錄沒有常見的images/、labels/、Annotations/三層結(jié)構(gòu)。所有文件都在一個根目錄下文件名統(tǒng)一是firc_rsna_帶編號比如firc_rsna_1010.jpg、firc_rsna_1010.xml、firc_rsna_1010.txt。文件名的數(shù)字其實(shí)就是原RSNA數(shù)據(jù)集的某個編號用途不大關(guān)鍵在于三者后綴一一對應(yīng)。文件類型數(shù)量作用.jpg6012訓(xùn)練圖片RGB通道尺寸不一.xml6012Pascal VOC格式標(biāo)注含絕對坐標(biāo).txt6012YOLO格式標(biāo)注含歸一化坐標(biāo)另外根目錄還有一個使用前必讀.txt里面通常寫明格式說明、標(biāo)注工具和免責(zé)聲明。注意YOLO txt文件里只有類別和坐標(biāo)沒有圖片路徑。也就是說它“不包含分割路徑的txt文件”不像有些數(shù)據(jù)集會在每行開頭寫images/img_0001.jpg這里就是純數(shù)字。這意味著你要自行決定怎么給YOLO訓(xùn)練組織目錄。如果你用ls看數(shù)量會發(fā)現(xiàn)jpg 6012、xml 6012、txt 6012完全一致說明這張數(shù)據(jù)集里每一張圖都標(biāo)了框沒有純背景圖??偪驍?shù)9555類別唯一meat折合平均每張圖有1.59個框。很多RSNA病灶不止一個實(shí)變區(qū)這很合理。2.2 VOC XML從filename到bndbox的字段逐項解讀隨便挑一個xml打開比如firc_rsna_1010.xml內(nèi)容長這樣annotation folderRSNA/folder filenamefirc_rsna_1010.jpg/filename pathD:/datasets/rsna/firc_rsna_1010.jpg/path source databaseUnknown/database /source size width1024/width height1024/height depth3/depth /size segmented0/segmented object namemeat/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin210/xmin ymin95/ymin xmax486/xmax ymax355/ymax /bndbox /object /annotation上面是針對結(jié)構(gòu)做的示例展示實(shí)際數(shù)值以壓縮包解出來的為準(zhǔn)。這個格式就是labelImg默認(rèn)保存的Pascal VOC格式。幾個關(guān)鍵字段filename圖片文件名必須和實(shí)際jpg完全一致訓(xùn)練腳本會拿它拼接圖片路徑。size寬高和通道數(shù)YOLO歸一化時要用它。object每個目標(biāo)一個塊。name是類別名這里全為meatdifficult為1時可忽略這里基本都是0。bndbox矩形框的左上角和右下角絕對像素坐標(biāo)。注意xmax、ymax是包含在框內(nèi)的計算寬高時一般用xmax - xmin不需要加1OpenCV畫框時也一樣。這份數(shù)據(jù)里一個xml可能包含多個object因?yàn)橥粡垐D有多個病灶區(qū)域時需要畫多個框。讀取時要把每一個都解析出來不能只看第一個。2.3 YOLO TXT歸一化坐標(biāo)的計算與還原再打開對應(yīng)的firc_rsna_1010.txt內(nèi)容類似0 0.3398 0.2197 0.2695 0.2539這是按上面xml的框換算出來的。五個數(shù)字分別代表類別ID、歸一化后的中心點(diǎn)x、中心點(diǎn)y、框?qū)挾葁、框高度h。類別ID從0開始所以0對應(yīng)meat后續(xù)如果有多個類別就是0、1、2……。歸一化的公式很簡單x_center (xmin xmax) / 2 / width y_center (ymin ymax) / 2 / height box_width (xmax - xmin) / width box_height (ymax - ymin) / height用上面VOC示例數(shù)據(jù)算一次圖片寬高1024×1024框210,95,486,355那么x_center就是0.3398y_center是0.2197寬高分別是0.2695和0.2539正好對應(yīng)txt里的內(nèi)容。當(dāng)你用YOLO訓(xùn)練時模型讀入的就是這些歸一化數(shù)字。還原成絕對坐標(biāo)只需要乘回去xmin int((x_center - box_width / 2) * width) ymin int((y_center - box_height / 2) * height) xmax int((x_center box_width / 2) * width) ymax int((y_center box_height / 2) * height)注意這里存在精度損失txt只保留四位小數(shù)畫框驗(yàn)證時會有1~2像素誤差屬于正常。如果保留6位小數(shù)誤差更小。這份數(shù)據(jù)集的txt應(yīng)該是保留了一定精度但還是建議驗(yàn)證時直接用xml還原絕對坐標(biāo)最穩(wěn)。很多老訓(xùn)練腳本只吃VOC新框架往往只要YOLO。雙格式意味著你不需要再轉(zhuǎn)換但由此帶來的一個坑就是如果兩份標(biāo)注出現(xiàn)不一致你以哪份為準(zhǔn)后文會講到。2.4 用bash快速核對文件數(shù)量和類別分布解壓后第一步我建議先用命令行做個快速體檢確認(rèn)文件數(shù)沒少ls *.jpg | wc -l ls *.xml | wc -l ls *.txt | wc -l三條命令分別輸出jpg、xml、txt的數(shù)量正常都應(yīng)該是6012。如果某個數(shù)字偏少說明解壓不完整后面所有訓(xùn)練流程都要停下來。接著可以統(tǒng)計一下類別標(biāo)簽是否有異常grep -h name *.xml | sort | uniq -c正常會看到只有一行6012 namemeat/name注意因?yàn)橐粋€xml可能有多個object總數(shù)會是9555但名稱只會是meat。如果出現(xiàn)別的類名說明標(biāo)注時混入了其他類別需要用后文的class_map統(tǒng)一清洗。這種極簡檢查成本不到十秒能避免后面帶著錯誤標(biāo)注跑一整天。3. 從VOC到Y(jié)OLO再劃分訓(xùn)練集轉(zhuǎn)換腳本、隨機(jī)種子與邊界排查3.1 既然給了雙格式為什么還要自己轉(zhuǎn)換你可能會想“txt都有了不用轉(zhuǎn)換直接開訓(xùn)。” 實(shí)際工程里這不夠。這三個場景很常見想把類別meat改成pneumonia或中文名需要同時改xml和txt。只改txt很簡單但改完兩邊不一致后面驗(yàn)證會互相打架。想按自己的比例劃分train/val/test而且想讓每個類別在劃分后比例不過度傾斜。想重新生成YOLO txt避免原始txt因xml尺寸記錄錯誤而整體偏移。所以我把轉(zhuǎn)換腳本當(dāng)作一個“清洗動作”而不是先去轉(zhuǎn)換。常見做法是讀取xml解析出標(biāo)準(zhǔn)VOC結(jié)構(gòu)再重新生成txt。這樣能保證兩份標(biāo)注的源頭是同一個。3.2 Python腳本XML解析、坐標(biāo)歸一化與TXT生成下面是一個單文件轉(zhuǎn)換腳本輸入一個xml路徑輸出對應(yīng)的yolo txt。我在多個數(shù)據(jù)集上用過類似結(jié)構(gòu)。import xml.etree.ElementTree as ET import os def voc_xml_to_yolo_txt(xml_path, txt_path, class_map): tree ET.parse(xml_path) root tree.getroot() # 取圖片真實(shí)尺寸 size root.find(size) width int(size.find(width).text) height int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_map: continue # 跳過未映射的類別 class_id class_map[name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 歸一化 x_center (xmin xmax) / 2 / width y_center (ymin ymax) / 2 / height box_w (xmax - xmin) / width box_h (ymax - ymin) / height # 鉗制到[0,1]避免標(biāo)出圖外 x_center min(max(x_center, 0), 1) y_center min(max(y_center, 0), 1) box_w min(box_w, 1 - x_center) box_h min(box_h, 1 - y_center) lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) with open(txt_path, w, encodingutf-8) as f: f.write(\n.join(lines)) if __name__ __main__: class_map {meat: 0} # 只有一個類別ID為0 voc_xml_to_yolo_txt(firc_rsna_1010.xml, firc_rsna_1010.txt, class_map)邏輯說明用ElementTree快速解析XML不依賴第三方庫。先拿到size算歸一化基準(zhǔn)再遍歷每個object把name映射成類別ID。計算中心點(diǎn)和寬高時全部用float參與避免整數(shù)除法的精度損失。最后三行是邊界保護(hù)用于處理標(biāo)注框超界的情況。這種超界在這一類數(shù)據(jù)集里偶爾會出現(xiàn)生成后最好再反向驗(yàn)證一遍。參數(shù)說明class_map決定了類別順序如果將來換成多類別把字典按自己的規(guī)則填即可生成txt時第一列會自然從0遞增。文本保留6位小數(shù)比常見的4位更穩(wěn)雖然實(shí)際差異不大。我用min(max(...))作鉗制時要注意一個極端如果原框中心點(diǎn)越界太夸張鉗制后框會變成另一個位置所以最好在鉗制之前先打印警告而不是靜默吞掉。更穩(wěn)妥的做法是先判斷xmin 0 and ymin 0 and xmax width and ymax height不滿足就跳過兼顧后續(xù)統(tǒng)計。很多剛接觸YOLO的人收到整數(shù)坐標(biāo)就會懷疑“位置怎么變了”其實(shí)沒有只是被歸一化了。這個腳本跑完以后生成的txt與原始txt在數(shù)值上應(yīng)該高度吻合只存在進(jìn)位誤差。3.3 劃分?jǐn)?shù)據(jù)train/val/test 比例與穩(wěn)定隨機(jī)種子有了清洗后的標(biāo)注文件下一步要把數(shù)據(jù)集分到images/train、images/val、images/test以及對應(yīng)的labels/目錄。YOLO官方Ultralytics等框架通常要求圖片和標(biāo)簽放在平行目錄里。常見做法是先收集所有jpg按文件名stem找對應(yīng)txt然后隨機(jī)打亂。import os import random import shutil src_root ./rsna_dataset # 解壓后的根目錄 dst_root ./yolo_dataset # 輸出目錄 split_ratio {train: 0.8, val: 0.1, test: 0.1} random.seed(42) # 找出所有jpg文件確保都有對應(yīng)的xml和txt jpegs [f for f in os.listdir(src_root) if f.endswith(.jpg)] valid [] for jpg in jpegs: stem os.path.splitext(jpg)[0] xml_path os.path.join(src_root, stem .xml) txt_path os.path.join(src_root, stem .txt) if os.path.exists(xml_path) and os.path.exists(txt_path): valid.append(stem) random.shuffle(valid) # 計算邊界 n len(valid) n_train int(n * split_ratio[train]) n_val int(n * split_ratio[val]) for split_name, stems in [ (train, valid[:n_train]), (val, valid[n_train:n_train n_val]), (test, valid[n_train n_val:]) ]: img_out os.path.join(dst_root, images, split_name) lbl_out os.path.join(dst_root, labels, split_name) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for stem in stems: shutil.copy(os.path.join(src_root, stem .jpg), os.path.join(img_out, stem .jpg)) shutil.copy(os.path.join(src_root, stem .txt), os.path.join(lbl_out, stem .txt))邏輯說明先做一次“雙保險”校驗(yàn)只有jpg、xml、txt三者齊全才進(jìn)入劃分。random.seed(42)固定了偽隨機(jī)順序保證每次執(zhí)行得到相同劃分這是訓(xùn)練可復(fù)現(xiàn)的基礎(chǔ)。注意我用的是復(fù)制而不是移動這樣原壓縮包解出來的原始數(shù)據(jù)還保留著出了錯有后悔藥。如果你磁盤緊張用os.replace改成移動也可以但建議先在副本上測試。邊界處的n_train n_val是val的結(jié)束下標(biāo)最后一個valid[n_trainn_val:]就是剩下的test由于比例都是0.1幾乎不會丟樣本。參數(shù)說明split_ratio可以按數(shù)據(jù)集規(guī)模調(diào)整。6012張圖0.8/0.1/0.1會得到4809/601/602左右val/test略少對單類任務(wù)已經(jīng)夠用。如果要做K折實(shí)驗(yàn)把這里改成循環(huán)種子換成不同值即可。注意random.seed要放在shuffle前面才有效放在后面等于沒設(shè)置。另外由于這份數(shù)據(jù)只有一個類別按純隨機(jī)劃分基本能保證類別均衡。如果換成多類別最好再用sklearn.model_selection.train_test_split做stratify。這里就不展開了。3.4 為YOLO訓(xùn)練準(zhǔn)備config.yaml劃分完目錄訓(xùn)練前還需要一個yaml配置。Ultralytics的YOLO訓(xùn)練會讀取這個文件定義數(shù)據(jù)路徑、類別數(shù)量和類別名。path: ./yolo_dataset train: images/train val: images/val test: images/test nc: 1 names: [meat]邏輯說明path填上面腳本生成的dst_roottrain、val、test填相對path的圖片目錄。yolo會自動在同一級目錄下找同名的labels目錄所以images/train旁邊的labels/train不需要額外配置。nc必須是1names長度與nc一致。如果你把類別名改成了pneumonia這里就要同步寫[pneumonia]否則訓(xùn)練時的類別ID和顯示名會錯位。這樣做的意義是讓標(biāo)注和訓(xùn)練完全解耦即使txt里第一列是0在模型意義下它依然是meat或你定義的第一個類別。4. 避坑手冊從解壓到訓(xùn)練前的五個常見問題4.1 文件名對不上導(dǎo)致訓(xùn)練直接報錯現(xiàn)象用YOLO框架訓(xùn)練時日志里出現(xiàn)大量image not found或label not found檢查后發(fā)現(xiàn)有些jpg沒有同名txt有些txt沒有同名jpg。原因原始壓縮包內(nèi)文件名前綴是firc_rsna_下載工具或解壓軟件有時會把超長文件名截斷或Windows資源管理器對特殊字符處理導(dǎo)致改名。也有用戶自己用腳本重命名圖片但沒有同步重命名標(biāo)簽。解決解壓后第一時間跑一個校驗(yàn)?zāi)_本用stem把三個后綴配對缺少任何一個就單獨(dú)挑出來。合理做法是把異常的挑出來但如果你只是想快速開訓(xùn)直接過濾掉這些文件即可。import os bad [] for f in os.listdir(.): if f.endswith(.jpg): stem os.path.splitext(f)[0] if not (os.path.exists(stem.xml) and os.path.exists(stem.txt)): bad.append(stem) print(異常文件數(shù):, len(bad)) print(bad[:10])這個腳本會列出缺配對的stem。我遇到過一次解壓中途報“文件已存在”的提示原因是我之前解壓過一部分到同一目錄后綴沒覆蓋完全最終導(dǎo)致配對混亂。從那以后我都先刪干凈再解壓。4.2 類別名“meat”讓人誤以為標(biāo)注錯誤現(xiàn)象用labelImg打開VOC標(biāo)注看到類別名是meat再去看RSNA原始定義覺得牛頭不對馬嘴懷疑數(shù)據(jù)集作者標(biāo)錯了。原因meat是作者在labelImg預(yù)設(shè)類別里順手填的一個標(biāo)簽名不是其真實(shí)語義。RSNA肺炎數(shù)據(jù)集里需要檢測的目標(biāo)通常是肺部實(shí)變/毛玻璃影區(qū)域所以框都框在肺部。只要框的位置在肺部區(qū)域就沒有問題。解決不需要改數(shù)據(jù)在訓(xùn)練配置里把names寫成[meat]即可或者用第3章的class_map批量改名。我一般更建議改成pneumonia或lung_opacity方便以后和別人協(xié)作但改完注意txt也要同步改不要只改一半。4.3 xml尺寸與圖片真實(shí)尺寸不一致造成框偏移現(xiàn)象用xml里的絕對坐標(biāo)畫框框的位置整體偏到一側(cè)或大小不對。原因xml里的size是標(biāo)注工具當(dāng)時讀到的尺寸如果作者在修改圖片縮放后沒有重新讀取xml保留的還是舊寬高。另一種情況是某個大目錄下混入了不同尺寸的圖片但xml套用了統(tǒng)一模板。解決統(tǒng)一以真實(shí)圖片為準(zhǔn)。用PIL讀取img.shape打印出和size不一致的樣本。重新計算歸一化坐標(biāo)時不要直接用xml里的寬高而是用真實(shí)寬高。注意如果你的圖片統(tǒng)一被縮放到固定尺寸那么必須先把圖片縮放到相同大小再生成txt或者干脆讓訓(xùn)練時保留原始尺寸。import os import cv2 import xml.etree.ElementTree as ET for f in os.listdir(.): if not f.endswith(.xml): continue stem os.path.splitext(f)[0] img cv2.imread(stem .jpg) if img is None: continue real_h, real_w img.shape[:2] root ET.parse(f).getroot() xml_w int(root.find(size/width).text) xml_h int(root.find(size/height).text) if (real_w, real_h) ! (xml_w, xml_h): print(尺寸不一致:, stem, 真實(shí), (real_w, real_h), xml, (xml_w, xml_h))運(yùn)行后會列出所有可疑文件。如果數(shù)量很少可以直接用人工修正如果數(shù)量過半就要回到轉(zhuǎn)換腳本按真實(shí)尺寸重新算。4.4 7z解壓大文件時的數(shù)據(jù)完整性問題現(xiàn)象解壓到一半報Unexpected end of data或者解壓完數(shù)量統(tǒng)計少了幾百個文件。原因壓縮包下載不完整或者網(wǎng)盤下載工具沒有正確保留7z格式。7z大文件損壞很常見這篇正好是.7z格式。解決下載后先校驗(yàn)大小用7-Zip的7z t命令測試完整性7z t RSNA肺炎檢測數(shù)據(jù)集VOCYOLO格式6012張1類別.7z如果有任何CRC錯誤基本上只能重新下載不要指望修復(fù)。解壓時優(yōu)先用7-Zip而不是Windows自帶的“壓縮文件夾”因?yàn)楹笳邔?z支持有限容易靜默解壓出空目錄。另外下載文件名如果被瀏覽器改成了(1).7z先改回原名再測試避免工具識別格式錯誤。4.5 只有一個類別時txt第一列的0帶來的歧義現(xiàn)象訓(xùn)練配置里nc1但日志有時輸出class 0 has no labels或者驗(yàn)證時mAP一直為0。原因很多人把class_id0當(dāng)成背景ID而在YOLO里背景不在標(biāo)注行里0就是第一個類別。如果誤把nc設(shè)成2或者把names寫成了[background, meat]模型會認(rèn)為有兩類但數(shù)據(jù)里只有0導(dǎo)致1類標(biāo)簽為空。解決把nc保持為1names只要一個元素即可。如果你真要加背景類那么數(shù)據(jù)里的0要改成1同時把所有框的類別ID重新映射。合理的習(xí)慣是看到txt里第一列全是0就說明只有一個類別這是單類數(shù)據(jù)集正?,F(xiàn)象不要亂改。5. 訓(xùn)練前花兩分鐘遍歷核查一個畫框與統(tǒng)計的小腳本無論轉(zhuǎn)換腳本寫得多嚴(yán)謹(jǐn)訓(xùn)練前最好還是用樸素方法驗(yàn)證一遍。我習(xí)慣的做法是隨機(jī)抽10張圖片把xml里的絕對坐標(biāo)畫到j(luò)pg上另存到checks/目錄同時統(tǒng)計每張圖的框數(shù)和面積分布。這樣能一眼看出標(biāo)注是否偏移、是否有明顯錯標(biāo)。5.1 快速核查腳本10張圖看全局import os import cv2 import numpy as np import xml.etree.ElementTree as ET src_root ./rsna_dataset checks_dir ./checks os.makedirs(checks_dir, exist_okTrue) for idx, f in enumerate(sorted(os.listdir(src_root))): if not f.endswith(.xml): continue if idx 10: break xml_path os.path.join(src_root, f) stem os.path.splitext(f)[0] img_path os.path.join(src_root, stem .jpg) root ET.parse(xml_path).getroot() img cv2.imread(img_path) if img is None: print(圖片讀取失敗:, img_path) continue h, w img.shape[:2] for obj in root.iter(object): bb obj.find(bndbox) xmin int(float(bb.find(xmin).text)) ymin int(float(bb.find(ymin).text)) xmax int(float(bb.find(xmax).text)) ymax int(float(bb.find(ymax).text)) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (0, 0, 255), 2) cv2.putText(img, meat, (xmin, ymin - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) out_path os.path.join(checks_dir, stem _check.jpg) cv2.imwrite(out_path, img) print(已保存核查圖片:, out_path)邏輯說明通過cv2讀取真實(shí)圖片用xml里的絕對坐標(biāo)畫紅色矩形框。這里要注意cv2.rectangle的坐標(biāo)順序是左上、右下正好對應(yīng)VOC的bndbox。如果框在圖中能貼合病灶區(qū)的邊緣說明標(biāo)注基本可信如果框跑到圖外或者明顯錯位就要回到錯誤目錄重新生成標(biāo)注。這個腳本只抽查前10個xml便于快速人工看。如果你想全量生成把idx 10的循環(huán)條件去掉即可但6012張圖全部輸出會比較占空間。參數(shù)說明顏色(0,0,255)是紅色文字標(biāo)簽可以改成你最后使用的類別名。如果圖片較大畫了框以后保存的jpeg體積會增加檢查完沒發(fā)現(xiàn)問題就刪掉整個目錄不用保留。注意中文路徑下cv2.imwrite可能報錯輸出文件名建議用純英文stem。這個方法投入的時間不超過三分鐘但能扼殺掉絕大部分“標(biāo)簽格式?jīng)]問題但訓(xùn)練崩了”的玄學(xué)問題。最后一次用這個數(shù)據(jù)集時我抽查到第7張圖發(fā)現(xiàn)xml里的xmin變成0追溯原因仍然是前一份xml尺寸錯誤。從那以后我每次下載別人標(biāo)注數(shù)據(jù)集都會先強(qiáng)制走一遍這個遍歷核查流程確認(rèn)框形和統(tǒng)計都正常后才交給訓(xùn)練腳本。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取