目标检测——SSD预测及后处理

1. 加载model及训练权重

    self.num_classes = len(self.class_names) + 1
    self.model = SSD300((300,300,3), self.num_classes)
    self.model.load_weights('ssd_model.h5', by_name=True, skip_mismatch=True)
    # self.model.summary()
    print('model loaded')

2. 图片预处理

将图片缩放至(300, 300)大小,并进行与训练过程同样的预处理(不包括图像增强)输入网络,得到预测结果

photo = preprocess_input(np.reshape(photo,[1,self.model_image_size[0],self.model_image_size[1],3]))
preds = self.get_pred(photo).numpy()

3. 预测结果后处理

3.1 得到所有预测框的位置

    def decode_boxes(self, mbox_loc, mbox_priorbox, variances):
        # 获得先验框的宽与高
        prior_width = mbox_priorbox[:, 2] - mbox_priorbox[:, 0]
        prior_height = mbox_priorbox[:, 3] - mbox_priorbox[:, 1]
        # 获得先验框的中心点
        prior_center_x = 0.5 * (mbox_priorbox[:, 2] + mbox_priorbox[:, 0])
        prior_center_y = 0.5 * (mbox_priorbox[:, 3] + mbox_priorbox[:, 1])
        
        # 真实框距离先验框中心的xy轴偏移情况
        decode_bbox_center_x = mbox_loc[:, 0] * prior_width * variances[:, 0]
        decode_bbox_center_x += prior_center_x
        decode_bbox_center_y = mbox_loc[:, 1] * prior_height * variances[:, 1]
        decode_bbox_center_y += prior_center_y
        
        # 真实框的宽与高的求取
        decode_bbox_width = np.exp(mbox_loc[:, 2] * variances[:, 2])
        decode_bbox_width *= prior_width
        decode_bbox_height = np.exp(mbox_loc[:, 3] * variances[:, 3])
        decode_bbox_height *= prior_height

        # 获取真实框的左上角与右下角
        decode_bbox_xmin = decode_bbox_center_x - 0.5 * decode_bbox_width
        decode_bbox_ymin = decode_bbox_center_y - 0.5 * decode_bbox_height
        decode_bbox_xmax = decode_bbox_center_x + 0.5 * decode_bbox_width
        decode_bbox_ymax = decode_bbox_center_y + 0.5 * decode_bbox_height

        # 真实框的左上角与右下角进行堆叠
        decode_bbox = np.concatenate((decode_bbox_xmin[:, None],
                                      decode_bbox_ymin[:, None],
                                      decode_bbox_xmax[:, None],
                                      decode_bbox_ymax[:, None]), axis=-1)
        # 防止超出0与1
        decode_bbox = np.minimum(np.maximum(decode_bbox, 0.0), 1.0)
        return decode_bbox

decode_bbox 的维度为(8732, 4)

3.2 针对每一个类别将置信度高于一定阈值 (一般设为0.5) 的作为备选框

for c in range(self.num_classes):
     if c == background_label_id:
           continue
     c_confs = mbox_conf[i, :, c]
     c_confs_m = c_confs > confidence_threshold
     if len(c_confs[c_confs_m]) > 0:
         # 取出得分高于confidence_threshold的框
          boxes_to_process = decode_bbox[c_confs_m]
          confs_to_process = c_confs[c_confs_m]

3.3 采取非极大值抑制过滤重合度较高的框

# 进行iou的非极大抑制
idx = tf.image.non_max_suppression(tf.cast(boxes_to_process,tf.float32), tf.cast(confs_to_process,tf.float32),self._top_k,
iou_threshold=self._nms_thresh).numpy()
# 取出在非极大抑制中效果较好的内容
good_boxes = boxes_to_process[idx]
confs = confs_to_process[idx][:, None]
# 将label、置信度、框的位置进行堆叠。
labels = c * np.ones((len(idx), 1))
c_pred = np.concatenate((labels, confs, good_boxes),
                                            axis=1)
# 添加进result里
results[-1].extend(c_pred)

c_pred 的维度为(n , 6), n为c类别框的个数

3.4 按置信度排序,选取top_k个框

results[-1] = np.array(results[-1])
argsort = np.argsort(results[-1][:, 1])[::-1]
results[-1] = results[-1][argsort]
# 选出置信度最大的keep_top_k个
results[-1] = results[-1][:keep_top_k]

return results

4. 将预测结果(框的位置)映射回原图像大小

def ssd_correct_boxes(top, left, bottom, right, input_shape, image_shape):
    new_shape = image_shape*np.min(input_shape/image_shape)

    offset = (input_shape-new_shape)/2./input_shape
    scale = input_shape/new_shape

    box_yx = np.concatenate(((top+bottom)/2,(left+right)/2),axis=-1)
    box_hw = np.concatenate((bottom-top,right-left),axis=-1)

    box_yx = (box_yx - offset) * scale
    box_hw *= scale

    box_mins = box_yx - (box_hw / 2.)
    box_maxes = box_yx + (box_hw / 2.)
    boxes =  np.concatenate([
        box_mins[:, 0:1],
        box_mins[:, 1:2],
        box_maxes[:, 0:1],
        box_maxes[:, 1:2]
    ],axis=-1)
    print(np.shape(boxes))
    boxes *= np.concatenate([image_shape, image_shape],axis=-1)
    return boxes

5.在原图像上画框

for i, c in enumerate(top_label_indices):
    predicted_class = self.class_names[int(c)-1]
    score = top_conf[i]

    top, left, bottom, right = boxes[i]
    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(np.shape(image)[0], np.floor(bottom + 0.5).astype('int32'))
    right = min(np.shape(image)[1], 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[int(c)-1])
    draw.rectangle(
         [tuple(text_origin), tuple(text_origin + label_size)],
                fill=self.colors[int(c)-1])
    draw.text(text_origin, str(label,'UTF-8'), fill=(0, 0, 0), font=font)
    del draw
return image

 

 

posted @ 2020-12-15 23:47  learningcaiji  阅读(1488)  评论(0编辑  收藏  举报