【问题标题】:Cropping rotated image with same aspect ratio裁剪具有相同纵横比的旋转图像
【发布时间】:2014-02-16 06:33:45
【问题描述】:

当输入图像旋转给定度数然后裁剪以避免任何非图像区域同时保持原始图像纵横比时,如何找出最终图像的宽度和高度。

示例:

【问题讨论】:

  • 这是一个很好的问题,我也不介意知道答案,但这是否更适合 Math Stack Exchange?
  • 也许吧。我虽然可能有人知道 Python PIL 中的一个技巧,所以在这里发布。
  • 手指交叉。我在努力……
  • 我实际上只是想出了如何去做。结果很简单。立即编写解决方案。
  • 哦,感谢上帝。当我意识到我的方程式取决于知道我首先要解决的变量时,我正准备弃船!

标签: python image-processing rotation crop


【解决方案1】:

  • 红色矩形是具有原始纵横比的原始图像。
  • W/t 矩形(由绿色和黄色三角形包围)被旋转 图片纵横比为extend=True。

这里是获取w和h的方法。

image = Image.open(...)
rotated = image.rotate(degrees, Image.BICUBIC, True)

aspect_ratio = float(image.size[0]) / image.size[1]
rotated_aspect_ratio = float(rotated.size[0]) / rotated.size[1]
angle = math.fabs(degrees) * math.pi / 180

if aspect_ratio < 1:
    total_height = float(image.size[0]) / rotated_aspect_ratio
else:
    total_height = float(image.size[1])

h = total_height / (aspect_ratio * math.sin(angle) + math.cos(angle))
w = h * aspect_ratio

现在可以在中心裁剪旋转图像,wxh 尺寸为 得到最终图像。

【讨论】:

  • 如果aspect ration = a = w/h 不是w = a / h 不是w = h * a?
  • 你把两边都乘以 h 因此 ha=hw/h 但 h/h 是 1 所以被取消了。
  • 发现代码错误:需要取正弦和余弦的绝对值,否则旋转> 90°会坏
【解决方案2】:

定义:

  • W0 和 H0 是原始矩形的宽度和高度

  • D0是原矩形的对角线(斜边)

  • W1 和 H1 是旋转矩形的填充宽度和高度

  • W2 和 H2 是目标矩形的宽度和高度

  • D2 是目标矩形的对角线(斜边)

  • E是复杂而短暂的

  • 您可能需要预先计算 sin(A)、cos(A) 和 tan(A),因为它们被重复使用

计算W1和H1:

它们由两个部分组成,两个三角形边构成每个长度

  • W1 = W0*cos(A) + H0*sin(A)
  • H1 = H0*cos(A) + W0*sin(A)

计算W2和H2:

  • E = W0 / (1 + tan(A) / W0 * H0)
  • W2 = E / tan(A)
  • H2 = W2 / W0 * H0

作为 Python:

W0 = # original rectangle width
H0 = # original rectangle height
cosA = cos(A)
sinA = sin(A)
tanA = tan(A)
W1 = W0 * cosA + H0 * sinA
H1 = H0 * cosA + W0 * sinA
E = W0 / (1 + tanA / W0 * H0)
W2 = E / tanA       # requested width
H2 = W2 / W0 * H0   # requested height

免责声明:这都是未经测试的


编辑:根据要求,我对 E 含义的最佳猜测:

r0 = w2/h2
h2 = (w0-e1) / sin(A)
h2 = e1/ cos(A) / r0
(w0-e1) / sin(A) = e1/ cos(A) / r0
x = cos(A) / sin(A)
e1 = w0 * x / (1/r0 + x)

E 是 w2 的水平分量,通过 a+b 线延伸。然后是计算 a 与 b 的区别,使用纵横比和 sin/cos 来计算。取消了条款,提高了声音,这就是我最终的结果。

【讨论】:

  • 什么是 E?也许是 wiki 链接。
  • 无链接。这是我自己推导出来的,E 是我需要的维度。我会用图片更新帖子。它与你的惊人的不同!
  • 也许我在这里遗漏了一些琐碎的事情,但我仍然没有关注什么是 e。也许晚上我会再试一次。
  • -1:这不可能是正确的:除以 tan(alpha)。 tan(ε)=ε。根据您的公式,微小的旋转会导致您除以一个很小的数字,从而导致宽度完全错误。
【解决方案3】:

此代码返回此块的坐标

returned box - is the coords of this block

from PIL import Image
def cropp_rotated(image, degrees):
    x, y = image.size
    cosA = abs(math.cos(math.radians(degrees)))
    sinA = abs(math.sin(math.radians(degrees)))

    a = x * cosA 
    b = x * sinA

    relation = a / (a + b)
    right_indent1 = a - x * relation * cosA

    relation = b / (a + b)
    bottom_ident1 = b - x * relation *sinA


    c = y * cosA 
    d = y * sinA

    relation = c / (c + d)
    right_indent2 = c - y * relation * cosA

    relation = d / (c + d)
    bottom_ident2 = d - y * relation *sinA

    right_indent = max(right_indent1, right_indent2)
    top_indent = max(bottom_ident1, bottom_ident2)

    #size of rotated image:
    w_rotated = x * cosA + y * sinA
    h_rotated = y * cosA + x * sinA


    box = (
    int(right_indent), 
    int(top_indent), 
    int(w_rotated - right_indent), 
    int(h_rotated - top_indent))

    return box

我导入 PIL 只是为了获取图像的真实尺寸。 您不能导入 PIL,取而代之的是您可以通过任何其他方式获取图像大小。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    • 2013-08-31
    • 1970-01-01
    相关资源
    最近更新 更多