裁剪
首先,您需要确定图像对于所需比例而言是太宽还是太高。
然后调整相应的尺寸。
我不知道你用的是哪个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