【算法介紹】
在航空運輸安全保障要求持續升級、對機場運行精細化管控需求愈發迫切的背景下,傳統機場跑道異物檢測方式已難以應對複雜多變的跑道環境。基於YOLOv11的機場跑道異物檢測系統應運而生,為航空領域帶來了高效、精準的異物排查解決方案。
該系統具備強大的多類型異物識別能力,可精準識別金屬碎片(metal debris)、小石子(small stones)、塑料雜物(plastic debris)、釘子(Nailtrack)、電線(Wiretrack)以及工具零件(tool parts)等多種常見跑道異物。YOLOv11作為核心算法,憑藉其創新的架構設計,在檢測速度和精度上實現了質的飛躍。它採用優化的特徵融合網絡,能夠迅速捕捉跑道圖像中異物的細微特徵,無論是異物的形狀、大小還是材質特性,都能被精準識別和解析。
在實際應用中,系統展現出非凡的性能。對於微小或隱蔽的異物,如細小的金屬碎片和布料碎片,其高分辨率檢測能力可確保不放過任何潛在威脅;面對複雜多變的跑道場景,如強光照射、陰影覆蓋或雨雪天氣,系統通過智能光照補償和抗噪濾波機制,有效降低誤檢和漏檢率。
此外,該系統支持高速實時處理,能夠快速分析跑道監控攝像頭採集的視頻流,即時輸出異物類型、位置和尺寸信息。這不僅為機場跑道安全評估、異物清理調度提供了有力支撐,還能助力機場運行管理部門實現風險預警和應急響應。
基於YOLOv11的機場跑道異物檢測系統,以其高效、精準、實時的特性,成為航空安全領域不可或缺的技術利器,為保障航班起降安全、提升機場運行效率發揮着關鍵作用。
【效果展示】
【訓練數據集介紹】
數據集格式:YOLO格式(不包含分割路徑的txt文件,僅僅包含jpg圖片以及對應的yolo格式txt文件)
圖片數量(jpg文件個數):7376
標註數量(txt文件個數):7376
訓練集數量:5163
驗證集數量:1475
測試集數量:738
標註類別數:30
所在倉庫:firc-dataset
標註類別名稱(注意yolo格式類別順序不和這個對應,而以labels文件夾classes.txt為準):['AdjustableClamptrack_idkeyframe','AdjustableWrenchtrack_idkeyframe','Batterytrack_idkeyframe','BoltNutSettrack_idkeyframe','BoltWashertrack_idkeyframe','Bolttrack_idkeyframe','ClampParttrack_idkeyframe','Cuttertrack_idkeyframe','FuelCaptrack_idkeyframe','Hammertrack_idkeyframe','Hosetrack_idkeyframe','Labeltrack_idkeyframe','LuggageParttrack_idkeyframe','LuggageTagtrack_idkeyframe','MetalParttrack_idkeyframe','MetalSheettrack_idkeyframe','Nailtrack_idkeyframe','Nuttrack_idkeyframe','PaintChiptrack_idkeyframe','Pentrack_idkeyframe','PlasticParttrack_idkeyframe','Plierstrack_idkeyframe','Rocktrack_idkeyframe','Screwdrivertrack_idkeyframe','Screwtrack_idkeyframe','SodaCantrack_idkeyframe','Washertrack_idkeyframe','Wiretrack_idkeyframe','Woodtrack_idkeyframe','Wrenchtrack_idkeyframe']
每個類別標註的框數:
AdjustableClamptrack_idkeyframe 框數=127
AdjustableWrenchtrack_idkeyframe 框數=109
Batterytrack_idkeyframe 框數=202
BoltNutSettrack_idkeyframe 框數=126
BoltWashertrack_idkeyframe 框數=250
Bolttrack_idkeyframe 框數=794
ClampParttrack_idkeyframe 框數=155
Cuttertrack_idkeyframe 框數=313
FuelCaptrack_idkeyframe 框數=135
Hammertrack_idkeyframe 框數=148
Hosetrack_idkeyframe 框數=74
Labeltrack_idkeyframe 框數=275
LuggageParttrack_idkeyframe 框數=138
LuggageTagtrack_idkeyframe 框數=369
MetalParttrack_idkeyframe 框數=154
MetalSheettrack_idkeyframe 框數=102
Nailtrack_idkeyframe 框數=307
Nuttrack_idkeyframe 框數=248
PaintChiptrack_idkeyframe 框數=184
Pentrack_idkeyframe 框數=91
PlasticParttrack_idkeyframe 框數=477
Plierstrack_idkeyframe 框數=662
Rocktrack_idkeyframe 框數=136
Screwdrivertrack_idkeyframe 框數=218
Screwtrack_idkeyframe 框數=35
SodaCantrack_idkeyframe 框數=169
Washertrack_idkeyframe 框數=517
Wiretrack_idkeyframe 框數=401
Woodtrack_idkeyframe 框數=45
Wrenchtrack_idkeyframe 框數=594
總框數=7555
使用標註工具:labelImg
標註規則:對類別進行畫矩形框
重要説明:暫無
特別聲明:本數據集不對訓練的模型或者權重文件精度作任何保證
圖片預覽:
標註例子:
【測試環境】
windows10
anaconda3+python3.8
torch==2.3.1
ultralytics==8.3.120
【模型可以檢測出類別】
AdjustableClamptrack_idkeyframe (可調夾具)
AdjustableWrenchtrack_idkeyframe (活動扳手)
Batterytrack_idkeyframe (電池)
BoltNutSettrack_idkeyframe (螺栓螺母組)
BoltWashertrack_idkeyframe (螺栓墊圈)
Bolttrack_idkeyframe (螺栓)
ClampParttrack_idkeyframe (夾具部件)
Cuttertrack_idkeyframe (切割器)
FuelCaptrack_idkeyframe (燃油蓋)
Hammertrack_idkeyframe (錘子)
Hosetrack_idkeyframe (軟管)
Labeltrack_idkeyframe (標籤)
LuggageParttrack_idkeyframe (行李部件)
LuggageTagtrack_idkeyframe (行李牌)
MetalParttrack_idkeyframe (金屬部件)
MetalSheettrack_idkeyframe (金屬板)
Nailtrack_idkeyframe (釘子)
Nuttrack_idkeyframe (螺母)
PaintChiptrack_idkeyframe (漆片)
Pentrack_idkeyframe (筆)
PlasticParttrack_idkeyframe (塑料部件)
Plierstrack_idkeyframe (鉗子)
Rocktrack_idkeyframe (石塊)
Screwdrivertrack_idkeyframe (螺絲刀)
Screwtrack_idkeyframe (螺絲)
SodaCantrack_idkeyframe (汽水罐)
Washertrack_idkeyframe (墊圈)
Wiretrack_idkeyframe (電線)
Woodtrack_idkeyframe (木材)
Wrenchtrack_idkeyframe (扳手)
【訓練信息】
|
參數
|
值
|
|
訓練集圖片數
|
5163
|
|
驗證集圖片數
|
1475
|
|
訓練map
|
99.3%
|
|
訓練精度(Precision)
|
99.1%
|
|
訓練召回率(Recall)
|
99.3%
|
驗證集統計:
|
Class |
Images |
Instances |
P |
R |
mAP50 |
mAP50-95 |
|
all |
1475 |
1503 |
0.991 |
0.993 |
0.993 |
0.902 |
|
AdjustableClamptrack_idkeyframe |
31 |
31 |
0.991 |
1 |
0.995 |
0.93 |
|
AdjustableWrenchtrack_idkeyframe |
32 |
32 |
0.978 |
1 |
0.995 |
0.952 |
|
Batterytrack_idkeyframe |
45 |
45 |
0.995 |
1 |
0.995 |
0.83 |
|
BoltNutSettrack_idkeyframe |
22 |
22 |
0.99 |
1 |
0.995 |
0.696 |
|
BoltWashertrack_idkeyframe |
49 |
49 |
0.998 |
1 |
0.995 |
0.818 |
|
Bolttrack_idkeyframe |
163 |
163 |
1 |
0.996 |
0.995 |
0.828 |
|
ClampParttrack_idkeyframe |
36 |
36 |
0.993 |
1 |
0.995 |
0.966 |
|
Cuttertrack_idkeyframe |
58 |
58 |
0.996 |
1 |
0.995 |
0.972 |
|
FuelCaptrack_idkeyframe |
23 |
23 |
0.988 |
1 |
0.995 |
0.935 |
|
Hammertrack_idkeyframe |
29 |
29 |
0.99 |
1 |
0.995 |
0.973 |
|
Hosetrack_idkeyframe |
15 |
15 |
0.982 |
1 |
0.995 |
0.98 |
|
Labeltrack_idkeyframe |
44 |
44 |
0.995 |
1 |
0.995 |
0.931 |
|
LuggageParttrack_idkeyframe |
32 |
32 |
0.994 |
1 |
0.995 |
0.964 |
|
LuggageTagtrack_idkeyframe |
84 |
84 |
0.998 |
1 |
0.995 |
0.888 |
|
MetalParttrack_idkeyframe |
25 |
25 |
0.99 |
1 |
0.995 |
0.903 |
|
MetalSheettrack_idkeyframe |
17 |
17 |
0.983 |
1 |
0.995 |
0.995 |
|
Nailtrack_idkeyframe |
50 |
50 |
1 |
0.982 |
0.995 |
0.676 |
|
Nuttrack_idkeyframe |
51 |
51 |
1 |
0.949 |
0.995 |
0.817 |
|
PaintChiptrack_idkeyframe |
33 |
33 |
0.996 |
1 |
0.995 |
0.978 |
|
Pentrack_idkeyframe |
14 |
14 |
0.99 |
1 |
0.995 |
0.886 |
|
PlasticParttrack_idkeyframe |
96 |
96 |
0.997 |
1 |
0.995 |
0.979 |
|
Plierstrack_idkeyframe |
129 |
129 |
0.995 |
0.977 |
0.988 |
0.94 |
|
Rocktrack_idkeyframe |
33 |
33 |
0.992 |
1 |
0.995 |
0.9 |
|
Screwdrivertrack_idkeyframe |
41 |
41 |
0.991 |
1 |
0.995 |
0.985 |
|
Screwtrack_idkeyframe |
10 |
10 |
0.982 |
1 |
0.995 |
0.847 |
|
SodaCantrack_idkeyframe |
36 |
36 |
0.991 |
1 |
0.995 |
0.982 |
|
Washertrack_idkeyframe |
93 |
93 |
0.989 |
0.959 |
0.987 |
0.736 |
|
Wiretrack_idkeyframe |
80 |
80 |
0.995 |
1 |
0.995 |
0.973 |
|
Woodtrack_idkeyframe |
8 |
8 |
0.967 |
1 |
0.995 |
0.995 |
|
Wrenchtrack_idkeyframe |
124 |
124 |
0.999 |
0.927 |
0.946 |
0.793 |
【界面設計】
class Ui_MainWindow(QtWidgets.QMainWindow):
signal = QtCore.pyqtSignal(str, str)
def setupUi(self):
self.setObjectName("MainWindow")
self.resize(1280, 728)
self.centralwidget = QtWidgets.QWidget(self)
self.centralwidget.setObjectName("centralwidget")
self.weights_dir = './weights'
self.picture = QtWidgets.QLabel(self.centralwidget)
self.picture.setGeometry(QtCore.QRect(260, 10, 1010, 630))
self.picture.setStyleSheet("background:black")
self.picture.setObjectName("picture")
self.picture.setScaledContents(True)
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(10, 10, 81, 21))
self.label_2.setObjectName("label_2")
self.cb_weights = QtWidgets.QComboBox(self.centralwidget)
self.cb_weights.setGeometry(QtCore.QRect(10, 40, 241, 21))
self.cb_weights.setObjectName("cb_weights")
self.cb_weights.currentIndexChanged.connect(self.cb_weights_changed)
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setGeometry(QtCore.QRect(10, 70, 72, 21))
self.label_3.setObjectName("label_3")
self.hs_conf = QtWidgets.QSlider(self.centralwidget)
self.hs_conf.setGeometry(QtCore.QRect(10, 100, 181, 22))
self.hs_conf.setProperty("value", 25)
self.hs_conf.setOrientation(QtCore.Qt.Horizontal)
self.hs_conf.setObjectName("hs_conf")
self.hs_conf.valueChanged.connect(self.conf_change)
self.dsb_conf = QtWidgets.QDoubleSpinBox(self.centralwidget)
self.dsb_conf.setGeometry(QtCore.QRect(200, 100, 51, 22))
self.dsb_conf.setMaximum(1.0)
self.dsb_conf.setSingleStep(0.01)
self.dsb_conf.setProperty("value", 0.25)
self.dsb_conf.setObjectName("dsb_conf")
self.dsb_conf.valueChanged.connect(self.dsb_conf_change)
self.dsb_iou = QtWidgets.QDoubleSpinBox(self.centralwidget)
self.dsb_iou.setGeometry(QtCore.QRect(200, 160, 51, 22))
self.dsb_iou.setMaximum(1.0)
self.dsb_iou.setSingleStep(0.01)
self.dsb_iou.setProperty("value", 0.45)
self.dsb_iou.setObjectName("dsb_iou")
self.dsb_iou.valueChanged.connect(self.dsb_iou_change)
self.hs_iou = QtWidgets.QSlider(self.centralwidget)
self.hs_iou.setGeometry(QtCore.QRect(10, 160, 181, 22))
self.hs_iou.setProperty("value", 45)
self.hs_iou.setOrientation(QtCore.Qt.Horizontal)
self.hs_iou.setObjectName("hs_iou")
self.hs_iou.valueChanged.connect(self.iou_change)
self.label_4 = QtWidgets.QLabel(self.centralwidget)
self.label_4.setGeometry(QtCore.QRect(10, 130, 72, 21))
self.label_4.setObjectName("label_4")
self.label_5 = QtWidgets.QLabel(self.centralwidget)
self.label_5.setGeometry(QtCore.QRect(10, 210, 72, 21))
self.label_5.setObjectName("label_5")
self.le_res = QtWidgets.QTextEdit(self.centralwidget)
self.le_res.setGeometry(QtCore.QRect(10, 240, 241, 400))
self.le_res.setObjectName("le_res")
self.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(self)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1110, 30))
self.menubar.setObjectName("menubar")
self.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(self)
self.statusbar.setObjectName("statusbar")
self.setStatusBar(self.statusbar)
self.toolBar = QtWidgets.QToolBar(self)
self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
self.toolBar.setObjectName("toolBar")
self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
self.actionopenpic = QtWidgets.QAction(self)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/images/1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionopenpic.setIcon(icon)
self.actionopenpic.setObjectName("actionopenpic")
self.actionopenpic.triggered.connect(self.open_image)
self.action = QtWidgets.QAction(self)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(":/images/2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.action.setIcon(icon1)
self.action.setObjectName("action")
self.action.triggered.connect(self.open_video)
self.action_2 = QtWidgets.QAction(self)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(":/images/3.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.action_2.setIcon(icon2)
self.action_2.setObjectName("action_2")
self.action_2.triggered.connect(self.open_camera)
self.actionexit = QtWidgets.QAction(self)
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap(":/images/4.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionexit.setIcon(icon3)
self.actionexit.setObjectName("actionexit")
self.actionexit.triggered.connect(self.exit)
self.toolBar.addAction(self.actionopenpic)
self.toolBar.addAction(self.action)
self.toolBar.addAction(self.action_2)
self.toolBar.addAction(self.actionexit)
self.retranslateUi()
QtCore.QMetaObject.connectSlotsByName(self)
self.init_all()
【常用評估參數介紹】
在目標檢測任務中,評估模型的性能是至關重要的。你提到的幾個術語是評估模型性能的常用指標。下面是對這些術語的詳細解釋:
Class:
這通常指的是模型被設計用來檢測的目標類別。例如,一個模型可能被訓練來檢測車輛、行人或動物等不同類別的對象。
Images:
表示驗證集中的圖片數量。驗證集是用來評估模型性能的數據集,與訓練集分開,以確保評估結果的公正性。
Instances:
在所有圖片中目標對象的總數。這包括了所有類別對象的總和,例如,如果驗證集包含100張圖片,每張圖片平均有5個目標對象,則Instances為500。
P(精確度Precision):
精確度是模型預測為正樣本的實例中,真正為正樣本的比例。計算公式為:Precision = TP / (TP + FP),其中TP表示真正例(True Positives),FP表示假正例(False Positives)。
R(召回率Recall):
召回率是所有真正的正樣本中被模型正確預測為正樣本的比例。計算公式為:Recall = TP / (TP + FN),其中FN表示假負例(False Negatives)。
mAP50:
表示在IoU(交併比)閾值為0.5時的平均精度(mean Average Precision)。IoU是衡量預測框和真實框重疊程度的指標。mAP是一個綜合指標,考慮了精確度和召回率,用於評估模型在不同召回率水平上的性能。在IoU=0.5時,如果預測框與真實框的重疊程度達到或超過50%,則認為該預測是正確的。
mAP50-95:
表示在IoU從0.5到0.95(間隔0.05)的範圍內,模型的平均精度。這是一個更嚴格的評估標準,要求預測框與真實框的重疊程度更高。在目標檢測任務中,更高的IoU閾值意味着模型需要更準確地定位目標對象。mAP50-95的計算考慮了從寬鬆到嚴格的多個IoU閾值,因此能夠更全面地評估模型的性能。
這些指標共同構成了評估目標檢測模型性能的重要框架。通過比較不同模型在這些指標上的表現,可以判斷哪個模型在實際應用中可能更有效。
【使用步驟】
使用步驟:
(1)首先根據官方框架ultralytics安裝教程安裝好yolov11環境,並安裝好pyqt5
(2)切換到自己安裝的yolo11環境後,並切換到源碼目錄,執行python main.py即可運行啓動界面,進行相應的操作即可
【提供文件】
python源碼
yolo11n.pt模型
訓練的map,P,R曲線圖(在weights\results.png)
測試圖片(在dataset/test/images文件夾下面)
注意提供訓練的數據集,在dataset文件夾