yolo_correct_boxes()解析

本文将对keras版本yolo中的yolo_correct_boxes()函数做简单说明

该函数源码、参数说明如下

def yolo_correct_boxes(box_xy, box_wh, input_shape, image_shape):
    """对模型输出的box信息(x, y, w, h)进行校正,输出基于原图坐标系的box信息(x_min, y_min, x_max, y_max)

    Args:
        box_xy: 模型输出的box中心坐标信息,范围0~1
        box_wh: 模型输出的box长宽信息,范围0~1
        input_shape: 模型的图像尺寸, 长宽均是32倍数
        image_shape: 原图尺寸

    Returns:
        boxes: 基于原图坐标系的box信息(实际坐标值,非比值)
    """
    # print("box_xy=", box_xy)
    box_yx = box_xy[..., ::-1]
    # print("box_yx=", box_yx)
    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))
    offset = (input_shape-new_shape)/2./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.)
    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
    ])

    # Scale boxes back to original image shape.
    boxes *= K.concatenate([image_shape, image_shape])
    return boxes

我们先来看看推理过程input_shape的生成过程,首先是推理入口函数

def detect_image(self, image):
        ''' Detect the objections of the input image.
        
        Args:
            image: A opencv-python mat objection.
            
        Returns:
            A PIL Image objection with the drawed rectangles.
        '''
        start = timer()

        if self.model_image_size != (None, None):
            assert self.model_image_size[0]%32 == 0, 'Multiples of 32 required'
            assert self.model_image_size[1]%32 == 0, 'Multiples of 32 required'
            boxed_image = letterbox_image(image, tuple(reversed(self.model_image_size)))
        else:
            new_image_size = (image.width - (image.width % 32),
                              image.height - (image.height % 32))
            boxed_image = letterbox_image(image, new_image_size)
        image_data = np.array(boxed_image, dtype='float32')

        # print(image_data.shape)
        image_data /= 255.
        image_data = np.expand_dims(image_data, 0)  # Add batch dimension.

                        
        out_boxes, out_scores, out_classes = self.sess.run(
            [self.boxes, self.scores, self.classes],
            feed_dict={
                self.yolo_model.input: image_data,
                self.input_image_shape: [image.size[1], image.size[0]],
                K.learning_phase(): 0
            })

最终输入模型的图像数据是image_data, input_shape也就是它的形状,这里有两种选择,一种是指定尺寸,如果不指定就就近选择和长宽值最接近的32的倍数值作为输入尺寸, 确定了输入尺寸之后,如何将原图缩放到这个尺寸呢?这就要看letterbox_image()函数:

def letterbox_image(image, size):
    '''resize image with unchanged aspect ratio using padding'''
    iw, ih = image.size
    w, h = size
    scale = min(w/iw, h/ih)
    nw = int(iw*scale)
    nh = int(ih*scale)

    image = image.resize((nw,nh), Image.BICUBIC)
    new_image = Image.new('RGB', size, (128,128,128))
    new_image.paste(image, ((w-nw)//2, (h-nh)//2))
    return new_image

image就是原图

模型输入图像我们称为input_image, size就是它的shape, 长宽均为32的倍数

原图长宽等比缩放后取整,得到的图像我们称为resize_image

input_image初始化为全图像素值为(128,128,128)的纯色图,然后将resize_image嵌在正中,这样就得到了输入图像

我画了个示意图方便理解

理解了这个过程之后我们再回头看yolo_correct_boxes()的逻辑

模型输出的box_xy和box_wh是相对于input_image的比值,映射回image需要经过如下步骤

step1. 将box_xy相对于input_image左上角的距离修改为相对于resize_image左上角的位置

step2. 将box_xy相对于input_image的比例修改为相对于resize_image的比例

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

step3. 将box_wh相对于input_image的比例修改为相对于resize_image的比例

box_hw *= scale

step4. 将比例值转化为坐标值

boxes *= K.concatenate([image_shape, image_shape])

tips:

没有深入理解之前会以为将原图粗暴的缩放成input_image,这样得到的box_xy直接乘image不就行了,为什么还要做yolo_correct_boxes(),这样做在流程上确实没什么问题,但是图像会形变,相当于特征发生了变化,模型看见的就不再是物体本来的样子了

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值