调整图像大小以使大小与指定的纵横比匹配[重复]

Posted

技术标签:

【中文标题】调整图像大小以使大小与指定的纵横比匹配[重复]【英文标题】:Resize an image so that the size matches a specified aspect ratio [duplicate] 【发布时间】:2021-12-23 01:06:25 【问题描述】:

我正在解决需要将图像大小调整为特定纵横比的问题。我想不出任何解决方案。我正在与来自 pixelz 的已处理图像共享示例图像。 例如,输入图像大小为 1833 x 2133,然后将其调整为 1623 x 2164,即 3:4 的比例。输出图像尺寸不固定,可以是任何最接近的尺寸,比例为 3:4。

也许我们可以通过找到最近的具有 3:4 比率的数字对来接近它。

【问题讨论】:

更重要的是,您能否澄清您的问题:您是要裁剪图像(在顶部/底部或左侧/右侧丢弃一点)还是要盲目调整其大小而不进行裁剪(在您的示例图片中,这会使女性看起来比原来更胖或更瘦)? @Stef,我们可以这样做会更好。假设我也在从图像中分割对象或前景。是的,我想我们可以丢弃背景像素,进行裁剪,这将是一个更好的解决方案。 为什么 1623x2164 比 1599/2132 或 1602/2136 等其他 3:4 比例更好?您是否还有其他限制因素促使您做出这一特定选择。 @AlainT。不,不,我只是举例说明 wxh 应该如何改变。任何最接近的 3:4 分辨率都可以。 如果任何3:4都可以,那么:h -= h%4w = h*3//4 【参考方案1】:

裁剪

首先,您需要确定图像对于所需比例而言是太宽还是太高。

然后调整相应的尺寸。

我不知道你用的是哪个python图像处理库,所以我的答案只包含计算新宽度和高度的算术代码,而不是转换图像的实际代码。

def cropped_dims(width, height, ratio):
    if width > height*ratio:
        width = int(height*ratio + 0.5)
    else:
        height = int(width/ratio + 0.5)
    return (width, height)

print(cropped_dims(1833, 2133, 3/4))
# (1600, 2133)

最接近的数对

在您给出的示例中,1833 x 2133 的大小被调整为 1623 x 2164,而不是 1600 x 2133。您提到寻找具有适当比例的“最近数字对”,而不是裁剪到适当的比例。

数字对可以表示为平面中的一个点,使用笛卡尔坐标。

在这种表示下,具有适当比率的数字对恰好是直线上斜率为该比率的点(点 (0,0) 除外,它没有比率)。

图像的原始维度也是一个数对,这个数对用平面上的一个点来表示;先验的,这个点不就行了。

您正在寻找的解决方案是在线上最近的点。这是一个非常经典的几何问题,有一个简单的解决方案。有关如何解决此问题的说明,请参阅以下问题:Point on a line closest to third point。

包含比率点ratio 的线L 包含(ratio * t, t) 形式的点,对于一些实数t

与通过(width, height) 的线L 的垂线D 包含(width+s, height - ratio * s) 形式的点,对于某个实数s

L 线上最接近(width, height) 的点是L 和D 的交点。您可以通过求解未知数(s,t) 方程组(ratio * t, t) == (width+s, height - ratio * s) 找到它的坐标。

解决方案是t = (ratio * width + height) / (1 + ratio**2)

python 代码如下:

def resized_dims(width, height, ratio):
   t = (height + ratio * width) / (ratio**2 + 1)
   new_width = int(t*ratio + 0.5)
   new_height = int(t + 0.5)
   return new_width, new_height

print(resized_dims(1833, 2133, 3/4))
# (1684, 2245)

比较不同的解决方案:

import math

w, h = (1833, 2133)
cropped_w, cropped_h = cropped_dims(1833, 2133, 3/4) # (1600, 2133)
closest_w, closest_h = resized_dims(1833, 2133, 3/4) # (1684, 2245)
your_w, your_h = (1623, 2164)

print('Original ratio:           ', w/h)
print('Wanted ratio:             ', 3/4)
print('Ratio of cropped:         ', cropped_w/cropped_h)
print('Ratio of closest:         ', closest_w/closest_h)
print('Ratio of your solution:   ', your_w/your_h)
print()
print('Distance of cropped:      ', math.dist((w,h), (cropped_w,cropped_h)))
print('Distance of closest:      ', math.dist((w,h), (closest_w,closest_h)))
print('Distance of your solution:', math.dist((w,h), (your_w,your_h)))

# Original ratio:            0.8594
# Wanted ratio:              0.75
# Ratio of cropped:          0.7501
# Ratio of closest:          0.7501
# Ratio of your solution:    0.75
# 
# Distance of cropped:       233.0
# Distance of closest:       186.40
# Distance of your solution: 212.28

【讨论】:

很好的解释和完整的解决方案!【参考方案2】:

在您的具体情况下,您需要找到方程的积分解(正如您所暗示的那样)

1833+x/z = 3/4 这会导致一些谎言 z= (1833 +x) *4/3 可以看到,x=0,z=2444 因此最近的纵横比大小的图像将是 1833/2444

也可以编写一个 Python 例程,该例程会针对给定的图像和纵横比返回图像大小。

def find_nearest (img_x , asp_neu, asp_den):
    delta_x =1
    while True:
       
        y= (img_x*asp_den) % asp_neu
        if y == 0 :
            img_y= (img_x*asp_den)/asp_neu
            return [img_x , img_y]
        if delta_x > 100:  #just for safety
            return [0, 0]
        delta_x +=1
        img_x +=1

print(find_nearest(1833,3,4 ))

【讨论】:

以上是关于调整图像大小以使大小与指定的纵横比匹配[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何使用“包含”选项调整图像的大小,但保留原始尺寸的纵横比?

在 PHP 中将图像裁剪为正方形,而不是调整为相同的纵横比

散景图像绘图与紧轴和匹配的纵横比

预览窗格中照片的纵横比,其中高度恒定且仅宽度变化

如何按比例调整图像大小/保持纵横比?

css 调整大小时保持容器的纵横比