构建属于自己的理想型的图像Resize函数应对图像裁剪出不定大小

278 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第32天,点击查看活动详情


项目需求

  近期在做项目的适合碰到了一个问题:进行图像分割裁剪时由于目标物不规范,我裁剪出的目标矩形框也不是一样的大小,这给我后面的工作进行造成了一定的麻烦,起初自己想直接暴力采用Resize,但是后面发现图像存在失真现象,主要有如下两种:

  1. 大图变小图:被拉的瘦长了
  2. 小图变大图:被填充成个胖墩墩了

  现在需要解决这个小麻烦,保证存起来的图像都是一般大并且尽量不失真

需求分析

  根据项目需求里面所阐述的那般,我想大家都想到了给图像添加灰条(OR其他颜色),这样可以保证小图可以在进行“变大”的过程中不会被拉伸失真。没错机制如我,我也采用了这种方式;但是如何解决大图转小图时能够不那么失真呢?

  由于暂时没找到一个很好的方式解决大图转小图时候被拉的瘦长这个问题,我选择了一个折中的方案:对切割下来的图像数据Size统计,剔除极少数异常值,分别取众数、平均数和中位数设置为标准的Size,在项目中尽量兼顾各项指标。(不知大家有什么合适的方法,望指点指点小弟我!)

  分析标准Size和待转的Size,我们分别取WidthHeight 代表图像的宽度和高度,对标准的WidthHeight以及待转的分别命名为:

  1. 标Width
  2. 标Height
  3. 原Width
  4. 原Height

对从原始图像中裁剪下来的图像Height&Width共有如下9种情况:

  1. 标Width = 原Width and 标Height = 原Height
  2. 标Width = 原Width and 标Height > 原Height
  3. 标Width = 原Width and 标Height < 原Height
  4. 标Width > 原Width and 标Height = 原Height
  5. 标Width < 原Width and 标Height = 原Height
  6. 标Width > 原Width and 标Height > 原Height
  7. 标Width < 原Width and 标Height < 原Height
  8. 标Width > 原Width and 标Height < 原Height
  9. 标Width < 原Width and 标Height > 原Height

解决思路

  从上面的9种情况分析可以得到有如下几种情况:

  1. 可以将原图贴到标准图上去直接使用,这样的情况有:1、2、4、6
  2. 不需要标准图像,直接将原图像进行缩放到标准图像的Size,这样的情况有:3、5、7
  3. 原图像的Width 或 Height存在小于标准的Width或Height这个时候会存在两种情况:
    3.1 先执行Resize到小的一边然后再执行填充到标准的Size
    3.2 先执行填充小的一边到同大的一边,再执行Resize

实践验证

情况1:这也三种情况中比较理想的情况。
数据准备: 这里的第一张图三标准图(经过缩小到10显示),第二张图像是原图像(未经缩放) RGB.jpg L.jpg

  1. 读取标准图像命名StandardImage
  2. 读取待Resize图像命名ArbitraryImage
  3. 将ArbitraryImage与StandardImage进行叠加(注意二者左上角对齐)
def MyResizeFun(BImgName, LImgName):
    with Image.open(BImgName) as BImg:  # 被粘贴的大图
        with Image.open(LImgName) as LImg:  # 要粘贴的小图
            BImg.paste(LImg, (0, 0))  # 小图 放在大图的坐标为0 0 的位置
            NewImg = BImg.copy()
    return NewImg

save.jpg

情况3: 面对情况三这种一大一小的,我们分别实验两种进行比对看看。 先Resize后填充:

def MyResizeFun2(BImgName, LImgName):
    LImg = Image.open(LImgName)
    L_Width, L_Height = LImg.size

    if L_Width > L_Height:
        RImg = LImg.resize((L_Height, L_Height), Image.ANTIALIAS)
        with Image.open(BImgName) as BImg:  # 被粘贴的大图
            with RImg as RImg:  # 要粘贴的小图
                RImg.paste(LImg, (0, 0))  # 小图 放在大图的坐标为0 0 的位置
                OutImg = BImg.copy()

    if L_Width < L_Height:
        RImg = LImg.resize((L_Width, L_Width), Image.ANTIALIAS)
        with Image.open(BImgName) as BImg:  # 被粘贴的大图
            with RImg as RImg:  # 要粘贴的小图
                RImg.paste(LImg, (0, 0))  # 小图 放在大图的坐标为0 0 的位置
                OutImg = BImg.copy()

    return OutImg

情况2: 这种情况较为简单,直接resize即可完成任务,我就不过多赘述了