
簡介這是一套基于YOLOv8的智慧碼頭集裝箱箱號自動識別系統主要面向計算機視覺、深度學習方向的畢業設計、課程設計或項目實踐。源碼由個人畢設整理完成運行測試通過包含完整數據集、可視化界面與部署文檔可生成混淆矩陣、F1分數曲線、精確率-召回率曲線、標簽分布圖等關鍵評估圖表便于答辯展示。壓縮包共8個文件其中3個py腳本負責模型訓練、視頻檢測與可視化交互3個pt文件為訓練好的模型權重與最佳模型2個txt文件提供說明與配置指引整體僅15.91MB輕量易部署。目前已有35人學習瀏覽適合需要快速搭建目標檢測演示系統的初學者或答辯前查漏補缺的學生。通過該資源可掌握YOLOv8在真實集裝箱箱號識別場景中的完整流程——從數據集組織、模型訓練到推理驗證、界面展示代碼結構清晰修改后也可遷移至其他字符識別或目標檢測任務實用性和完成度都比較高。1. 集裝箱箱號識別為什么適合直接用YOLOv8字符檢測集裝箱箱號識別放到真實碼頭里比實驗室跑通要麻煩得多。箱號噴在瓦楞鋼箱體表面金屬反光、油污、銹蝕、綁扎件遮擋和相機俯仰角疊加在一起整行OCR往往在第一個字符就定位失敗。這套基于YOLOv8的識別系統換了一條更穩的技術路線不直接讀整行文本而是把箱號里的每個字符當作獨立目標用目標檢測的方式先定位后分類再按字符框的空間坐標排序拼回完整箱號。這樣即使個別字符被反光吞掉也能從前后位置關系里判斷缺了幾位。對做畢業設計或課程設計的人來說它給了一條從數據集構建、模型訓練、指標驗證到可視化界面部署的完整鏈路并且自帶驗證集預測結果、混淆矩陣、F1分數曲線、精確率-召回率曲線和標簽分布圖拿來改一改就能適配自己的數據。2. 數據集構建ISO 6346字符集、YOLO標注與標簽分布分析不管是用項目自帶數據集還是重新標注一批現場圖片都要先理解箱號在YOLO坐標系下是如何表達的。這一章把數據層面的事情講透后面的訓練和部署才不會返工。2.1 箱號格式與檢測粒度選擇集裝箱箱號遵循 ISO 6346 標準前三位是箱主代碼第四位是設備類別碼干貨箱一般為大寫字母 U接著是六位注冊編號最后一位是獨立的校驗碼整體一共 11 個字符。字母只出現在前四位數字占后七位這個先驗知識對后處理拼接和校驗非常重要。ISO 6346 還規定字母表必須排除 I 和 O避免與數字 1、0 在金屬表面上相互混淆所以實際字符類別是 24 個字母加 10 個數字一共 34 類。處理粒度方面整行 OCR 需要先定位箱號區域再交給識別模型定位框稍微偏移后半段數字就會全部錯位。YOLOv8 字符檢測方案則把 11 個字符當作 34 類目標里的任意組合來做密集小目標檢測每個字符獨立輸出一個帶類別和置信度的檢測框再通過坐標聚類拼出完整箱號。即使某個字符被遮擋漏檢前后框的間距也能提示這里少了一位工程上更容易兜底。這套項目里的訓練腳本、視頻推理和可視化界面全部圍繞這種字符檢測粒度組織包括預訓練權重里默認的 34 類分類頭。2.2 數據集目錄結構與YOLO標簽格式下載資源解壓后數據集目錄按 YOLO 標準格式組織圖片與標簽文件同名一一對應。典型的目錄結構如下dataset/ ├── images/ │ ├── train/ # 訓練圖片建議不同時段、不同箱型混合 │ └── val/ # 驗證圖片盡量與 train 不同批次采集 ├── labels/ │ ├── train/ # 每個 jpg 對應一個同名 txt │ └── val/ ├── dataset.yaml # 模型訓練時讀取的數據集配置 └── stats/ └── label_distribution.png # 由統計腳本生成的標簽分布圖每個 txt 文件里一行描述一個字符目標格式為class x_center y_center width height坐標全部歸一化到 0 到 1 之間。以某張訓練圖片為例12 0.5312 0.6435 0.0421 0.0912 33 0.5867 0.6421 0.0402 0.0898 7 0.6402 0.6389 0.0418 0.0907第一列是類別索引對應 dataset.yaml 里 names 列表的位置后面四列分別是歸一化后的中心點 x、中心點 y、框寬和框高。類別順序一旦定下來就不要在中途修改否則重新訓練時標簽全部錯位。項目自帶的標簽文件已經按固定順序生成如果你打算換自己的數據集建議先用腳本跑一遍標簽格式校驗再開始訓練。2.3 dataset.yaml配置與標簽分布分析dataset.yaml 是訓練入口train 和 val 路徑寫相對路徑時必須保證命令行當前工作目錄在 dataset 的上級目錄。示例如下# dataset/dataset.yaml path: . train: images/train val: images/val nc: 34 names: 0: 0 1: 1 2: 2 3: 3 4: 4 5: 5 6: 6 7: 7 8: 8 9: 9 10: A 11: B 12: C 13: D 14: E 15: F 16: G 17: H 18: J 19: K 20: L 21: M 22: N 23: P 24: Q 25: R 26: S 27: T 28: U 29: V 30: W 31: X 32: Y 33: Znames 順序建議固定為數字在前、字母在后并且字母表跳過 I 和 O。這樣做的直接好處是類別索引和 ASCII 順序天然一致后處理里做類別名映射時不容易寫錯下標。數據準備的下一步是統計每個類別的樣本數量我在拿到新數據集時一般會先跑一個標簽分布統計腳本把類別不平衡的情況可視化出來# stats_label_distribution.py統計訓練集每個類別的目標數并繪制柱狀圖 from pathlib import Path import matplotlib.pyplot as plt import numpy as np label_dir Path(dataset/labels/train) counts np.zeros(34, dtypeint) for txt in label_dir.glob(*.txt): for line in txt.read_text().strip().splitlines(): cls int(line.split()[0]) counts[cls] 1 labels [str(i) for i in range(10)] list(ABCDEFGHJKLMNPQRSTUVWXYZ) plt.figure(figsize(14, 6)) plt.bar(range(34), counts, tick_labellabels) plt.xticks(rotation45, fontsize8) plt.ylabel(sample count) plt.savefig(label_distribution.png, dpi160) plt.show()這段腳本讀取全部訓練標簽把每個 txt 的第一列累加到對應類別桶里最后畫出柱狀圖。運行之后重點關注兩類問題一是某些字母類別樣本量遠低于平均數比如 Q、Z 這類冷門字符在碼頭上出現頻率很低檢測器對尾部類別的召回率天然不佳一個字母漏檢就會導致整個箱號識別失敗二是數字與易混字母的樣本比例只要 D 和 0、B 和 8、S 和 5 這三組數據分布差距過大混淆矩陣里就會出現明顯的誤檢塊。統計出結果后如果某個類別低于 1000 個框我一般會優先用復制增強或者重新采集補樣本而不是直接開訓。2.4 數據增強參數怎么調YOLOv8 默認開啟 mosaic、hsv、平移和縮放增強但這些默認值并不完全適合字符檢測場景。mosaic 把四張圖拼接成一張會導致字符這種小目標被切碎在拼接縫附近訓練后期的負面影響尤其明顯。表 2-1 是我在箱號數據集上常用的增強參數配置和默認值拉開差距的地方都做了標注。參數默認值箱號場景建議調整理由mosaic1.0最后 10 輪設為 0字符框小mosaic 拼接會切碎目標degrees0.03 ~ 5碼頭相機角度固定沒必要加大旋轉擾動hsv_h0.0150.01過強的色相偏移會模擬出訓練集不存在的金屬反光色scale0.50.8箱號字符尺度變化大適當放大幫助小目標檢測translate0.10.05箱號位置相對固定不需要大幅平移這些參數在 train_mode.py 里通常有兩種寫法。一種是直接在 model.train() 里以關鍵字參數傳入比如close_mosaic10表示最后 10 輪自動關閉 mosaic另一種是在一個單獨的 yaml 里定義增強配置。跑訓練之前先看一眼腳本里讀的是哪種方式避免改了參數實際沒生效。關于驗證集劃分還需要保證 val 集和 train 集不是同一批圖片的不同幀不然標簽分布圖會漂亮得沒有參考價值。3. 訓練與調優C2f骨干、預訓練權重與指標曲線解讀環境配置是第一個容易被卡住的環節。項目依賴的核心是 ultralytics 庫Python 3.8 及以上版本執行pip install ultralytics即可它會把 torch 和 torchvision 一起拉起來。做完數據集校驗、補齊尾部類別樣本后就可以進入正式訓練。3.1 train_mode.py的訓練流程與參數含義train_mode.py 是項目里負責模型訓練的入口核心邏輯和下面的代碼骨架一致但具體超參數要以 README.txt 里寫的為準。實際運行前先確認 dataset.yaml 中的路徑和當前工作目錄匹配否則會很早拋出數據集加載失敗的錯誤。# train_mode.py 核心訓練邏輯 from ultralytics import YOLO if __name__ __main__: model YOLO(yolov8n.pt) # 加載 COCO 預訓練權重做遷移學習 model.train( datadataset/dataset.yaml, epochs120, imgsz640, batch16, device0, patience15, lr00.01, close_mosaic10, namecontainer_ocr, )上面代碼里YOLO(yolov8n.pt)表示加載 YOLOv8n 的 COCO 預訓練權重箱號字符檢測屬于典型的領域遷移直接從頭訓練會顯著增加收斂時間data指定數據集配置imgsz640是輸入分辨率字符是小目標不建議降到 416batch受顯卡顯存約束GTX 1660Ti 這類 6GB 顯存卡我把 batch 設置在 8 到 16 之間配合默認開啟的 AMP 混合精度可以正常跑完lr0是初始學習率字符類別數少學習率偏大容易在早期震蕩close_mosaic10表示最后 10 輪關閉 mosaic 增強讓模型在小目標上做精細適配。這組超參不是唯一解。如果你的顯卡顯存小于 6GB就把 batch 降到 8并把workers同時調低避免數據加載成為瓶頸。如果訓練集圖像分辨率本身就超過 1280可以試試 imgsz 取 960但顯存占用會同步上漲需要權衡。遇到顯存溢出時先看 nvidia-smi確認是不是別的進程占用了顯存再決定降 batch 還是降 imgsz。3.2 預訓練權重怎么選yolov8n.pt、yolo11n.pt與best.pt項目里同時出現了兩個預訓練權重文件yolov8n.pt 是訓練腳本默認加載的 YOLOv8 最小的 nano 版特點是參數少、推理快yolo11n.pt 是 YOLO11 的 nano 版網絡結構上把 YOLOv8 的 C2f 換成了 C3k2 模塊同樣主打輕量部署。兩者在訓練時都可以作為起點只是網絡結構圖里骨干和頸部的組合不同最終精度也會有小幅差異。權重文件參數量級結構特點適用場景yolov8n.pt約 3.2MC2f 骨干梯度支路豐富訓練腳本默認起點穩妥選擇yolo11n.pt約 2.6MC3k2 模塊計算量更低對比實驗或追求更高 FPS 時使用best.pt訓練產物由 train_mode.py 生成推理腳本和可視化界面默認加載我在箱號數據集上做對比實驗時會在 train_mode.py 里把YOLO(yolov8n.pt)替換成YOLO(yolo11n.pt)保持其他超參數完全一致各訓一輪后再用驗證集 F1 曲線對比。注意兩個權重文件的類別數都是 COCO 的 80 類它們只負責提供骨干特征提取能力最后輸出頭的類別數會在訓練時根據 dataset.yaml 的 nc 自動重建不用擔心 34 類字符放不進去。對畢設來說用默認的 yolov8n.pt 訓練到收斂再換 yolo11n.pt 做一組對照正好可以作為答辯里對比實驗的素材。3.3 訓練產物解讀混淆矩陣、F1與損失曲線訓練結束后在 runs/detect/container_ocr 目錄下能看到一批分析圖這些圖在答辯時是證明系統有效性的直接材料。results.png 里包含 box_loss、cls_loss、dfl_loss 三條損失曲線和 mAP50、mAP50-95 兩條精度曲線也就是常說的損失函數曲線圖觀察 loss 曲線時關注的是下降后是否呈收斂平臺而不是追求數值上無限接近零。confusion_matrix.png 是字符混淆矩陣第 i 行第 j 列代表真實類別 i 被預測成類別 j 的樣本數對角線越亮越好。最容易出問題的是 D 與 0、B 與 8、S 與 5 三組鋼印字體中這些字符輪廓高度相似如果這三塊附近出現亮色塊說明數據增強或分辨率還需要調整。F1_curve.png 展示不同置信度閾值下的 F1 分數曲線最高點對應的閾值就是推理時最合適的 confidence 參數我通常會在 0.4 到 0.55 之間取比無腦用默認的 0.25 直觀得多。PR_curve.png 則反映精確率和召回率的整體平衡曲線越靠近右上角越好。val_batch0_pred.jpg 這類驗證集預測圖展示的是模型在未見過的圖片上畫出的檢測框和類別標簽用來做定性檢查比如是否存在同一字符被重復檢測、相鄰字符框是否粘連。標簽分布圖由第 2 章的統計腳本生成和這些指標曲線一起放進論文附錄能讓評審快速確認實驗數據的可靠性。4. 推理落地Detection_video.py、Visual_interface.py與箱號拼接訓練完成后best.pt 就是整個系統真正要用的權重。項目里的推理鏈路分成兩條Detection_video.py 面向視頻流和攝像頭Visual_interface.py 面向人工交互的可視化界面。兩條鏈路底層走的都是同一個推理邏輯只是輸入源和結果呈現方式不同。4.1 視頻推理腳本的典型用法Detection_video.py 一般接收權重路徑、視頻路徑、置信度閾值和輸入分辨率這幾個參數。常見的啟動方式如下# 對本地視頻文件做識別 python Detection_video.py --weights best.pt --source test_video.mp4 --conf 0.45 --imgsz 640 # 對攝像頭實時流做識別source 傳攝像頭索引 python Detection_video.py --weights best.pt --source 0 --conf 0.45 --imgsz 640--conf是置信度閾值低于這個值的檢測框會被丟棄取值建議先對照第 3 章 F1 曲線的峰值來確定--source 0表示讀取本機第一個攝像頭在碼頭頂部相機場景里通常是一個 RTSP 拉流地址。實際運行前先檢查腳本里是用 argparse 解析參數還是硬編碼路徑如果硬編碼直接改源碼里的輸入路徑常量即可README.txt 里一般已寫明推薦值。視頻推理的瓶頸往往不在檢測本身而在視頻解碼和結果顯示。使用 OpenCV 的 VideoCapture 讀取高分辨率視頻時解碼耗時可能比模型前向推理還高這種情況我會先把視頻幀縮放至 1280 寬度再做檢測箱號字符在 640 分辨率下已經足夠檢出盲目保持原尺寸只會拖慢速度。4.2 可視化界面Visual_interface.py的功能組織Visual_interface.py 是整個項目里答辯演示最有沖擊力的部分。界面通常分為三個區域左側是模型和輸入源選擇區中間是實時檢測結果預覽右側是識別到的箱號文本和置信度信息。操作流程大致是加載 best.pt 權重選擇圖片、視頻或攝像頭輸入點擊開始識別后界面逐幀顯示檢測框并把箱號實時拼出來。這類界面如果用的是 Tkinter簡單但刷新效率一般如果用的是 PySide6則要注意把模型推理放到子線程里執行否則視頻幀一過來界面就會卡死。常見做法是用 QThread 接收視頻幀推理完成后通過信號把帶框圖像傳回主線程更新界面。這里有一個容易踩的坑在子線程里直接訪問界面控件對象輕則警告重則崩潰正確做法是只發信號不傳對象。如果腳本里已有這個機制在答辯演示時就不會出現切換視頻源后界面無響應的問題。4.3 從檢測框到完整箱號行聚類與坐標排序模型輸出的只是 34 類字符的獨立檢測框必須把它們按空間位置組織成字符串。由于箱體上字符是一行排列的后處理的第一步是把所有檢測框按 y 坐標聚類成行第二步在行內按 x 坐標排序最后拼接成箱號。這個邏輯看起來簡單但在視頻幀的連續推理里框的抖動會直接影響排序穩定性。# sort_boxes.py把YOLOv8輸出的字符框拼成箱號 def boxes_to_code(boxes, row_thr15): # boxes: list of [x1, y1, x2, y2, conf, cls] rows [] for b in boxes: y_center (b[1] b[3]) / 2 target None for row in rows: if abs(y_center - row[yc]) row_thr: target row break if target is None: rows.append({yc: y_center, boxes: [b]}) else: target[boxes].append(b) # 更新該行的平均y中心避免累積偏移 target[yc] sum((x[1] x[3]) / 2 for x in target[boxes]) / len(target[boxes]) codes [] for row in rows: row[boxes].sort(keylambda x: x[0]) # 行內按x左邊界排序 codes.append(.join(class_names[int(b[5])] for b in row[boxes])) return codes這段代碼先按 y 中心點做行聚類row_thr15表示兩個字符框的 y 中心距離小于 15 像素就視為同一行這個閾值應根據實際圖像高度等比調整例如取圖像高度的 0.01 到 0.03 倍。找到同一行的字符后按 x 左邊界排序而不是按中心點排序因為字符框寬度差異不大但左邊界更能反映真實閱讀順序。行聚類完成后每一行拼接出的字符串就是一個候選箱號。如果畫面里同時出現兩行字符比如看多了半截字體這段代碼會返回多個字符串再由上層邏輯按長度和校驗位篩選。4.4 GPU與CPU部署的差異處理推理階段對速度的要求比訓練階段更高尤其是視頻流識別。NVIDIA 顯卡上可以做兩件事一是開啟半精度推理GTX 16 系及以上架構都支持顯存占用和單幀延遲都能再降一檔。python Detection_video.py --weights best.pt --half二是把模型導出成 engine 格式減少運行時構圖開銷。CPU 推理場景下batch 固定為 1輸入分辨率保持 640yolov8n 在桌面級 CPU 上單幀大約幾百毫秒勉強可用于離線圖片識別實時視頻就需要考慮 GPU 或邊緣設備加速。項目里可視化界面默認加載 best.pt 的路徑如果找不到權重文件界面啟動時會直接報錯退不出調試時先檢查weights這個全局變量是否指向真實存在的文件。5. 進階ISO 6346校驗位、邊界樣本處理與TensorRT優化基本鏈路跑通后還能做幾件提升系統可靠性的工作。ISO 6346 的校驗位機制可以用來過濾識別錯誤的箱號TensorRT 導出則能顯著降低視頻推理延遲。5.1 用ISO 6346校驗位驗證識別結果ISO 6346 規定第 11 位是校驗碼它由前 10 位字符按特定規則計算得到。識別結果出來后立刻用前 10 位重新計算校驗碼與第 11 位比較不一致就說明識別有誤應當觸發人工復核。校驗算法如下def iso6346_check(container_no: str): # container_no 為前10位返回應與第11位字符一致 mapping {c: ord(c) - ord(A) 10 for c in ABCDEFGHJKLMNPQRSTUVWXYZ} total 0 for i, ch in enumerate(container_no): v mapping.get(ch, int(ch)) total v * (2 ** i) # 權重為2的i次方 check total % 11 return 0 if check 10 else str(check)權重從第 0 位開始按 2 的冪遞增累加后對 11 取模余數 10 映射為 0。使用例子模型識別結果是 CMSU1234565前 10 位是 CMSU123456計算出校驗碼如果等于 5 則通過否則把這條結果標記為低置信輸出彈窗提示人工確認。這個邏輯加到 Visual_interface.py 里并不復雜但效果顯著能直接把誤識別箱號擋閘在自動過閘流程之外。5.2 現場常見壞樣本的應對碼頭現場的壞樣本集中在幾類鋼面反光、字符銹蝕、綁扎件遮擋、雨霧天模糊。針對反光推理前對圖像做 CLAHE 對比度增強能讓字符輪廓更清晰針對模糊保持 imgsz640 不降分辨率同時避免把視頻幀直接拉伸到 640 乘以 640。訓練層面少樣本冷門字符先做復制粘貼增強再看混淆矩陣確認 D/0、B/8、S/5 三組的誤檢是否被壓低。這里的原則是優先補數據和增強而不是盲目換更大的模型。5.3 TensorRT導出與邊緣設備部署如果要將系統部署到閘口工控機或邊緣盒子上TensorRT 是性價比最高的加速手段yolo export modelbest.pt formatengine halfTrue device0導出成功后推理腳本里把權重路徑換成導出的.engine文件即可VideoEvent 和 Detection_video.py 的其余代碼不用改。TensorRT 對網絡結構做層融合和精度校準yolov8n 在常見邊緣 GPU 上單幀延遲能壓到個位數毫秒級但導出與運行必須在相同顯卡驅動版本環境下執行否則 engine 序列化會失敗。導出前先驗證一次 FP32 權重和 engine 在同一段視頻上的識別結果確保字符類別順序和置信度分布一致再進入正式部署。本文還有配套的精品資源點擊獲取