1 总体简介
对图像进行预处理操作的时候,一般有两种缩放方式。
-
一种是直接宽、高缩放至想要的宽、高,这种方式快捷,但可能会导致图像变形
-
一种是等比例缩放,然后用灰色边缘填充
step1: 计算宽高缩放比例,选择较小的那个缩放系数;
step2: 计算缩放后的尺寸: 原始图片的长宽都乘以较小的缩放系数;
step3:计算短边需要填充的灰边数,将短边的两边各自填充一半的灰行即可。
2 实现效果
2.1 直接缩放,不怕变形
针对直接缩放的方式,主要代码如下,全部代码实现见最下方
new_image = image.resize((target_w, target_h), Image.BICUBIC)
2.2 不变形缩放/letterbox_image
2.2.1 不变形缩放,两端填充灰边
yolov3使用这个方案
2.2.2 不变形缩放,一端填充灰边
Yolov5使用这个方案,是Yolov5推理速度能够很快的一个trick
很多图片的长宽比不同导致缩放填充后,两端的黑边大小都不同。而如果填充的比较多,则存在信息冗余,影响推理速度。YOLOv5作者对letterbox的缩放策略进行了修改,对原图自适应的添加最少的黑边。
计算方法:
- 计算原始图片宽高与输入尺寸的缩放比例rw和rh,选取r = min(rw,rh)后把原图按r进行缩放
- 原图宽和高中一定有一边完全贴合输入尺寸,没有达到输入尺寸的一边计算与输入尺寸的差值,然后进行上下(or左右)的填充。
3 代码运行
import matplotlib.pyplot as plt
from PIL import Image
# ------------------------------------------------------------------------#
# 对输入图像进行resize,他人测试发现,不用letterbox_image直接resize的效果更好
# ------------------------------------------------------------------------#
def resize_image(image, size, letterbox_image):
iw, ih = image.size
w, h = size # w=200, h=300
if letterbox_image:
scale = min(w/iw, h/ih)
nw = int(iw*scale)
nh = int(ih*scale)
image = image.resize((nw,nh), Image.BICUBIC)
# 新建一张image,第二个参数表示尺寸,第三个参数表示颜色
new_image = Image.new('RGB', size, (128,128,128))
# --------------------------------------------------------------#
# 不变形resize,两端填充灰边
# image.paste函数表示将一张图片覆盖到另一张图片的指定位置去
# a.paste(b, (50,50)) 将b的左上顶点贴到a的坐标为(50,50)的位置,
# 左上顶点为(0,0), b超出a的部分会被自动舍弃
# --------------------------------------------------------------#
# new_image.paste(image, ((w-nw)//2, (h-nh)//2))
# ---------------------------------------------------#
# 不变形resize,一端填充灰边
# ---------------------------------------------------#
new_image.paste(image, (0, 0))
else:
new_image = image.resize((w, h), Image.BICUBIC)
return new_image
img_PIL = Image.open("Avatar.jpg")
# ---------------------------------------------------#
# 第二参数表示目标尺寸,第三参数表示是否使用letterbox
# ---------------------------------------------------#
img = resize_image(img_PIL, (200, 300), True)
plt.imshow(img)
plt.show()