如何从中心裁剪出3x2比例的图像?

0 投票
2 回答
1544 浏览
提问于 2025-04-16 06:32

有没有简单的方法来做到这一点?

我在Python里写了一个脚本,可以从一张图片中获取一个“正方形框”,是根据中心点来做的。

不过,这让我费了不少脑筋。有没有简单的方法可以根据中心点获取一个3x2的框(宽3,高2)呢?

这是我用来获取“正方形框”的脚本,但我不想为3x2的框去修改它。

def letterbox(f,thumb_w=None,thumb_h=None):
    try:
        im = Image.open(StringIO(f))
        imagex = int(im.size[0])
        imagey = int(im.size[1])
        thumb_size = (thumb_w,thumb_h) #what if it is too small!?? fix it.
        if imagex > imagey:
            setlen = imagey
            left = (imagex - setlen)/2
            top = 0
            height = setlen
            width = setlen
        if imagey > imagex:
            setlen = imagex
            left = 0
            top = (imagey - setlen)/2
            heigth = setlen
            width = setlen
        if imagex == imagey:
            left = 0
            top = 0
            height = imagey
            width = imagex
        box = (left,top,left+width,top+height)
        im = im.crop(box)
        #im.thumbnail(thumb_size,Image.ANTIALIAS)
        new_file = StringIO()
        im.save(new_file,'JPEG')
        new_file.seek(0)
    except Exception, e:
        pass
    return new_file

网上有没有现成的脚本可以满足我的需求?

2 个回答

0

首先,你这个函数的名字有点误导,因为它做的事情并不是信箱式裁剪图片(不管具体的高宽比是什么)——所以这里把它改名为aspectcrop(),这样更能准确描述它的功能。

def aspectcrop(f, ratio=1.0):
    try:
        im = Image.open(StringIO(f))
        imagewidth,imageheight = im.size

        # determine the dimensions of a crop area
        # which is no wider or taller than the image
        if int(imagewidth*ratio) > imageheight:
            cropheight,cropwidth = imageheight,int(imageheight/ratio)
        else:
            cropwidth,cropheight = imagewidth,int(imagewidth*ratio)

        # center the crop area on the image (dx and/or dy will be zero)
        dx,dy = (imagewidth-cropwidth)/2,(imageheight-cropheight)/2

        # crop, save, and return image data
        im = im.crop((dx,dy,cropwidth+dx,cropheight+dy))
        new_file = StringIO()
        im.save(new_file,'JPEG')
        new_file.seek(0)
    except Exception, e:
        new_file = None # prevent exception on return
        pass
    return new_file

如果你传给它的任何高宽比ratio参数不是一个整数,确保它是浮点数,比如用3./2.而不是3/2。默认值(1.0)本来可以是整数,但我特意把它设成浮点数,以此提醒你。其实把它作为两个单独的整数传入,然后在内部计算比率可能会更好。

最后,我注意到你的示例代码中有一些明显的痕迹,看起来像是试图创建图片的缩略图,所以我对相关问题的回答在Python中,最简单的方法是什么来调整图片大小以适应给定的边界区域?也许会对你有帮助(而且可能可以很容易地整合到这个函数中)。

2

使用一个宽高比,它是通过宽度除以高度来定义的,比如3:2的宽高比可以写成3/2,16:9的宽高比可以写成16/9,依此类推。

def letterbox(f,aspect_ratio=1):
    try:
        im = Image.open(StringIO(f))
        imagex = int(im.size[0])
        imagey = int(im.size[1])
        width = min(imagex, imagey*aspect_ratio)
        height = min(imagex/aspect_ratio, imagey)
        left =(imagex - width)/2
        top = (imagey - height)/2
        box = (left,top,left+width,top+height)
        im = im.crop(box)
        new_file = StringIO()
        im.save(new_file,'JPEG')
        new_file.seek(0)
    except Exception, e:
        pass
    return new_file

你可能需要在某个时候检查一下四舍五入的误差,但除此之外,这样做就可以了。

撰写回答