運用訓練好的模型進行目標檢測,模型輸出為中心點對grid的偏移,長寬相對於anchor的縮放比例以及類別
其維度為(b, 13, 13, 3, classes+5)
1. 根據(x, y, h, w)計算出預測框相對於原圖像的位置和大小
def yolo_correct_boxes(box_xy, box_wh, input_shape, image_shape): # (b, 13, 13, 3, 2) box_yx = box_xy[..., ::-1] box_hw = box_wh[..., ::-1] input_shape = K.cast(input_shape, K.dtype(box_yx)) image_shape = K.cast(image_shape, K.dtype(box_yx)) new_shape = K.round(image_shape * K.min(input_shape / image_shape)) # 原圖相對於input_shape的偏移 offset = (input_shape - new_shape) / 2. / input_shape # 原圖相對於input_shape的縮放比例 scale = input_shape / new_shape # 映射回原圖 box_yx = (box_yx - offset) * scale box_hw *= scale box_mins = box_yx - (box_hw / 2.) box_maxes = box_yx + (box_hw / 2.) # (b, 13, 13, 3, 4) boxes = K.concatenate([ box_mins[..., 0:1], # y_min box_mins[..., 1:2], # x_min box_maxes[..., 0:1], # y_max box_maxes[..., 1:2] # x_max ]) # 實際大小 boxes *= K.concatenate([image_shape, image_shape]) return boxes
2. 獲取得分
box_scores = box_confidence * box_class_probs # 預測置信度和預測類別概率的乘積
3.非極大值抑制
# (n, 4)
boxes = K.concatenate(boxes, axis=0)
# (n, classes_num)
box_scores = K.concatenate(box_scores, axis=0)
設定閾值,大於此閾值的判斷為正類(有目標)
mask = box_scores >= score_threshold
對於每一種類別,采用非極大值抑制
for c in range(num_classes): # 取出所有box_scores >= score_threshold的框,和成績 class_boxes = tf.boolean_mask(boxes, mask[:, c]) class_box_scores = tf.boolean_mask(box_scores[:, c], mask[:, c]) # 非極大抑制,去掉box重合程度高的那一些 nms_index = tf.image.non_max_suppression( class_boxes, class_box_scores, max_boxes_tensor, iou_threshold=iou_threshold) # 獲取非極大抑制后的結果 # 下列三個分別是 # 框的位置,得分與種類 class_boxes = K.gather(class_boxes, nms_index) class_box_scores = K.gather(class_box_scores, nms_index) classes = K.ones_like(class_box_scores, 'int32') * c boxes_.append(class_boxes) scores_.append(class_box_scores) classes_.append(classes) boxes_ = K.concatenate(boxes_, axis=0) scores_ = K.concatenate(scores_, axis=0) classes_ = K.concatenate(classes_, axis=0) return boxes_, scores_, classes_
非極大值抑制,顧名思義,即如果不是極大值,就將它抑制掉,選取這個類別最大的score,這個就是極大值,是要顯示的框,即目標存在與這個位置
將其他位置分別與這個框進行iou計算,如果iou大於閾值,則判定這兩個框預測的使同一個目標,則將這個框抑制掉,將此處的score置為0,
一直重復這個過程,知道選擇出全部的目標。
4.在圖像上畫框
out_boxes, out_scores, out_classes = self.yolo_model.predict([image_data, input_image_shape])
for i, c in list(enumerate(out_classes)): predicted_class = self.class_names[c] box = out_boxes[i] score = out_scores[i] top, left, bottom, right = box top = top - 5 left = left - 5 bottom = bottom + 5 right = right + 5 top = max(0, np.floor(top + 0.5).astype('int32')) left = max(0, np.floor(left + 0.5).astype('int32')) bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32')) right = min(image.size[0], np.floor(right + 0.5).astype('int32')) # 畫框框 label = '{} {:.2f}'.format(predicted_class, score) draw = ImageDraw.Draw(image) label_size = draw.textsize(label, font) label = label.encode('utf-8') print(label) if top - label_size[1] >= 0: text_origin = np.array([left, top - label_size[1]]) else: text_origin = np.array([left, top + 1]) for i in range(thickness):
# 目標區域畫框 draw.rectangle( [left + i, top + i, right - i, bottom - i], outline=self.colors[c])
# text區域畫框 draw.rectangle( [tuple(text_origin), tuple(text_origin + label_size)], fill=self.colors[c])
# text區域寫字(lable) draw.text(text_origin, str(label, 'UTF-8'), fill=(0, 0, 0), font=font)