文章目錄
- 前言
- 視頻效果
- 必要環境
- 一、代碼結構
- 1、 訓練參數解析
- 2、 核心代碼解析
- 1.初始化Detector類
- 2. @torch.no_grad()
- 3. 復制輸入圖像并初始化計數器
- 4. 調用YOLOv10模型進行目標檢測
- 5. 提取檢測結果信息
- 6. 遍歷檢測結果并在圖像上繪制邊界框和標簽
- 7. 準備輸入圖像以適應End-to-end模型
- 8. 使用YOLOP模型進行推理
- 9. 處理可行駛區域分割結果
- 10. 處理車道線分割結果
- 二、效果展示
- 三、完整代碼獲取
- 總結
前言
在往期博客中,我們詳細介紹了如何搭建YOLOv10和YOLOP的環境。本期將結合這兩個算法,實現多類別目標檢測、可行駛區域分割和車道線分割等多種任務,并將其部署到PYQT界面中進行展示。
視頻效果
b站鏈接:基于YOLOv10+YOLOP+PYQT的可視化系統,實現多類別目標檢測+可行駛區域分割+車道線分割多種任務
必要環境
- 配置yolov10環境 可參考往期博客
地址:搭建YOLOv10環境 訓練+推理+模型評估
- 配置yolop環境 可參考往期博客
地址:YOLOP 訓練+測試+模型評估
一、代碼結構
1、 訓練參數解析
首先,我們利用 argparse 模塊來設置命令行參數,以便靈活配置模型的權重路徑、使用設備(cpu、gpu)等信息
# 解析命令行參數
parser.add_argument('--v10weights', default=r"yolov10s.pt", type=str, help='weights path')
parser.add_argument('--weights', default=r"weights/End-to-end.pth", type=str, help='weights path')
parser.add_argument('--device', default='0', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
parser.add_argument('--imgsz', type=int, default=640, help='image size')
parser.add_argument('--merge_nms', default=False, action='store_true', help='merge class')
parser.add_argument('--conf_thre', type=float, default=0.3, help='conf_thre')
parser.add_argument('--iou_thre', type=float, default=0.2, help='iou_thre')
parser.add_argument('--augment', action='store_true', help='augmented inference')
opt = parser.parse_args()
關鍵參數詳解:
-
–v10weights: 指定YOLOv10模型的權重文件路徑。
-
–weights: 指定YOLOP模型的權重文件路徑,這個模型包含了車道線分割和可行駛區域分割的任務
-
–device: 指定運行模型的設備,可以是單個GPU(如 0),或者是CPU(cpu)
-
–imgsz: 指定輸入圖像的尺寸,輸入圖像會被調整為這個尺寸,以適應模型的輸入要求
-
–conf_thre: 設置初始置信度閾值,只有置信度高于這個閾值的檢測框才會被保留
-
–iou_thre: 設置初始IOU閾值,在NMS過程中,只有IOU低于這個閾值的檢測框才會被保留
2、 核心代碼解析
此部分包含車道線分割、可行駛區域分割和目標檢測等關鍵部分的代碼
1.初始化Detector類
這段代碼定義了一個名為Detector的類,該類初始化了兩個模型:一個是用于End-to-end檢測的YOLOP模型,另一個是用于目標檢測的YOLOv10模型。通過加載權重文件、設置設備、調整圖像大小以及配置模型參數,實現了對這兩個模型的初始化和準備工作
class Detector:def __init__(self, v10weights, cfg, device, model_path=r'./best_dist_model.pt', imgsz=640, conf=0.5, iou=0.0625, merge_nms=False):self.device = deviceself.model = get_net(cfg)checkpoint = torch.load(model_path, map_location=device)self.model.load_state_dict(checkpoint['state_dict'])self.model = self.model.to(device)img_w = torch.zeros((1, 3, imgsz, imgsz), device=device)_ = self.model(img_w)self.model.eval()self.stride = int(self.model.stride.max())self.imgsz = check_img_size(imgsz, s=self.stride)self.merge_nms = merge_nmsself.model_v10 = YOLOv10(v10weights)self.names = self.model_v10.names
2. @torch.no_grad()
這是一個裝飾器,用于禁用梯度計算,可以減少內存消耗并加快推理速度,通常在推理時使用
@torch.no_grad()
def __call__(self, image: np.ndarray, conf, iou):
3. 復制輸入圖像并初始化計數器
復制輸入圖像以便在結果圖像上進行操作,并初始化一個默認字典來記錄每個類別的檢測次數
img_vis = image.copy()
class_counts = defaultdict(int)
4. 調用YOLOv10模型進行目標檢測
使用YOLOv10模型在輸入圖像上進行目標檢測,返回檢測結果
results = self.model_v10(image, verbose=True, conf=conf, iou=iou, device=self.device)
5. 提取檢測結果信息
提取檢測結果中的類別、置信度和邊界框坐標
bboxes_cls = results[0].boxes.cls
bboxes_conf = results[0].boxes.conf
bboxes_xyxy = results[0].boxes.xyxy.cpu().numpy().astype('uint32')
6. 遍歷檢測結果并在圖像上繪制邊界框和標簽
遍歷所有檢測到的目標,在圖像上繪制邊界框和標簽,并記錄每個類別的檢測次數
for idx in range(len(bboxes_cls)):box_cls = int(bboxes_cls[idx])bbox_xyxy = bboxes_xyxy[idx]bbox_label = self.names[box_cls]class_counts[bbox_label] += 1box_conf = f"{bboxes_conf[idx]:.2f}"xmax, ymax, xmin, ymin = bbox_xyxy[2], bbox_xyxy[3], bbox_xyxy[0], bbox_xyxy[1]img_vis = cv2.rectangle(img_vis, (xmin, ymin), (xmax, ymax), get_color(box_cls + 2), 3)cv2.putText(img_vis, f'{str(bbox_label)}/{str(box_conf)}', (xmin, ymin - 10),cv2.FONT_HERSHEY_SIMPLEX, 1.0, get_color(box_cls + 2), 3)
7. 準備輸入圖像以適應End-to-end模型
對輸入圖像進行調整和預處理,以適應End-to-end模型的輸入要求
img, ratio, pad = letterbox_for_img(image, new_shape=self.imgsz, auto=True)
pad_w, pad_h = pad
pad_w = int(pad_w)
pad_h = int(pad_h)
ratio = ratio[1]
img = np.ascontiguousarray(img)
img = transform(img).to(self.device)
im = img.float()
if im.ndimension() == 3:im = im.unsqueeze(0)
8. 使用YOLOP模型進行推理
在預處理后的圖像上運行End-to-end模型,輸出檢測結果、車道線分割結果和可行駛區域分割結果
det_out, da_seg_out, ll_seg_out = self.model(im)
9. 處理可行駛區域分割結果
這段代碼將對可行駛區域的分割結果進行后處理,首先從模型輸出中裁剪出實際的分割結果,通過雙線性插值恢復到原始圖像尺寸,然后提取每個像素的類別索引,最終生成可行駛區域的分割掩碼
_, _, height, width = im.shape
da_predict = da_seg_out[:, :, pad_h:(height - pad_h), pad_w:(width - pad_w)]
da_seg_mask = torch.nn.functional.interpolate(da_predict, scale_factor=int(1 / ratio), mode='bilinear')
_, da_seg_mask = torch.max(da_seg_mask, 1)
da_seg_mask = da_seg_mask.int().squeeze().cpu().numpy()
10. 處理車道線分割結果
這段代碼將對車道線分割結果進行后處理,和處理可行駛區域分割結果同理,首先從模型輸出中裁剪出實際的分割結果,并通過雙線性插值恢復到原始圖像尺寸,然后提取每個像素的類別索引,生成最終的分割掩碼
ll_predict = ll_seg_out[:, :, pad_h:(height - pad_h), pad_w:(width - pad_w)]
ll_seg_mask = torch.nn.functional.interpolate(ll_predict, scale_factor=int(1 / ratio), mode='bilinear')
_, ll_seg_mask = torch.max(ll_seg_mask, 1)
ll_seg_mask = ll_seg_mask.int().squeeze().cpu().numpy()
二、效果展示
三、完整代碼獲取
鏈接:基于YOLOv10+YOLOP+PYQT的可視化系統,實現多類別目標檢測+可行駛區域分割+車道線分割
總結
本期博客就到這里啦,喜歡的小伙伴們可以點點關注,感謝!
最近經常在b站上更新一些有關目標檢測的視頻,大家感興趣可以來看看 https://b23.tv/1upjbcG
學習交流群:995760755