我只需要处理类似的事情:让我们调用 rectangle2image
和 rectangle1 window
。所以我们的任务是将图像放入窗口中。
同样在我的场景中,image
和window
都有一个“内部”坐标系[-1,1]X[-1,1]
。事实上,在窗口内部,有一个viewport
(问题中的 rectangle3)image
将被投影,因此我们的任务是找到与具有相同纵横比(宽度/高度)的最大viewport
(内部矩形) 。window
image
![在此处输入图像描述](https://i.stack.imgur.com/y1KR7.jpg)
由的viewport
宽度/高度的一部分确定image
:
viewport_width = scale_w * window_w
viewport_height = scale_h * window_h
所以我们的目标是找到 的宽度和高度的正确缩放比例window
,这样viewport
将具有与 相同的纵横比(宽度/高度)image
:
# goal:
scale_w * window_w == image_w
scale_h * window_h == image_h
这意味着我们正在寻找的规模满足:
(scale_w / scale_h) == ((image_w / image_h) / (window_w / window_h))
s
让我们暂时用 表示这个等式的右手边。
由于我们正在寻找最大的viewport
,肯定至少有一个scale_w
和scale_h
将等于 1。所以 - 如果s<1
,意味着window
比 宽image
,我们将有scale_w=s, scale_h=1
(这对应于上图,带有scale_w=0.5
)。如果s>1
, 意义image
比 更广泛window
, 我们将拥有scale_w=1, scale_h=1/s
.
在 python 代码中,它看起来像这样:
def compute_viewport_scale(image_size, window_size):
image_w, image_h = image_size
window_w, window_h = window_size
im_ratio, win_ratio = image_w / image_h, window_w / window_h
scale = im_ratio / win_ratio
if scale > 1: # image is wider than screen
scale_w = 1
scale_h = 1 / scale
else: # window is wider then image
scale_w = scale
scale_h = 1
viewport_w, viewport_h = window_w * scale_w, window_h * scale_h
assert (round(viewport_w / viewport_h, 5) == round(image_w / image_h, 5))
return scale_w, scale_h
因为我想绝对确定我已经涵盖了所有案例,所以我构建了一个尺寸示例列表,以确保这个公式确实是正确的。事实上,如果你运行所有这些行,你将不会得到任何断言错误:)
# aspect ratio = 1
compute_viewport_scale((100, 100), (100, 100))
compute_viewport_scale((100, 100), (200, 200))
compute_viewport_scale((200, 200), (100, 100))
# image is wider than screen: (im_w / im_h) > (win_w / win_h) [ i.e. im_ratio > win_ratio ]
# (im_ratio < 1 and win_ratio > 1 cant happen)
# im_w > win_w and im_h > win_h
compute_viewport_scale((300, 200), (100, 90)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((200, 300), (100, 200)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((300, 200), (100, 150)) # im_ratio > 1 and win_ratio < 1
# im_w > win_w and im_h < win_h
compute_viewport_scale((150, 50), (110, 100)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((200, 300), (100, 400)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((300, 100), (100, 150)) # im_ratio > 1 and win_ratio < 1
# (im_w < win_w and im_h > win_h cant happen)
# im_w < win_w and im_h < win_h
compute_viewport_scale((150, 50), (200, 100)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((90, 100), (100, 200)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((110, 100), (100, 200)) # im_ratio > 1 and win_ratio < 1
# image is wider than screen: (im_w / im_h) < (win_w / win_h) [ i.e. im_ratio < win_ratio ]
# (im_ratio > 1 and win_ratio < 1 cant happen)
# im_w > win_w and im_h > win_h
compute_viewport_scale((300, 200), (100, 50)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((200, 400), (100, 150)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((200, 400), (150, 100)) # im_ratio < 1 and win_ratio > 1
# (im_w > win_w and im_h < win_h cant happen)
# im_w < win_w and im_h > win_h
compute_viewport_scale((150, 100), (200, 50)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((200, 400), (380, 390)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((200, 400), (390, 380)) # im_ratio < 1 and win_ratio > 1
# im_w < win_w and im_h < win_h
compute_viewport_scale((300, 200), (600, 300)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((200, 300), (500, 600)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((50, 100), (300, 200)) # im_ratio < 1 and win_ratio > 1