Pytorch机器学习(六)——YOLOV5中的自适应图片缩放letterbox

YOLOV5中的自适应图片缩放letterbox

前言

一、letterbox自适应图片缩放技术

一,计算收缩比

二,计算收缩后图片的长宽

三,计算需要填充的像素

四,最后resize图片并填充像素

二、代码总和

二、使用步骤

1.引入库

2.读入数据

总结


前言

YOLOV5中相比于之前的版本,有很多小trick,导致其性能和应用比较好。本文先讲讲在将图片输入网络前,对图片进行预处理的letterbox的自适应图片缩放技术


一、letterbox自适应图片缩放技术

在目标检测中,输入的图片尺寸有大有小,根据前人的实验结果,输入网络的尺寸统一缩放到同一个尺寸时,检测效果会更好(train中放入的图片并不经过letterbox,而是检测的时候使用letterbox

但这时就有个问题,如果是简单的使用resize,很有可能就造成了图片信息的丢失,所以提出了letterbox自适应图片缩放技术。

设计思想 

letterbox的主要思想是尽可能的利用网络感受野的信息特征。比如在YOLOV5中最后一层的Stride=5,即最后一层的特征图中每个点,可以对应原图中32X32的区域信息,那么只要在保证整体图片变换比例一致的情况下,长宽均可以被32整除,那么就可以有效的利用感受野的信息。

具体来说,图片变换比例一致指的是,长宽的收缩比例应该采用相同的比例。有效利用感受野信息则指对于收缩后不满足条件的一边,用灰白填充至可以被感受野整除。下面举例说明。

下图即是经过letterbox处理的图片,假设图片原来尺寸为(1080, 1920),我们想要resize的尺寸为(640,640)。要想满足收缩的要求,应该选取收缩比例640/1920 = 0.33.则图片被缩放为(360,640).下一步则要填充灰白边至360可以被32整除,则应该填充至384,最终得到图片尺寸(384,640)

Pytorch机器学习(六)——YOLOV5中的自适应图片缩放letterbox_第1张图片Pytorch机器学习(六)——YOLOV5中的自适应图片缩放letterbox_第2张图片

 而其实letterbox的实现也十分简单,以下将结合代码讲解步骤。

一,计算收缩比

shape = im.shape[:2]  # current shape [height, width]
r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])

这里的收缩比取的是长宽方向上变化范围最小的一个。

二,计算收缩后图片的长宽

new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))

三,计算需要填充的像素

这里其实就是在计算那个需要收缩比大的那一边需要填充的像素

# 计算需要填充的边的像素
dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  
# stride表示的即是模型下采样次数的2的次方,这个涉及感受野的问题,在YOLOV5中下采样次数为5
# 则stride为32
dw, dh = np.mod(dw, stride), np.mod(dh, stride)  
dw /= 2  # 除以2即最终每边填充的像素
dh /= 2

四,最后resize图片并填充像素

if shape[::-1] != new_unpad:  # resize
    im = cv.resize(im, new_unpad, interpolation=cv.INTER_LINEAR)
# round(dw,dh - 0.1)直接让小于1的为0
top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
# 添加灰边
im = cv.copyMakeBorder(im, top, bottom, left, right, cv.BORDER_CONSTANT, value=color) 

二、代码总和

def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, stride=32):
    # Resize and pad image while meeting stride-multiple constraints
    shape = im.shape[:2]  # current shape [height, width]
    if isinstance(new_shape, int):
        new_shape = (new_shape, new_shape)
   
    # Scale ratio (new / old)
    r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])

    # Compute padding
    ratio = r, r  # width, height ratios
    new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
    
    dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  # wh padding
    if auto:  # minimum rectangle
        dw, dh = np.mod(dw, stride), np.mod(dh, stride)  # wh padding

    dw /= 2  # divide padding into 2 sides
    dh /= 2
    print(dw, dh)
    if shape[::-1] != new_unpad:  # resize
        im = cv.resize(im, new_unpad, interpolation=cv.INTER_LINEAR)
    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
    im = cv.copyMakeBorder(im, top, bottom, left, right, cv.BORDER_CONSTANT, value=color)  # add border
    return im, ratio, (dw, dh)

你可能感兴趣的:(深度学习,pytorch,python,人工智能,图片处理,数据增强)